<commit_before>var fs              = require('fs')
var path            = require('path')
var debug           = require('debug')('app:' + path.basename(__filename).replace('.js', ''))
var async           = require('async')
var op              = require('object-path')
var Promise         = require('promise')
var entu            = require('entulib')
var gm              = require('gm')
var passThrough     = require('stream').PassThrough

var CPU_COUNT = 4

// Generate structure like in ./data flow model.md
function prepareTasks(updateTask, results, callback) {
    function targetFilename(sourceFilename, template) {
        var sourceExtName = path.extname(sourceFilename)
        var sourceFilename = sourceFilename.substr(0, sourceFilename.length - sourceExtName.length)
        var targetFilename = template.fileNamePrefix + sourceFilename + template.fileNameSuffix + sourceExtName
        // debug('targetFilename', updateTask.item.id, targetFilename)
        return targetFilename
    }
    // debug('1:', JSON.stringify(updateTask))
    entu.getEntity(updateTask.item.id, results.entuOptions)
    .then(function(opEntity) {
        var returnTasks = op.get(updateTask.job, ['tasks'], []).map(function(_task) { // For every task
            var returnTask = {
                jobName: _task.name,
                toCreate: [],
                toRemove: []
            }
            if (op.get(_task,['source', 'definitions'], []).indexOf(op.get(updateTask, ['item', 'definition'])) === -1) {
                return returnTask
            }
            // debug('1:', JSON.stringify(updateTask.job))
            _task.targets.forEach(function(_template) { // For every template
                // debug('1.1:', JSON.stringify(_template))
                var existingFiles = opEntity.get(['properties', _template.property], [])
                // debug('1.2:', JSON.stringify(existingFiles))
                    // NOTE forceKeepInSync indicates, if we want to remove files created by others
                    existingFiles = existingFiles.filter(function(a) {
                        if (_template.forceKeepInSync === true) { return true }
                        return Number(results.entuOptions.user) === Number(a.created_by)
                    })

                returnTask.toRemove = returnTask.toRemove.concat(existingFiles)
                // debug('1.3:', JSON.stringify(opEntity.get(['properties', _template.property], []), null, 2))
            })
            // debug('2:', JSON.stringify(returnTask))

            opEntity.get(['properties', _task.source.property], []).forEach(function(_toCreate) { // For every source file
                var toCreate = {
                    value: _toCreate.value,
                    id: _toCreate.id,
                    file: _toCreate.file,
                    targets: []
                }
                _task.targets.forEach(function(_template) { // For every template
                    var target = {
                        fileName: targetFilename(_toCreate.value, _template),
                        property: _template.property,
                        format: _template.format,
                        fixWidth: _template.fixWidth,
                        fixHeight: _template.fixHeight,
                        maxWidth: _template.maxWidth,
                        maxHeight: _template.maxHeight,
                        crop: _template.crop,
                        metaFields: _template.metaFields,
                        subs: _template.subs,
                        exif: _template.exif,
                    }
                    if (target.subs) {
                        if (target.subs.formula) {
                            target.subs.text = target.subs.formula
                            // debug (target.subs.text, target.metaFields)
                            target.metaFields.forEach(function(field) {
                                var search = '@mapping.' + field.mapping + '@'
                                var replace = opEntity.get(['properties', field.definition, 0, 'value'], 'N/A')
                                target.subs.text = target.subs.text.split(search).join(replace)
                            })
                        }
                    }

                    returnTask.toRemove = returnTask.toRemove.filter(function(a){
                        if (a.value === target.fileName) {
                            return false
                        } else {
                            if (toCreate.targets.map(function(a) { return JSON.stringify(a) }).indexOf(JSON.stringify(target)) === -1) {
                                toCreate.targets.push(target)
                            }
                            return true
                        }
                    })
                })
                returnTask.toCreate.push(toCreate)
            })
            // debug('3:', JSON.stringify(returnTask))
            return returnTask
        })
        callback(null, {entityId: updateTask.item.id, tasks: returnTasks})
    })
    .catch(function(reason) {
        if (reason.code === 'ETIMEDOUT' || reason.code === 'ENOTFOUND') {
            debug('reason 1', JSON.stringify(reason))
            setTimeout(function () {
                prepareTasks(updateTask, results, callback)
            }, 10e3)
        } else if (reason.code === 'ECONNRESET') {
            debug('reason 2', JSON.stringify(reason))
            setTimeout(function () {
                prepareTasks(updateTask, results, callback)
            }, 10e3)
        } else {
            debug('reason 3', JSON.stringify(reason))
            setTimeout(function () {
                prepareTasks(updateTask, results, callback)
            }, 10e3)
        }
    })
}

function createMissing(results, callback) {
    if (op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
        return sum + op.get(a, ['toCreate'], []).reduce(function(sum, b) {
            return sum + op.get(b, ['targets'], []).length
        }, 0)
    }, 0) === 0) { return callback(null) }
    debug('\n==== Download sources')

    var outStreams = []
    var sources = results.prepareTasks.tasks.reduce(function(arr, a) { return arr.concat(a.toCreate) }, [])
    async.each(sources, function iterator(source, callback) {
        debug('Process source', JSON.stringify(source))
        var entuSourceStream = entu.requestFile(source.file, results.entuOptions)
            .on('response', function(response) {
                  debug('response', response.statusCode, response.headers['content-type']) // 200, 'image/png'
            })
            .on('error', function(err) {
                console.log('error', JSON.stringify(err))
            })
        var originalFilepath = './temp/ORIGINAL_' + source.id
        var originalWriteStream = fs.createWriteStream(originalFilepath)
        entuSourceStream.pipe(originalWriteStream)
        originalWriteStream.on('finish', function() {
            async.forEachOfSeries(op.get(source, ['targets'], []), function(target, ix, callback) {
                debug('Piping ' + target.property + ' from ' + originalFilepath + ' to ' + target.fileName)

                var sourceStream = fs.createReadStream(originalFilepath)
                var finalStream = fs.createWriteStream('temp/' + source.id + '.' + ix + '.jpg')
                finalStream.on('finish', callback)

                var passToResize = new passThrough()
                sourceStream.pipe(passToResize)
                var passCropped = new passThrough()

                if (!target.subs) {
                    debug('no subs')
                    gm(passCropped)
                    .stream('jpg')
                    .pipe(finalStream)
                }
                else {
                    var appendBgFilename = 'temp/bg_' + source.id + '.' + ix + '.jpg'
                    finalStream.on('finish', function(){
                        fs.unlink(appendBgFilename)
                    })
                    debug('subbing with ' + target.subs.text)
                    var passToAddSubs = new passThrough()
                    passCropped.pipe(passToAddSubs)

                    // var pixelSource = fs.createReadStream('./pixel.png')
                    var passBackground = new passThrough()
                    var finalBgStream = fs.createWriteStream(appendBgFilename)

                    var width = target.maxWidth ? target.maxWidth : target.fixWidth
                    target.subs.text = target.subs.text || 'abrakadabra mims leidfg asdgiooh asgoasdgl adfgladskg ais gaodshgoa sdiohia sdgas.'
                    gm(width, target.subs.height, '#' + target.subs.backgroundColor)
                    .fontSize(12)
                    .fill("#000000")
                    // .fill('#' + ('000000' + parseInt(Math.random()*256*256*256, 10).toString(16)).slice(-6))
                    .drawText(0, 0, target.subs.text, 'center')
                    .quality(100)
                    .stream('jpg')
                    .pipe(finalBgStream)

                    finalBgStream.on('finish', function() {
                        gm(passToAddSubs)
                        .append(appendBgFilename)
                        .stream('jpg')
                        .pipe(finalStream)
                    })
                }
                debug('Resizing ', JSON.stringify(target))
                if (target.fixWidth && target.fixHeight) {
                    debug('Resizing fix-fix')
                    gm(passToResize)
                    .resize(target.fixWidth, target.fixHeight, '^')
                    .gravity('Center')
                    // .crop(target.fixWidth, target.fixHeight)
                    .stream('jpg')
                    .pipe(passCropped)
                }
                else if (target.maxWidth && target.fixHeight) {
                    debug('Resizing max-fix')
                    gm(passToResize)
                    .resize(null, target.fixHeight)
                    .gravity('Center')
                    .crop(target.maxWidth, target.fixHeight)
                    .extent(target.maxWidth, target.fixHeight)
                    .stream('jpg')
                    .pipe(passCropped)
                }
                else if (target.fixWidth && target.maxHeight) {
                    debug('Resizing fix-max')
                    gm(passToResize)
                    .resize(target.fixWidth, null)
                    .gravity('Center')
                    .crop(target.fixWidth, target.maxHeight)
                    .extent(target.fixWidth, target.maxHeight)
                    .stream('jpg')
                    .pipe(passCropped)
                }
                else if (target.maxWidth && target.maxHeight) {
                    debug('Resizing max-max')
                    gm(passToResize)
                    .resize(target.maxWidth, target.maxHeight)
                    .extent(target.maxWidth, target.maxHeight)
                    .gravity('Center')
                    .stream('jpg')
                    .pipe(passCropped)
                }

            },
            function(err) {
                fs.unlink(originalFilepath)
                if (err) { return callback(err) }
                callback()
            })

        })
    },
    function(err) {
        if (err) {
            debug('Pildimaag stopped with error.', err)
            throw err
        }
        debug('file fetch success')
        callback(null)
    })
}

function removeExtra(results, callback) {
    if (op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
        return sum + op.get(a, ['toRemove', 'targets'], []).length
    }, 0) === 0) { return callback(null) }

    return callback(null)
    debug('          ---------------------- FOOOOOÖö 1          ---------------------- ')
    entu.getEntity(results.prepareTasks.entityId, results.entuOptions)
    .then(function(request) {
        debug('          ---------------------- FOOOOOÖö 2          ---------------------- ')
        request.on('response', function(response) {
              debug('response', response.statusCode) // 200
              debug('response', response.headers['content-type']) // 'image/png'
        })
        .on('error', function(err) {
            console.log('error', JSON.stringify(err))
        })
        .pipe(fs.createWriteStream('./doodle.jpg'))
    })
    .catch(function(reason) {
        debug('reason', JSON.stringify(reason))
    })
}

var updateQueue = async.queue( function (updateTask, callback) {
    // debug('Adding new task to job "' + updateTask.job.name + '" queue: ' + JSON.stringify(updateTask.item))
    async.auto({
        entuOptions: function(callback) {
            callback(null, updateTask.entuOptions)
        },
        prepareTasks: ['entuOptions', function(callback, results) {
            prepareTasks(updateTask, results, callback)
        }],
        createMissing: ['prepareTasks', function(callback, results) {
            // debug('results', JSON.stringify(results, null, 4))
            createMissing(results, callback)
        }],
        // removeExtra: ['prepareTasks', function(callback, results) {
        //     // debug('results', JSON.stringify(results, null, 4))
        //     removeExtra(results, callback)
        // }],
    }, function(err, results) {
        if (err) {
            return debug('Failed to add new task to job "' + updateTask.job.name + '" task item: ' + JSON.stringify(updateTask.item), JSON.stringify(err))
        }
        var toCreate = op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
            return sum + op.get(a, ['toCreate'], []).reduce(function(sum, b) {
                return sum + op.get(b, ['targets'], []).length
            }, 0)
        }, 0)
        var toRemove = op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
            return sum + op.get(a, ['toRemove', 'targets'], []).length
        }, 0)
        if (toCreate + toRemove) {
            debug('Job "' + updateTask.job.name + '", task item: ' + JSON.stringify(updateTask.item) + ' at ', new Date(updateTask.item.timestamp * 1e3))
            debug('|__ :', JSON.stringify({toCreate:toCreate, toRemove:toRemove}))
        }
        callback()
    })
}, CPU_COUNT)
updateQueue.drain = function() {
    debug('=== UPDATEQUEUE: ALL ITEMS HAVE BEEN PROCESSED ===')
}

var uploadQueue = async.queue( function (task, callback) {
    callback()
})
uploadQueue.drain = function() {
    debug('uploadQueue: all items have been processed')
}

module.exports = updateQueue
<commit_msg>crop to fix dimensions<commit_after>var fs              = require('fs')
var path            = require('path')
var debug           = require('debug')('app:' + path.basename(__filename).replace('.js', ''))
var async           = require('async')
var op              = require('object-path')
var Promise         = require('promise')
var entu            = require('entulib')
var gm              = require('gm')
var passThrough     = require('stream').PassThrough

var CPU_COUNT = 4

// Generate structure like in ./data flow model.md
function prepareTasks(updateTask, results, callback) {
    function targetFilename(sourceFilename, template) {
        var sourceExtName = path.extname(sourceFilename)
        var sourceFilename = sourceFilename.substr(0, sourceFilename.length - sourceExtName.length)
        var targetFilename = template.fileNamePrefix + sourceFilename + template.fileNameSuffix + sourceExtName
        // debug('targetFilename', updateTask.item.id, targetFilename)
        return targetFilename
    }
    // debug('1:', JSON.stringify(updateTask))
    entu.getEntity(updateTask.item.id, results.entuOptions)
    .then(function(opEntity) {
        var returnTasks = op.get(updateTask.job, ['tasks'], []).map(function(_task) { // For every task
            var returnTask = {
                jobName: _task.name,
                toCreate: [],
                toRemove: []
            }
            if (op.get(_task,['source', 'definitions'], []).indexOf(op.get(updateTask, ['item', 'definition'])) === -1) {
                return returnTask
            }
            // debug('1:', JSON.stringify(updateTask.job))
            _task.targets.forEach(function(_template) { // For every template
                // debug('1.1:', JSON.stringify(_template))
                var existingFiles = opEntity.get(['properties', _template.property], [])
                // debug('1.2:', JSON.stringify(existingFiles))
                    // NOTE forceKeepInSync indicates, if we want to remove files created by others
                    existingFiles = existingFiles.filter(function(a) {
                        if (_template.forceKeepInSync === true) { return true }
                        return Number(results.entuOptions.user) === Number(a.created_by)
                    })

                returnTask.toRemove = returnTask.toRemove.concat(existingFiles)
                // debug('1.3:', JSON.stringify(opEntity.get(['properties', _template.property], []), null, 2))
            })
            // debug('2:', JSON.stringify(returnTask))

            opEntity.get(['properties', _task.source.property], []).forEach(function(_toCreate) { // For every source file
                var toCreate = {
                    value: _toCreate.value,
                    id: _toCreate.id,
                    file: _toCreate.file,
                    targets: []
                }
                _task.targets.forEach(function(_template) { // For every template
                    var target = {
                        fileName: targetFilename(_toCreate.value, _template),
                        property: _template.property,
                        format: _template.format,
                        fixWidth: _template.fixWidth,
                        fixHeight: _template.fixHeight,
                        maxWidth: _template.maxWidth,
                        maxHeight: _template.maxHeight,
                        crop: _template.crop,
                        metaFields: _template.metaFields,
                        subs: _template.subs,
                        exif: _template.exif,
                    }
                    if (target.subs) {
                        if (target.subs.formula) {
                            target.subs.text = target.subs.formula
                            // debug (target.subs.text, target.metaFields)
                            target.metaFields.forEach(function(field) {
                                var search = '@mapping.' + field.mapping + '@'
                                var replace = opEntity.get(['properties', field.definition, 0, 'value'], 'N/A')
                                target.subs.text = target.subs.text.split(search).join(replace)
                            })
                        }
                    }

                    returnTask.toRemove = returnTask.toRemove.filter(function(a){
                        if (a.value === target.fileName) {
                            return false
                        } else {
                            if (toCreate.targets.map(function(a) { return JSON.stringify(a) }).indexOf(JSON.stringify(target)) === -1) {
                                toCreate.targets.push(target)
                            }
                            return true
                        }
                    })
                })
                returnTask.toCreate.push(toCreate)
            })
            // debug('3:', JSON.stringify(returnTask))
            return returnTask
        })
        callback(null, {entityId: updateTask.item.id, tasks: returnTasks})
    })
    .catch(function(reason) {
        if (reason.code === 'ETIMEDOUT' || reason.code === 'ENOTFOUND') {
            debug('reason 1', JSON.stringify(reason))
            setTimeout(function () {
                prepareTasks(updateTask, results, callback)
            }, 10e3)
        } else if (reason.code === 'ECONNRESET') {
            debug('reason 2', JSON.stringify(reason))
            setTimeout(function () {
                prepareTasks(updateTask, results, callback)
            }, 10e3)
        } else {
            debug('reason 3', JSON.stringify(reason))
            setTimeout(function () {
                prepareTasks(updateTask, results, callback)
            }, 10e3)
        }
    })
}

function createMissing(results, callback) {
    if (op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
        return sum + op.get(a, ['toCreate'], []).reduce(function(sum, b) {
            return sum + op.get(b, ['targets'], []).length
        }, 0)
    }, 0) === 0) { return callback(null) }
    debug('\n==== Download sources')

    var outStreams = []
    var sources = results.prepareTasks.tasks.reduce(function(arr, a) { return arr.concat(a.toCreate) }, [])
    async.each(sources, function iterator(source, callback) {
        debug('Process source', JSON.stringify(source))
        var entuSourceStream = entu.requestFile(source.file, results.entuOptions)
            .on('response', function(response) {
                  debug('response', response.statusCode, response.headers['content-type']) // 200, 'image/png'
            })
            .on('error', function(err) {
                console.log('error', JSON.stringify(err))
            })
        var originalFilepath = './temp/ORIGINAL_' + source.id
        var originalWriteStream = fs.createWriteStream(originalFilepath)
        entuSourceStream.pipe(originalWriteStream)
        originalWriteStream.on('finish', function() {
            async.forEachOfSeries(op.get(source, ['targets'], []), function(target, ix, callback) {
                debug('Piping ' + target.property + ' from ' + originalFilepath + ' to ' + target.fileName)

                var sourceStream = fs.createReadStream(originalFilepath)
                var finalStream = fs.createWriteStream('temp/' + source.id + '.' + ix + '.jpg')
                finalStream.on('finish', callback)

                var passToResize = new passThrough()
                sourceStream.pipe(passToResize)
                var passCropped = new passThrough()

                if (!target.subs) {
                    debug('no subs')
                    gm(passCropped)
                    .stream('jpg')
                    .pipe(finalStream)
                }
                else {
                    var appendBgFilename = 'temp/bg_' + source.id + '.' + ix + '.jpg'
                    finalStream.on('finish', function(){
                        fs.unlink(appendBgFilename)
                    })
                    debug('subbing with ' + target.subs.text)
                    var passToAddSubs = new passThrough()
                    passCropped.pipe(passToAddSubs)

                    // var pixelSource = fs.createReadStream('./pixel.png')
                    var passBackground = new passThrough()
                    var finalBgStream = fs.createWriteStream(appendBgFilename)

                    var width = target.maxWidth ? target.maxWidth : target.fixWidth
                    target.subs.text = target.subs.text || 'abrakadabra mims leidfg asdgiooh asgoasdgl adfgladskg ais gaodshgoa sdiohia sdgas.'
                    gm(width, target.subs.height, '#' + target.subs.backgroundColor)
                    .fontSize(12)
                    .fill("#000000")
                    // .fill('#' + ('000000' + parseInt(Math.random()*256*256*256, 10).toString(16)).slice(-6))
                    .drawText(0, 0, target.subs.text, 'center')
                    .quality(100)
                    .stream('jpg')
                    .pipe(finalBgStream)

                    finalBgStream.on('finish', function() {
                        gm(passToAddSubs)
                        .append(appendBgFilename)
                        .stream('jpg')
                        .pipe(finalStream)
                    })
                }
                debug('Resizing ', JSON.stringify(target))
                if (target.fixWidth && target.fixHeight) {
                    debug('Resizing fix-fix')
                    gm(passToResize)
                    .resize(target.fixWidth, target.fixHeight, '^')
                    .gravity('Center')
                    .crop(target.fixWidth, target.fixHeight)
                    .stream('jpg')
                    .pipe(passCropped)
                }
                else if (target.maxWidth && target.fixHeight) {
                    debug('Resizing max-fix')
                    gm(passToResize)
                    .resize(null, target.fixHeight)
                    .gravity('Center')
                    .crop(target.maxWidth, target.fixHeight)
                    .extent(target.maxWidth, target.fixHeight)
                    .stream('jpg')
                    .pipe(passCropped)
                }
                else if (target.fixWidth && target.maxHeight) {
                    debug('Resizing fix-max')
                    gm(passToResize)
                    .resize(target.fixWidth, null)
                    .gravity('Center')
                    .crop(target.fixWidth, target.maxHeight)
                    .extent(target.fixWidth, target.maxHeight)
                    .stream('jpg')
                    .pipe(passCropped)
                }
                else if (target.maxWidth && target.maxHeight) {
                    debug('Resizing max-max')
                    gm(passToResize)
                    .resize(target.maxWidth, target.maxHeight)
                    .extent(target.maxWidth, target.maxHeight)
                    .gravity('Center')
                    .stream('jpg')
                    .pipe(passCropped)
                }

            },
            function(err) {
                fs.unlink(originalFilepath)
                if (err) { return callback(err) }
                callback()
            })

        })
    },
    function(err) {
        if (err) {
            debug('Pildimaag stopped with error.', err)
            throw err
        }
        debug('file fetch success')
        callback(null)
    })
}

function removeExtra(results, callback) {
    if (op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
        return sum + op.get(a, ['toRemove', 'targets'], []).length
    }, 0) === 0) { return callback(null) }

    return callback(null)
    debug('          ---------------------- FOOOOOÖö 1          ---------------------- ')
    entu.getEntity(results.prepareTasks.entityId, results.entuOptions)
    .then(function(request) {
        debug('          ---------------------- FOOOOOÖö 2          ---------------------- ')
        request.on('response', function(response) {
              debug('response', response.statusCode) // 200
              debug('response', response.headers['content-type']) // 'image/png'
        })
        .on('error', function(err) {
            console.log('error', JSON.stringify(err))
        })
        .pipe(fs.createWriteStream('./doodle.jpg'))
    })
    .catch(function(reason) {
        debug('reason', JSON.stringify(reason))
    })
}

var updateQueue = async.queue( function (updateTask, callback) {
    // debug('Adding new task to job "' + updateTask.job.name + '" queue: ' + JSON.stringify(updateTask.item))
    async.auto({
        entuOptions: function(callback) {
            callback(null, updateTask.entuOptions)
        },
        prepareTasks: ['entuOptions', function(callback, results) {
            prepareTasks(updateTask, results, callback)
        }],
        createMissing: ['prepareTasks', function(callback, results) {
            // debug('results', JSON.stringify(results, null, 4))
            createMissing(results, callback)
        }],
        // removeExtra: ['prepareTasks', function(callback, results) {
        //     // debug('results', JSON.stringify(results, null, 4))
        //     removeExtra(results, callback)
        // }],
    }, function(err, results) {
        if (err) {
            return debug('Failed to add new task to job "' + updateTask.job.name + '" task item: ' + JSON.stringify(updateTask.item), JSON.stringify(err))
        }
        var toCreate = op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
            return sum + op.get(a, ['toCreate'], []).reduce(function(sum, b) {
                return sum + op.get(b, ['targets'], []).length
            }, 0)
        }, 0)
        var toRemove = op.get(results, ['prepareTasks', 'tasks'], []).reduce(function(sum, a) {
            return sum + op.get(a, ['toRemove', 'targets'], []).length
        }, 0)
        if (toCreate + toRemove) {
            debug('Job "' + updateTask.job.name + '", task item: ' + JSON.stringify(updateTask.item) + ' at ', new Date(updateTask.item.timestamp * 1e3))
            debug('|__ :', JSON.stringify({toCreate:toCreate, toRemove:toRemove}))
        }
        callback()
    })
}, CPU_COUNT)
updateQueue.drain = function() {
    debug('=== UPDATEQUEUE: ALL ITEMS HAVE BEEN PROCESSED ===')
}

var uploadQueue = async.queue( function (task, callback) {
    callback()
})
uploadQueue.drain = function() {
    debug('uploadQueue: all items have been processed')
}

module.exports = updateQueue
<|endoftext|>


<commit_before>var events = require('events');
var fs = require('fs');
var util = require("util");
var crypto = require('crypto');
var Buffers = require('buffers');
var _ = require('underscore');
var logger = require('tracer').console();
var bw = require("buffered-writer");
var common = require('./common.js');
var socket = require('./socket.js');
var BufferedFile = require("./bufferedfile.js");
var Router = require("./router.js");

function Room(options) {
    events.EventEmitter.call(this);

    var defaultOptions = new function () {
        var self = this;
        self.name = '';
        self.canvasSize = {
            width: 720,
            height: 480
        };
        self.password = ''; // for private room
        self.maxLoad = 5;
        self.welcomemsg = '';
        self.emptyclose = false;
        self.permanent = false;
        self.expiration = 0; // 0 for limitless
        self.salt = '';
        self.log = false;
    };

    if (_.isUndefined(options)) {
        var options = {};
    }
    var op = _.defaults(options, defaultOptions);
    if(!_.isString(op.name) || op.name.length < 1) {
        common.log('valid name');
        // TODO: throw exception
        return;
    }
    op.logLocation = function() {
        var hash = crypto.createHash('sha1');
        hash.update(op.name, 'utf8');
        hash = hash.digest('hex');
        return './logs/rooms/'+hash+'.log';
    }();

    var room = this;
    room.workingSockets = 0;
    room.options = op;
    room.router = new Router();

    // NOTE: here we use sync read function
    // to ensure we have that key when running.
    if(room.options.salt.length < 1){
        room.options.salt = fs.readFileSync('./config/salt.key');
    }

    var hash_source = room.options.name + room.options.salt;
    var hashed = crypto.createHash('sha1');
    hashed.update(hash_source, 'utf8');
    room.signed_key = hashed.digest('hex');

    function prepareCheckoutTimer(r_room) {
        if(r_room.options.expiration) {
            r_room.checkoutTimer = setTimeout(function onTimeout() {
                r_room.options.emptyclose = true;
            }, r_room.options.expiration * 3600*1000);
        }
    };
    prepareCheckoutTimer(room);

    room.dataFile = function() {
        fs.exists('./data/room/', function (exists) {
          if(!exists){
            fs.mkdirSync('./data/room/');
          }
        });

        var hash = crypto.createHash('sha1');
        hash.update(room.options.name, 'utf8');
        hash = hash.digest('hex');
        return './data/room/'+hash+'.data';
    }();
    room.dataFileSize = 0;
    var bf = new BufferedFile({
                fileName: room.dataFile,
                bufferSize: 1024*1024*2,
                writeCycle: 0
            });

    room.msgFile = function() {
        fs.exists('./data/room/', function (exists) {
          if(!exists){
            fs.mkdirSync('./data/room/');
          }
        });

        var hash = crypto.createHash('sha1');
        hash.update(op.name, 'utf8');
        hash = hash.digest('hex');
        return './data/room/'+hash+'.msg';
    }();
    // room.msgFileSize = 0;
    var tf = new BufferedFile({
                fileName: room.msgFile,
                bufferSize: 1024*1024,
                writeCycle: 0
            });

    room.dataSocket = new socket.SocketServer();
    room.dataSocket.maxConnections = room.options.maxLoad;
    room.dataSocket.on('datapack', function(cli, dbuf) {
        bf.append(dbuf);
        room.dataFileSize += dbuf.length;
    }).on('connection', function(con){
        bf.readAll(function(da) {
            con.write(da);
        });
    });

    room.msgSocket = new socket.SocketServer();
    room.msgSocket.maxConnections = room.options.maxLoad;
    room.msgSocket.on('connection', function(con){
        con.on('end', function() {
            if(room.options.emptyclose){
                if(room.currentLoad() <= 1){
                    room.close();
                }
            }
        });

        room.msgSocket.sendData(con, JSON.stringify({
            content: '欢迎使用茶绘君，我们的主页：http://mrspaint.com。\n'+
                    '如果您在使用中有任何疑问，'+
                    '请在茶绘君贴吧留言：'+
                    'http://tieba.baidu.com/f?kw=%B2%E8%BB%E6%BE%FD \n'
        }));
        // TODO: use cmd channal
        // var send_msg = '
欢迎使用'+
        //             '茶绘君。
'+
        //             '如果您在使用中有任何疑问，'+
        //             '请在茶绘君贴吧留言。
\n';
        // BUG: use con will send msg into msgSocket, not cmdSocket
        // room.notify(con, send_msg);
        if(room.options.welcomemsg.length) {
            room.msgSocket.sendData(con, JSON.stringify({
                content: room.options.welcomemsg+'\n'
            }));
        }
        tf.readAll(function(da) {
            con.write(da);
        });
    }).on('datapack', function(cli, dbuf) {
        tf.append(dbuf);
    });

    room.router.reg('request', 'login', function(cli, obj) {
        var r_room = this;
        // name check
        if(!obj['name'] || !_.isString(obj['name'])){
            var ret = {
                response: 'login',
                result: false,
                errcode: 301
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
            return;
        }
        // password check
        if(r_room.options.password.length > 0){
            if(!obj['password'] || !_.isString(obj['password'])
            || obj['password'] != r_room.options.password){
                var ret = {
                    response: 'login',
                    result: false,
                    errcode: 302
                };
                logger.log(ret);
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
                return;
            }
        }
        // send info
        var ret = {
            response: 'login',
            result: true,
            info: {
                historysize: r_room.dataFileSize,
                dataport: r_room.ports().dataPort,
                msgport: r_room.ports().msgPort,
                size: r_room.options.canvasSize,
                clientid: function(){
                    var hash = crypto.createHash('sha1');
                    hash.update(r_room.options.name
                                + obj['name']
                                + r_room.options.salt
                                + (new Date()).getTime()
                                ,'utf8');
                    hash = hash.digest('hex');
                    cli['clientid'] = hash;
                    return hash;
                }()
            }
        };
        logger.log(ret);
        var jsString = JSON.stringify(ret);
        r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        cli['username'] = obj['name'];
        return;
    }, room).reg('request', 'close', function(cli, obj) {
        var r_room = this;
        // check signed key
        if(!obj['key'] || !_.isString(obj['key'])){
            var ret = {
                response: 'close',
                result: false
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }else{
            if(obj['key'].toLowerCase() == r_room.signed_key.toLowerCase()){
                var ret = {
                    response: 'close',
                    result: true
                };
                logger.log(ret);
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
                var ret_all = {
                    action: 'close',
                    'info': {
                        reason: 501
                    }
                };
                jsString = JSON.stringify(ret_all);
                logger.log(jsString);
                r_room.cmdSocket.broadcastData(new Buffer(jsString));
                r_room.options.emptyclose = true;
            }
        }
    }, room).reg('request', 'clearall', function(cli, obj) {
        var r_room = this;
        if(!obj['key'] || !_.isString(obj['key'])){
            var ret = {
                response: 'clearall',
                result: false
            };
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }else{
            if(obj['key'].toLowerCase() == r_room.signed_key.toLowerCase()){
                var ret = {
                    response: 'clearall',
                    result: true
                };
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
                var ret_all = {
                    action: 'clearall',
                };
                jsString = JSON.stringify(ret_all);
                r_room.cmdSocket.broadcastData(new Buffer(jsString));
                bf.clearAll();
            }else{
                var ret = {
                    response: 'clearall',
                    result: false
                };
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
            }
        }
    }, room).reg('request', 'onlinelist', function(cli, obj) {
        var r_room = this;
        if(!obj['clientid']){
            return;
        }
        logger.log('onlinelist request by '+obj['clientid']);
        if( !_.findWhere(r_room.cmdSocket.clients,
            {'clientid': obj['clientid']}) ){
            return;
        }

        var people = [];
        _.each(r_room.cmdSocket.clients, function(va) {
            if(va['username'] && va['clientid']){
                people.push({
                    'name': va['username'],
                    'clientid': va['clientid']
                });
            }
        });
        if(!people.length){
            return;
        }

        var ret = {
            response: 'onlinelist',
            result: true,
            onlinelist: people
        };
        logger.log(ret);
        var jsString = JSON.stringify(ret);
        r_room.cmdSocket.sendData(cli, new Buffer(jsString));
    }, room).reg('request', 'checkout', function(cli, obj) {
        var r_room = this;
        if(!obj['key'] || !_.isString(obj['key'])){
            var ret = {
                response: 'checkout',
                result: false,
                errcode: 701
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }
        if(obj['key'].toLowerCase() == r_room.signed_key.toLowerCase()){
            if(r_room.checkoutTimer){
                clearTimeout(r_room.checkoutTimer);
                prepareCheckoutTimer(r_room);
            }
            var ret = {
                response: 'checkout',
                result: true,
                cycle: r_room.options.expiration?r_room.options.expiration:0
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }
    }, room);

    room.cmdSocket = new socket.SocketServer({
        autoBroadcast: false,
        useAlternativeParser: function(cli, buf) {
                var obj = JSON.parse(buf);
                room.router.message(cli, obj);
        }
    });
    room.cmdSocket.maxConnections = room.options.maxLoad;

    var tmpF = function() {
        room.workingSockets += 1;
        if(room.workingSockets >= 3) {
            room.emit('create', {
                cmdPort: room.cmdSocket.address().port,
                maxLoad: room.options.maxLoad,
                currentLoad: room.currentLoad(),
                name: room.options.name,
                key: room.signed_key
            });
        }
    };

    room.dataSocket.on('listening', tmpF);
    room.cmdSocket.on('listening', tmpF);
    room.msgSocket.on('listening', tmpF);
}

util.inherits(Room, events.EventEmitter);

Room.prototype.start = function() {
    if(!this.options.permanent) {
        fs.unlink(this.dataFile, function(){});
        fs.unlink(this.msgFile, function(){});
    }
    this.cmdSocket.listen(0, '::'); // this will support both ipv6 and ipv4 address
    this.dataSocket.listen(0, '::');
    this.msgSocket.listen(0, '::');
    return this;
};

Room.prototype.ports = function() {
    return {
        cmdPort: this.cmdSocket.address().port,
        dataPort: this.dataSocket.address().port,
        msgPort: this.msgSocket.address().port
    };
};

Room.prototype.close = function() {
    logger.log('Room.close()');
    this.emit('close');
    this.cmdSocket.close();
    this.dataSocket.close();
    this.msgSocket.close();
    if(!this.options.permanent) {
        fs.unlink(this.dataFile, function(){});
        fs.unlink(this.msgFile, function(){});
    }
    return this;
};

Room.prototype.currentLoad = function() {
    // do not count cmdSocket because it's a public socket
    return Math.max(this.dataSocket.clients.length,
        this.msgSocket.clients.length);
};

Room.prototype.notify = function(con, content) {
    var self = this;
    var sendContent = {
        action: 'notify',
        'content': content
    };
    self.cmdSocket.sendData(con, JSON.stringify(sendContent));
    logger.log('cmdSocket: ');
    logger.log(self.cmdSocket);
    logger.log(sendContent);
};

Room.prototype.bradcastMessage = function(content) {
    var self = this;
    var sendContent = {
        action: 'notify',
        'content': content
    };
    self.cmdSocket.broadcastData(JSON.stringify(sendContent));
};

module.exports = Room;<commit_msg>bugfix: reset history data size counter when cleanall.<commit_after>var events = require('events');
var fs = require('fs');
var util = require("util");
var crypto = require('crypto');
var Buffers = require('buffers');
var _ = require('underscore');
var logger = require('tracer').console();
var bw = require("buffered-writer");
var common = require('./common.js');
var socket = require('./socket.js');
var BufferedFile = require("./bufferedfile.js");
var Router = require("./router.js");

function Room(options) {
    events.EventEmitter.call(this);

    var defaultOptions = new function () {
        var self = this;
        self.name = '';
        self.canvasSize = {
            width: 720,
            height: 480
        };
        self.password = ''; // for private room
        self.maxLoad = 5;
        self.welcomemsg = '';
        self.emptyclose = false;
        self.permanent = false;
        self.expiration = 0; // 0 for limitless
        self.salt = '';
        self.log = false;
    };

    if (_.isUndefined(options)) {
        var options = {};
    }
    var op = _.defaults(options, defaultOptions);
    if(!_.isString(op.name) || op.name.length < 1) {
        common.log('valid name');
        // TODO: throw exception
        return;
    }
    op.logLocation = function() {
        var hash = crypto.createHash('sha1');
        hash.update(op.name, 'utf8');
        hash = hash.digest('hex');
        return './logs/rooms/'+hash+'.log';
    }();

    var room = this;
    room.workingSockets = 0;
    room.options = op;
    room.router = new Router();

    // NOTE: here we use sync read function
    // to ensure we have that key when running.
    if(room.options.salt.length < 1){
        room.options.salt = fs.readFileSync('./config/salt.key');
    }

    var hash_source = room.options.name + room.options.salt;
    var hashed = crypto.createHash('sha1');
    hashed.update(hash_source, 'utf8');
    room.signed_key = hashed.digest('hex');

    function prepareCheckoutTimer(r_room) {
        if(r_room.options.expiration) {
            r_room.checkoutTimer = setTimeout(function onTimeout() {
                r_room.options.emptyclose = true;
            }, r_room.options.expiration * 3600*1000);
        }
    };
    prepareCheckoutTimer(room);

    room.dataFile = function() {
        fs.exists('./data/room/', function (exists) {
          if(!exists){
            fs.mkdirSync('./data/room/');
          }
        });

        var hash = crypto.createHash('sha1');
        hash.update(room.options.name, 'utf8');
        hash = hash.digest('hex');
        return './data/room/'+hash+'.data';
    }();
    room.dataFileSize = 0;
    var bf = new BufferedFile({
                fileName: room.dataFile,
                bufferSize: 1024*1024*2,
                writeCycle: 0
            });

    room.msgFile = function() {
        fs.exists('./data/room/', function (exists) {
          if(!exists){
            fs.mkdirSync('./data/room/');
          }
        });

        var hash = crypto.createHash('sha1');
        hash.update(op.name, 'utf8');
        hash = hash.digest('hex');
        return './data/room/'+hash+'.msg';
    }();
    // room.msgFileSize = 0;
    var tf = new BufferedFile({
                fileName: room.msgFile,
                bufferSize: 1024*1024,
                writeCycle: 0
            });

    room.dataSocket = new socket.SocketServer();
    room.dataSocket.maxConnections = room.options.maxLoad;
    room.dataSocket.on('datapack', function(cli, dbuf) {
        bf.append(dbuf);
        room.dataFileSize += dbuf.length;
    }).on('connection', function(con){
        bf.readAll(function(da) {
            con.write(da);
        });
    });

    room.msgSocket = new socket.SocketServer();
    room.msgSocket.maxConnections = room.options.maxLoad;
    room.msgSocket.on('connection', function(con){
        con.on('end', function() {
            if(room.options.emptyclose){
                if(room.currentLoad() <= 1){
                    room.close();
                }
            }
        });

        room.msgSocket.sendData(con, JSON.stringify({
            content: '欢迎使用茶绘君，我们的主页：http://mrspaint.com。\n'+
                    '如果您在使用中有任何疑问，'+
                    '请在茶绘君贴吧留言：'+
                    'http://tieba.baidu.com/f?kw=%B2%E8%BB%E6%BE%FD \n'
        }));
        // TODO: use cmd channal
        // var send_msg = '
欢迎使用'+
        //             '茶绘君。
'+
        //             '如果您在使用中有任何疑问，'+
        //             '请在茶绘君贴吧留言。
\n';
        // BUG: use con will send msg into msgSocket, not cmdSocket
        // room.notify(con, send_msg);
        if(room.options.welcomemsg.length) {
            room.msgSocket.sendData(con, JSON.stringify({
                content: room.options.welcomemsg+'\n'
            }));
        }
        tf.readAll(function(da) {
            con.write(da);
        });
    }).on('datapack', function(cli, dbuf) {
        tf.append(dbuf);
    });

    room.router.reg('request', 'login', function(cli, obj) {
        var r_room = this;
        // name check
        if(!obj['name'] || !_.isString(obj['name'])){
            var ret = {
                response: 'login',
                result: false,
                errcode: 301
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
            return;
        }
        // password check
        if(r_room.options.password.length > 0){
            if(!obj['password'] || !_.isString(obj['password'])
            || obj['password'] != r_room.options.password){
                var ret = {
                    response: 'login',
                    result: false,
                    errcode: 302
                };
                logger.log(ret);
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
                return;
            }
        }
        // send info
        var ret = {
            response: 'login',
            result: true,
            info: {
                historysize: r_room.dataFileSize,
                dataport: r_room.ports().dataPort,
                msgport: r_room.ports().msgPort,
                size: r_room.options.canvasSize,
                clientid: function(){
                    var hash = crypto.createHash('sha1');
                    hash.update(r_room.options.name
                                + obj['name']
                                + r_room.options.salt
                                + (new Date()).getTime()
                                ,'utf8');
                    hash = hash.digest('hex');
                    cli['clientid'] = hash;
                    return hash;
                }()
            }
        };
        logger.log(ret);
        var jsString = JSON.stringify(ret);
        r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        cli['username'] = obj['name'];
        return;
    }, room).reg('request', 'close', function(cli, obj) {
        var r_room = this;
        // check signed key
        if(!obj['key'] || !_.isString(obj['key'])){
            var ret = {
                response: 'close',
                result: false
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }else{
            if(obj['key'].toLowerCase() == r_room.signed_key.toLowerCase()){
                var ret = {
                    response: 'close',
                    result: true
                };
                logger.log(ret);
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
                var ret_all = {
                    action: 'close',
                    'info': {
                        reason: 501
                    }
                };
                jsString = JSON.stringify(ret_all);
                logger.log(jsString);
                r_room.cmdSocket.broadcastData(new Buffer(jsString));
                r_room.options.emptyclose = true;
            }
        }
    }, room).reg('request', 'clearall', function(cli, obj) {
        var r_room = this;
        if(!obj['key'] || !_.isString(obj['key'])){
            var ret = {
                response: 'clearall',
                result: false
            };
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }else{
            if(obj['key'].toLowerCase() == r_room.signed_key.toLowerCase()){
                var ret = {
                    response: 'clearall',
                    result: true
                };
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
                var ret_all = {
                    action: 'clearall',
                };
                jsString = JSON.stringify(ret_all);
                r_room.cmdSocket.broadcastData(new Buffer(jsString));
                bf.clearAll();
                r_room.dataFileSize = 0;
            }else{
                var ret = {
                    response: 'clearall',
                    result: false
                };
                var jsString = JSON.stringify(ret);
                r_room.cmdSocket.sendData(cli, new Buffer(jsString));
            }
        }
    }, room).reg('request', 'onlinelist', function(cli, obj) {
        var r_room = this;
        if(!obj['clientid']){
            return;
        }
        logger.log('onlinelist request by '+obj['clientid']);
        if( !_.findWhere(r_room.cmdSocket.clients,
            {'clientid': obj['clientid']}) ){
            return;
        }

        var people = [];
        _.each(r_room.cmdSocket.clients, function(va) {
            if(va['username'] && va['clientid']){
                people.push({
                    'name': va['username'],
                    'clientid': va['clientid']
                });
            }
        });
        if(!people.length){
            return;
        }

        var ret = {
            response: 'onlinelist',
            result: true,
            onlinelist: people
        };
        logger.log(ret);
        var jsString = JSON.stringify(ret);
        r_room.cmdSocket.sendData(cli, new Buffer(jsString));
    }, room).reg('request', 'checkout', function(cli, obj) {
        var r_room = this;
        if(!obj['key'] || !_.isString(obj['key'])){
            var ret = {
                response: 'checkout',
                result: false,
                errcode: 701
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }
        if(obj['key'].toLowerCase() == r_room.signed_key.toLowerCase()){
            if(r_room.checkoutTimer){
                clearTimeout(r_room.checkoutTimer);
                prepareCheckoutTimer(r_room);
            }
            var ret = {
                response: 'checkout',
                result: true,
                cycle: r_room.options.expiration?r_room.options.expiration:0
            };
            logger.log(ret);
            var jsString = JSON.stringify(ret);
            r_room.cmdSocket.sendData(cli, new Buffer(jsString));
        }
    }, room);

    room.cmdSocket = new socket.SocketServer({
        autoBroadcast: false,
        useAlternativeParser: function(cli, buf) {
                var obj = JSON.parse(buf);
                room.router.message(cli, obj);
        }
    });
    room.cmdSocket.maxConnections = room.options.maxLoad;

    var tmpF = function() {
        room.workingSockets += 1;
        if(room.workingSockets >= 3) {
            room.emit('create', {
                cmdPort: room.cmdSocket.address().port,
                maxLoad: room.options.maxLoad,
                currentLoad: room.currentLoad(),
                name: room.options.name,
                key: room.signed_key
            });
        }
    };

    room.dataSocket.on('listening', tmpF);
    room.cmdSocket.on('listening', tmpF);
    room.msgSocket.on('listening', tmpF);
}

util.inherits(Room, events.EventEmitter);

Room.prototype.start = function() {
    if(!this.options.permanent) {
        fs.unlink(this.dataFile, function(){});
        fs.unlink(this.msgFile, function(){});
    }
    this.cmdSocket.listen(0, '::'); // this will support both ipv6 and ipv4 address
    this.dataSocket.listen(0, '::');
    this.msgSocket.listen(0, '::');
    return this;
};

Room.prototype.ports = function() {
    return {
        cmdPort: this.cmdSocket.address().port,
        dataPort: this.dataSocket.address().port,
        msgPort: this.msgSocket.address().port
    };
};

Room.prototype.close = function() {
    logger.log('Room.close()');
    this.emit('close');
    this.cmdSocket.close();
    this.dataSocket.close();
    this.msgSocket.close();
    if(!this.options.permanent) {
        fs.unlink(this.dataFile, function(){});
        fs.unlink(this.msgFile, function(){});
    }
    return this;
};

Room.prototype.currentLoad = function() {
    // do not count cmdSocket because it's a public socket
    return Math.max(this.dataSocket.clients.length,
        this.msgSocket.clients.length);
};

Room.prototype.notify = function(con, content) {
    var self = this;
    var sendContent = {
        action: 'notify',
        'content': content
    };
    self.cmdSocket.sendData(con, JSON.stringify(sendContent));
    logger.log('cmdSocket: ');
    logger.log(self.cmdSocket);
    logger.log(sendContent);
};

Room.prototype.bradcastMessage = function(content) {
    var self = this;
    var sendContent = {
        action: 'notify',
        'content': content
    };
    self.cmdSocket.broadcastData(JSON.stringify(sendContent));
};

module.exports = Room;<|endoftext|>


<commit_before>// var lifx = require('lifx');

/*
var day = {
	 hue: 360,
	 saturation: 1,
	 brightness: 1,
	 kelvin: 9000
}

var night = {
	hue: 360,
	saturation: 1,
	brightness: 0,
	kelvin: 2500,
	duration: 2
};
*/
//
// var fade = {
//         duration: 2000,
//         hue: 0,
//         saturation: 65535,
//         brightness: 32767,
//         kelvin: 0
//     }
//
//     lx.lightsColour(0, 65535, 32767, 3500, 2000);

// var lx = lifx.init();

/*
 * Saturation: 0x0000 to 0xffff
 *
 */

function Aurora(lx) {

	// var lx = lifx.init();
	console.log('============ CONSTRUCTOR =======================');
	console.log(lx);
	console.log('============ /CONSTRUCTOR =======================');

    this.lifx = lx;
}

Aurora.prototype = {
	fadeOn: function() {
		console.log('============  fadeOn: function ============');
		console.log(this.lifx);
		this.lifx.lightsColour(0, 65535, 32767, 3500, 2000);
	},
	turnOn: function() {
		console.log('============  turnOn: function ============');
	    this.lifx.lightsOn();
		this.getBulbStatus();
	},
	turnOff: function() {
		console.log('============  turnOff: function ============');
		console.log(this.lifx);
	    this.lifx.lightsOff();
		this.getBulbStatus();
	},
	shutdown: function() {
		console.log('Shutting down');
		this.lifx.lightsOff();
		this.lifx.close();
	},
	getBulbStatus: function() {
		console.log('**************** BULB STATUS *****************')
		console.log(this.lifx.requestStatus());
	}
}

// var aurora = new Aurora(lx);

module.exports = Aurora;
<commit_msg>Seperated out Aurora methods<commit_after>// var lifx = require('lifx');

/*
var day = {
	 hue: 360,
	 saturation: 1,
	 brightness: 1,
	 kelvin: 9000
}

var night = {
	hue: 360,
	saturation: 1,
	brightness: 0,
	kelvin: 2500,
	duration: 2
};
*/
//
// var fade = {
//         duration: 2000,
//         hue: 0,
//         saturation: 65535,
//         brightness: 32767,
//         kelvin: 0
//     }
//
//     lx.lightsColour(0, 65535, 32767, 3500, 2000);

// var lx = lifx.init();

/*
 * Saturation: 0x0000 to 0xffff
 *
 */

function Aurora(lx) {

	// var lx = lifx.init();
	console.log('============ CONSTRUCTOR =======================');
	console.log(lx);
	console.log('============ /CONSTRUCTOR =======================');

    this.lifx = lx;
}

Aurora.prototype.fadeOn = function() {
		console.log('============  fadeOn: function ============');
		console.log(this.lifx);
		this.lifx.lightsColour(0, 65535, 32767, 3500, 2000);
	}

Aurora.prototype.turnOn = function() {
		console.log('============  turnOn: function ============');
	    this.lifx.lightsOn();
		this.getBulbStatus();
}

Aurora.prototype.turnOff = function() {
		console.log('============  turnOff: function ============');
		console.log(this.lifx);
	    this.lifx.lightsOff();
		this.getBulbStatus();
}

Aurora.prototype.shutdown = function() {
		console.log('Shutting down');
		this.lifx.lightsOff();
		this.lifx.close();
}

Aurora.prototype.getBulbStatus = function() {
		console.log('**************** BULB STATUS *****************')
		console.log(this.lifx.requestStatus());
}

// var aurora = new Aurora(lx);

module.exports = Aurora;
<|endoftext|>


<commit_before>import $ from 'jquery'
import startswith from 'lodash.startswith'

const fetch = window.fetch
const path = window.location.pathname.split('/')

export function process () {
  let treePromise =
    fetch(`https://api.github.com/repos/${path[1]}/${path[2]}/git/refs/heads/${path[4]}`)
    .then(res => res.json())
    .then(data => data.object.sha)
    .then(sha => fetch(`https://api.github.com/repos/${path[1]}/${path[2]}/git/trees/${sha}?recursive=4`))
    .then(res => res.json())
    .then(data => data.tree)
    .then(tree => tree.filter(b => startswith(b.path, 'lib/')))
    .then(tree => tree.map(b => b.path.split('/').slice(1).join('/')))

  $('.blob-code-inner').each((i, el) => {
    (function (elem) {
      let line = elem.innerText.trim()
      let require = /require ["']([\w-_\/]*)["']/.exec(line)
      if (!require) return
      let moduleName = require[1]

      treePromise.then(paths => {
        for (let i = 0; i < paths.length; i++) {
          let relativePath = paths[i]

          if (relativePath.slice(0, -3) === moduleName) {
            return `/${path[1]}/${path[2]}/blob/${path[4]}/lib/` + relativePath
          }
        }

        if (moduleName in stdlib) {
          return 'http://ruby-doc.org/stdlib/libdoc/' + moduleName + '/rdoc/index.html'
        } else {
          return 'https://rubygems.org/gems/' + moduleName
        }
      })
      .then(url =>
        $(elem).find('.pl-s').wrap(`<a href="${url}"></a>`)
      )
    })(el)
  })
}

const stdlib = {abbrev: 1, base64: 1, benchmark: 1, bigdecimal: 1, cgi: 1, cmath: 1, coverage: 1, csv: 1, date: 1, dbm: 1, debug: 1, delegate: 1, digest: 1, drb: 1, e2mmap: 1, English: 1, erb: 1, etc: 1, expect: 1, extmk: 1, fcntl: 1, fiddle: 1, fileutils: 1, find: 1, forwardable: 1, gdbm: 1, getoptlong: 1, 'io/console': 1, 'io/nonblock': 1, 'io/wait': 1, ipaddr: 1, irb: 1, json: 1, logger: 1, mathn: 1, matrix: 1, mkmf: 1, monitor: 1, mutex_m: 1, 'net/ftp': 1, 'net/http': 1, 'net/imap': 1, 'net/pop': 1, 'net/smtp': 1, 'net/telnet': 1, nkf: 1, objspace: 1, observer: 1, 'open-uri': 1, open3: 1, openssl: 1, optparse: 1, ostruct: 1, pathname: 1, pp: 1, prettyprint: 1, prime: 1, profile: 1, profiler: 1, pstore: 1, psych: 1, pty: 1, racc: 1, 'racc/parser': 1, rake: 1, rdoc: 1, readline: 1, resolv: 1, 'resolv-replace': 1, rexml: 1, rinda: 1, ripper: 1, rss: 1, rubygems: 1, scanf: 1, sdbm: 1, securerandom: 1, set: 1, shell: 1, shellwords: 1, singleton: 1, socket: 1, stringio: 1, strscan: 1, sync: 1, syslog: 1, tempfile: 1, thread: 1, thwait: 1, time: 1, timeout: 1, tk: 1, tmpdir: 1, tracer: 1, tsort: 1, un: 1, unicode_normalize: 1, uri: 1, weakref: 1, webrick: 1, win32ole: 1, xmlrpc: 1, yaml: 1, zlib: 1}
<commit_msg>better ruby support.<commit_after>import $ from 'jquery'

const fetch = window.fetch
const path = window.location.pathname.split('/')

export function process () {
  let treePromise =
    fetch(`https://api.github.com/repos/${path[1]}/${path[2]}/git/refs/heads/${path[4]}`)
    .then(res => res.json())
    .then(data => data.object.sha)
    .then(sha => fetch(`https://api.github.com/repos/${path[1]}/${path[2]}/git/trees/${sha}?recursive=4`))
    .then(res => res.json())
    .then(data => data.tree)
    .then(tree => tree.map(b => {
      let parts = b.path.split('/')
      let index = parts.indexOf('lib')
      if (index === -1) return null
      return {
        prefix: parts.slice(0, index).join('/'),
        suffix: parts.slice(index + 1).join('/')
      }
    }))
    .then(tree => tree.filter(path => path))

  $('.blob-code-inner').each((i, el) => {
    (function (elem) {
      let line = elem.innerText.trim()
      let require = /require ["']([\w-_\/]*)["']/.exec(line)
      if (!require) return
      let moduleName = require[1]

      treePromise.then(paths => {
        for (let i = 0; i < paths.length; i++) {
          let {prefix, suffix} = paths[i]

          if (suffix.slice(0, -3) === moduleName) {
            return `/${path[1]}/${path[2]}/blob/${path[4]}/${prefix}/lib/${suffix}`
          }
        }

        if (moduleName in stdlib) {
          return 'http://ruby-doc.org/stdlib/libdoc/' + moduleName + '/rdoc/index.html'
        } else {
          return 'https://rubygems.org/gems/' + moduleName
        }
      })
      .then(url =>
        $(elem).find('.pl-s').wrap(`<a href="${url}"></a>`)
      )
    })(el)
  })
}

const stdlib = {abbrev: 1, base64: 1, benchmark: 1, bigdecimal: 1, cgi: 1, cmath: 1, coverage: 1, csv: 1, date: 1, dbm: 1, debug: 1, delegate: 1, digest: 1, drb: 1, e2mmap: 1, English: 1, erb: 1, etc: 1, expect: 1, extmk: 1, fcntl: 1, fiddle: 1, fileutils: 1, find: 1, forwardable: 1, gdbm: 1, getoptlong: 1, 'io/console': 1, 'io/nonblock': 1, 'io/wait': 1, ipaddr: 1, irb: 1, json: 1, logger: 1, mathn: 1, matrix: 1, mkmf: 1, monitor: 1, mutex_m: 1, 'net/ftp': 1, 'net/http': 1, 'net/imap': 1, 'net/pop': 1, 'net/smtp': 1, 'net/telnet': 1, nkf: 1, objspace: 1, observer: 1, 'open-uri': 1, open3: 1, openssl: 1, optparse: 1, ostruct: 1, pathname: 1, pp: 1, prettyprint: 1, prime: 1, profile: 1, profiler: 1, pstore: 1, psych: 1, pty: 1, racc: 1, 'racc/parser': 1, rake: 1, rdoc: 1, readline: 1, resolv: 1, 'resolv-replace': 1, rexml: 1, rinda: 1, ripper: 1, rss: 1, rubygems: 1, scanf: 1, sdbm: 1, securerandom: 1, set: 1, shell: 1, shellwords: 1, singleton: 1, socket: 1, stringio: 1, strscan: 1, sync: 1, syslog: 1, tempfile: 1, thread: 1, thwait: 1, time: 1, timeout: 1, tk: 1, tmpdir: 1, tracer: 1, tsort: 1, un: 1, unicode_normalize: 1, uri: 1, weakref: 1, webrick: 1, win32ole: 1, xmlrpc: 1, yaml: 1, zlib: 1}
<|endoftext|>


<commit_before>'use strict';

var Joi = require('joi');
Joi.objectId = require('joi-objectid')(Joi);
var _ = require('lodash');
var assert = require('assert');
var validationHelper = require("./validation-helper");
var mongoose = require('mongoose');

//TODO: support "allowNull"
//TODO: add ".default()" to paths that have a default value
//TODO: support arrays and objects
//TODO: support "allowUndefined"

module.exports = {

  /**
   * Generates a Joi object that validates a query result for a specific model
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiReadModel: function (model, Log) {
    validationHelper.validateModel(model, Log);

    var readModelBase = {};

    var fields = model.schema.paths;

    var associations = model.routeOptions.associations ? Object.keys(model.routeOptions.associations) : [];

    for (var fieldName in fields) {
      var field = fields[fieldName].options;

      var isAssociation = associations.indexOf(fields[fieldName].path);

      if (field.readModel) {
        readModelBase[fieldName] = field.readModel;
      }
      else if (field.allowOnRead !== false && field.exclude !== true && isAssociation < 0 && fieldName !== "__v") {
        var attributeReadModel = this.generateJoiModelFromFieldType(field, Log);

        if (field.requireOnRead === true) {
          attributeReadModel = attributeReadModel.required();
        }

        readModelBase[fieldName] = attributeReadModel;
      }
    }

    if (model.routeOptions && model.routeOptions.associations) {
      for (var associationName in model.routeOptions.associations) {
        var association = model.routeOptions.associations[associationName];

        //TODO: possibly add stricter validation for associations
        if (association.type === "MANY_MANY" || association.type === "ONE_MANY") {
          readModelBase[associationName] = Joi.array().items(Joi.object().unknown());
          if (association.linkingModel) {
            readModelBase[association.linkingModel] = Joi.object().unknown().allow(null);
          }
        } else {
          readModelBase[associationName] = Joi.object().unknown().allow(null);
        }
      }
    }

    var readModel = Joi.object(readModelBase).label(model.modelName + "ReadModel");

    return readModel;
  },

  /**
   * Generates a Joi object that validates a query request payload for updating a document
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiUpdateModel: function (model, Log) {
    validationHelper.validateModel(model, Log);

    var updateModelBase = {};

    var fields = model.schema.paths;

    var associations = model.routeOptions.associations ? model.routeOptions.associations : {};

    for (var fieldName in fields) {
      var field = fields[fieldName].options;

      var association = associations[fields[fieldName].path] || null;

      var canUpdateAssociation = association ? (association.type === "ONE_ONE" || association.type === "MANY_ONE") : false;

      if (fieldName !== "__t" && fieldName !== "__v") {
        if (field.updateModel) {
          updateModelBase[fieldName] = field.updateModel;
        }
        else if (field.allowOnUpdate !== false && (canUpdateAssociation || !association)) {
          var attributeUpdateModel = this.generateJoiModelFromFieldType(field, Log);

          if (field.requireOnUpdate === true) {
            attributeUpdateModel = attributeUpdateModel.required();
          }

          updateModelBase[fieldName] = attributeUpdateModel;
        }
      }
    }

    var updateModel = Joi.object(updateModelBase).label(model.modelName + "UpdateModel");

    return updateModel;
  },

  /**
   * Generates a Joi object that validates a query request payload for creating a document
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiCreateModel: function (model, Log) {
    validationHelper.validateModel(model, Log);

    var createModelBase = {};

    var fields = model.schema.paths;

    var associations = model.routeOptions.associations ? model.routeOptions.associations : {};

    for (var fieldName in fields) {

      var field = fields[fieldName].options;

      var association = associations[fields[fieldName].path] || null;

      var canCreateAssociation = association ? (association.type === "ONE_ONE" || association.type === "MANY_ONE") : false;

      if (fieldName !== "__t" && fieldName !== "__v") {
        if (field.createModel) {
          createModelBase[fieldName] = field.createModel;
        }
        else if (field.allowOnCreate !== false && (canCreateAssociation || !association)) {
          var attributeCreateModel = this.generateJoiModelFromFieldType(field, Log);

          if (field.required === true) {
            attributeCreateModel = attributeCreateModel.required();
          }

          createModelBase[fieldName] = attributeCreateModel;
        }
      }
    }

    var createModel = Joi.object(createModelBase).label(model.modelName + "CreateModel");

    return createModel;
  },

  /**
   * Generates a Joi object that validates a query request payload for adding a association
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiAssociationModel: function (model, Log) {
    assert(model.Schema, "incorrect model format");

    var associationModelBase = {};

    for (var fieldName in model.Schema) {

      var field = model.Schema[fieldName];

      if (field.createModel) {
        associationModelBase[fieldName] = field.createModel;
      }
      else {
        var attributeAssociationModel = this.generateJoiModelFromFieldType(field, Log);

        if (field.required) {
          attributeAssociationModel = attributeAssociationModel.required();
        }
        associationModelBase[fieldName] = attributeAssociationModel;
      }
    }

    var associationModel = Joi.object(associationModelBase).label(model.modelName + "AssociationModel");

    return associationModel;
  },

  /**
   * Returns a Joi object based on the mongoose field type.
   * @param field: A field from a mongoose model.
   * @param Log: A logging object.
   * @returns {*}: A Joi object.
   */
  generateJoiModelFromFieldType: function (field, Log) {
    var model;

    assert(field.type, "incorrect field format");

    let isArray = false;
    let fieldCopy = _.extend({}, field);

    if (_.isArray(fieldCopy.type)) {
      isArray = true;
      fieldCopy.type = fieldCopy.type[0];
    }

    switch (fieldCopy.type.schemaName) {
      case 'ObjectId':
        model = Joi.objectId().description("objectId");
        break;
      case 'Boolean':
        model = Joi.bool();
        break;
      case 'Number':
        model = Joi.number();
        break;
      case 'Date':
        model = Joi.date();
        break;
      case 'String':
        if (fieldCopy.enum) {
          model = Joi.any().only(fieldCopy.enum);
        }
        else if (fieldCopy.stringType) {
          switch (fieldCopy.stringType) {
            case 'uri':
              model = Joi.string().uri();
              break;
            case 'email':
              model = Joi.string().email();
              break;
            case 'token':
              model = Joi.string().token();
              break;
            case 'hex':
              model = Joi.string().hex();
              break;
            case 'base64':
              model = Joi.string().base64();
              break;
            case 'hostname':
              model = Joi.string().hostname();
              break;
            case 'lowercase':
              model = Joi.string().lowercase();
              break;
            case 'uppercase':
              model = Joi.string().uppercase();
              break;
            case 'trim':
              model = Joi.string().trim();
              break;
            case 'creditCard':
              model = Joi.string().creditCard();
              break;
            default:
              model = Joi.string().allow('');
          }
        }
        else {
          model = Joi.string().allow('');
        }
        break;
      default:
        model = Joi.any();
        break;
    }

    if (fieldCopy.allowNull) {
      model = model.allow(null);
    }

    if (isArray) {
      model = Joi.array().items(model);
    }

    if (fieldCopy.description) {
      model = model.description(fieldCopy.description);
    }
    else if (fieldCopy.stringType) {
      model = model.description(fieldCopy.stringType);
    }

    return model;
  }

};<commit_msg>Relaxed validation of readAssociation to allow for direct id arrays.<commit_after>'use strict';

var Joi = require('joi');
Joi.objectId = require('joi-objectid')(Joi);
var _ = require('lodash');
var assert = require('assert');
var validationHelper = require("./validation-helper");
var mongoose = require('mongoose');

//TODO: support "allowNull"
//TODO: add ".default()" to paths that have a default value
//TODO: support arrays and objects
//TODO: support "allowUndefined"

module.exports = {

  /**
   * Generates a Joi object that validates a query result for a specific model
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiReadModel: function (model, Log) {
    validationHelper.validateModel(model, Log);

    var readModelBase = {};

    var fields = model.schema.paths;

    var associations = model.routeOptions.associations ? Object.keys(model.routeOptions.associations) : [];

    for (var fieldName in fields) {
      var field = fields[fieldName].options;

      var isAssociation = associations.indexOf(fields[fieldName].path);

      if (field.readModel) {
        readModelBase[fieldName] = field.readModel;
      }
      else if (field.allowOnRead !== false && field.exclude !== true && isAssociation < 0 && fieldName !== "__v") {
        var attributeReadModel = this.generateJoiModelFromFieldType(field, Log);

        if (field.requireOnRead === true) {
          attributeReadModel = attributeReadModel.required();
        }

        readModelBase[fieldName] = attributeReadModel;
      }
    }

    if (model.routeOptions && model.routeOptions.associations) {
      for (var associationName in model.routeOptions.associations) {
        var association = model.routeOptions.associations[associationName];

        //TODO: possibly add stricter validation for associations
        if (association.type === "MANY_MANY" || association.type === "ONE_MANY") {
          readModelBase[associationName] = Joi.array().items(Joi.any());
          if (association.linkingModel) {
            readModelBase[association.linkingModel] = Joi.object().unknown().allow(null);
          }
        } else {
          readModelBase[associationName] = Joi.object().unknown().allow(null);
        }
      }
    }

    var readModel = Joi.object(readModelBase).label(model.modelName + "ReadModel");

    return readModel;
  },

  /**
   * Generates a Joi object that validates a query request payload for updating a document
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiUpdateModel: function (model, Log) {
    validationHelper.validateModel(model, Log);

    var updateModelBase = {};

    var fields = model.schema.paths;

    var associations = model.routeOptions.associations ? model.routeOptions.associations : {};

    for (var fieldName in fields) {
      var field = fields[fieldName].options;

      var association = associations[fields[fieldName].path] || null;

      var canUpdateAssociation = association ? (association.type === "ONE_ONE" || association.type === "MANY_ONE") : false;

      if (fieldName !== "__t" && fieldName !== "__v") {
        if (field.updateModel) {
          updateModelBase[fieldName] = field.updateModel;
        }
        else if (field.allowOnUpdate !== false && (canUpdateAssociation || !association)) {
          var attributeUpdateModel = this.generateJoiModelFromFieldType(field, Log);

          if (field.requireOnUpdate === true) {
            attributeUpdateModel = attributeUpdateModel.required();
          }

          updateModelBase[fieldName] = attributeUpdateModel;
        }
      }
    }

    var updateModel = Joi.object(updateModelBase).label(model.modelName + "UpdateModel");

    return updateModel;
  },

  /**
   * Generates a Joi object that validates a query request payload for creating a document
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiCreateModel: function (model, Log) {
    validationHelper.validateModel(model, Log);

    var createModelBase = {};

    var fields = model.schema.paths;

    var associations = model.routeOptions.associations ? model.routeOptions.associations : {};

    for (var fieldName in fields) {

      var field = fields[fieldName].options;

      var association = associations[fields[fieldName].path] || null;

      var canCreateAssociation = association ? (association.type === "ONE_ONE" || association.type === "MANY_ONE") : false;

      if (fieldName !== "__t" && fieldName !== "__v") {
        if (field.createModel) {
          createModelBase[fieldName] = field.createModel;
        }
        else if (field.allowOnCreate !== false && (canCreateAssociation || !association)) {
          var attributeCreateModel = this.generateJoiModelFromFieldType(field, Log);

          if (field.required === true) {
            attributeCreateModel = attributeCreateModel.required();
          }

          createModelBase[fieldName] = attributeCreateModel;
        }
      }
    }

    var createModel = Joi.object(createModelBase).label(model.modelName + "CreateModel");

    return createModel;
  },

  /**
   * Generates a Joi object that validates a query request payload for adding a association
   * @param model: A mongoose model object.
   * @param Log: A logging object.
   * @returns {*}: A Joi object
   */
  generateJoiAssociationModel: function (model, Log) {
    assert(model.Schema, "incorrect model format");

    var associationModelBase = {};

    for (var fieldName in model.Schema) {

      var field = model.Schema[fieldName];

      if (field.createModel) {
        associationModelBase[fieldName] = field.createModel;
      }
      else {
        var attributeAssociationModel = this.generateJoiModelFromFieldType(field, Log);

        if (field.required) {
          attributeAssociationModel = attributeAssociationModel.required();
        }
        associationModelBase[fieldName] = attributeAssociationModel;
      }
    }

    var associationModel = Joi.object(associationModelBase).label(model.modelName + "AssociationModel");

    return associationModel;
  },

  /**
   * Returns a Joi object based on the mongoose field type.
   * @param field: A field from a mongoose model.
   * @param Log: A logging object.
   * @returns {*}: A Joi object.
   */
  generateJoiModelFromFieldType: function (field, Log) {
    var model;

    assert(field.type, "incorrect field format");

    let isArray = false;
    let fieldCopy = _.extend({}, field);

    if (_.isArray(fieldCopy.type)) {
      isArray = true;
      fieldCopy.type = fieldCopy.type[0];
    }

    switch (fieldCopy.type.schemaName) {
      case 'ObjectId':
        model = Joi.objectId().description("objectId");
        break;
      case 'Boolean':
        model = Joi.bool();
        break;
      case 'Number':
        model = Joi.number();
        break;
      case 'Date':
        model = Joi.date();
        break;
      case 'String':
        if (fieldCopy.enum) {
          model = Joi.any().only(fieldCopy.enum);
        }
        else if (fieldCopy.stringType) {
          switch (fieldCopy.stringType) {
            case 'uri':
              model = Joi.string().uri();
              break;
            case 'email':
              model = Joi.string().email();
              break;
            case 'token':
              model = Joi.string().token();
              break;
            case 'hex':
              model = Joi.string().hex();
              break;
            case 'base64':
              model = Joi.string().base64();
              break;
            case 'hostname':
              model = Joi.string().hostname();
              break;
            case 'lowercase':
              model = Joi.string().lowercase();
              break;
            case 'uppercase':
              model = Joi.string().uppercase();
              break;
            case 'trim':
              model = Joi.string().trim();
              break;
            case 'creditCard':
              model = Joi.string().creditCard();
              break;
            default:
              model = Joi.string().allow('');
          }
        }
        else {
          model = Joi.string().allow('');
        }
        break;
      default:
        model = Joi.any();
        break;
    }

    if (fieldCopy.allowNull) {
      model = model.allow(null);
    }

    if (isArray) {
      model = Joi.array().items(model);
    }

    if (fieldCopy.description) {
      model = model.description(fieldCopy.description);
    }
    else if (fieldCopy.stringType) {
      model = model.description(fieldCopy.stringType);
    }

    return model;
  }

};<|endoftext|>


<commit_before>(function(w){
    var B = {
        dataArr:[

        ],
        addValue:function(name, data){

        },
        addArrValues: function(){

        },

    };

    function insertValues(name, value) {
        var patternConstructor = "/{{"+name+"}}/";
        var pattern = new RegExp(patternConstructor, "gi");
        var body = document.getElementsByTagName("body")[0];
        //var bodyText = document.getElementsByTagName("body")[0].innerHTML;
        var bodyText = body.innerHTML;
        bodyLikeText.replace(pattern, value);
        body.innerHTML = bodyText;
    }

    return B;
})(windows);<commit_msg>fix scopes<commit_after>(function(w, d){
    var B = {
        dataArr:[

        ],
        addValue:function(name, data){

        },
        addArrValues: function(){

        },

    };

    function insertValues(name, value) {
        var patternConstructor = "/{{"+name+"}}/";
        var pattern = new RegExp(patternConstructor, "gi");
        var body = d.getElementsByTagName("body")[0];
        //var bodyText = document.getElementsByTagName("body")[0].innerHTML;
        var bodyText = body.innerHTML;
        bodyLikeText.replace(pattern, value);
        body.innerHTML = bodyText;
    }

    return B;
})(windows, document);<|endoftext|>


<commit_before>var POLLING_INTERVAL = 3500, // Milliseconds
    VICINITY_STRENGTH = -8, // B/T RSSI
    BUTTON_HOLD_TIME = 2000, // Milliseconds
    DISCONNECTION_DURATION = 24500, // Milliseconds
    CONF_FILE = 'BLUETOOTH-HW.CONF';

var exec = require('child_process').exec,
    fs = require("fs"),
    GPIO = require('rpi').GPIO;

var mac = fs.readFileSync(CONF_FILE);

var unlockPin = new GPIO(0, 'out'),
    lockPin = new GPIO(7, 'out');

var changeButton = new GPIO(8, 'in');

var connectionStatus = false,
    lastConnectionTime = 0;

var disconnectionCount = 0;

changeButton.on('change', function(value) {
    if (value == 1) {
        exec("hcitool scan", function(error, stdout, stderr) {
            mac = stdout.split("\n")[1].split("\t")[1];
            //
            // check mac, err. check with values
            // take first dev.
            //
            fs.writeFileSync(CONF_FILE, mac);
        });
    }
});

function switchPower(pin) {
    pin.high();
    setTimeout(function() {
        pin.low();
    }, BUTTON_HOLD_TIME);
}

function cmd() {
    return "hcitool cc " + mac + " && hcitool rssi " + mac;
}

function parseConnectionStrength(resp) {
    var rawRSSI = resp.split(": ")[1];
    if (rawRSSI != "") {
        return Math.round(rawRSSI); // Math.round is applied to convert string to number, returns RSSI from command
    } else {
        return -2056;               // Device is not is range
    }
}

// Probe for Device Presence
setInterval(function() {
    if (mac.length == 17) {
        exec(cmd(), function(error, stdout, stderr) {
            var connectionStrength = parseConnectionStrength(stdout);

            // Check if phone is in valid range
            if ((connected == false) && (connectionStrength > VICINITY_STRENGTH)) {
                switchPower(unlockPin);
                connected = true;
                lastConnectionTime = Date.now();
                disconnectionCount = 0;
            }
            // If the signal is weaker than that, treat it as though the phone is not in valid range
            else if ((connected == true) && (connectionStrength < VICINITY_STRENGTH)) {
                disconnectionCount++;
                // Calculate approx. how many times hardware should be probed before disconnect is acknowledged
                if (disconnectionCount >= Math.ceil(DISCONNECTION_DURATION / POLLING_INTERVAL)) {
                    switchPower(lockPin);
                    connected = false;
                }
            }
        });
    }
}, POLLING_INTERVAL);<commit_msg>Cleanup Code & Add Device Option<commit_after>var POLLING_INTERVAL = 3500, // Milliseconds
    VICINITY_STRENGTH = -8, // B/T RSSI
    BUTTON_HOLD_TIME = 2000, // Milliseconds
    DISCONNECTION_DURATION = 24500, // Milliseconds
    CONF_FILE = 'BLUETOOTH-HW.CONF';

var exec = require('child_process').exec,
    fs = require("fs"),
    GPIO = require('rpi').GPIO;

var mac = fs.readFileSync(CONF_FILE);

var unlockPin = new GPIO(0, 'out'),
    lockPin = new GPIO(7, 'out');

var changeButton = new GPIO(8, 'in');

var inRange = false,
    lastConnectionTime = 0;

var disconnectionCount = 0;

changeButton.on('change', function(value) {
    if (value == 1) {
        console.log("Request to Change Bluetooth Device Received.");
        exec("hcitool scan", function(error, stdout, stderr) {
            console.log(" - Scanning...");
            var mac_addr_line = stdout.split("\n")

            if(mac_addr_line[1] != ""){
                var temp_mac = mac_addr_line[1].split("\t")[1];

                if(temp_mac.length = 17){
                    console.log("   - Device found: " + mac);
                    mac = temp_mac;
                    fs.writeFileSync(CONF_FILE, mac);
                } else {
                    console.log("   - No Device was Found.");
                }
            }
        });
    }
});

function switchPower(pin) {
    pin.high();
    setTimeout(function() {
        pin.low();
    }, BUTTON_HOLD_TIME);
}

function cmd() {
    return "hcitool cc " + mac + " && hcitool rssi " + mac;
}

function parseConnectionStrength(resp) {
    var rawRSSI = resp.split(": ")[1];
    console.log("    - raw RSSI: " + rawRSSI);

    if (rawRSSI != "") {
        return Math.round(rawRSSI); // Math.round is applied to convert string to number, returns RSSI from command
    } else {
        return -2056;               // Device is not is range, return number that is guaranteed to far out of the RSSI range
    }
}

// Probe for Device Presence
setInterval(function() {
    console.log("Probing for Connection...");
    console.log(" - " + Date.now());
    if (mac.length == 17) {
        console.log(" - Valid MAC Address was found, detecting signal strength.");
        exec(cmd(), function(error, stdout, stderr) {
            var connectionStrength = parseConnectionStrength(stdout);

            // Check if phone is in valid range
            if ((inRange == false) && (connectionStrength > VICINITY_STRENGTH)) {
                console.log(" - Phone is in the disconnected state and device is within preconfigured vicinity.");
                console.log("    - Unlocking Car");
                switchPower(unlockPin);
                console.log("    - Reconfiguring Variables");
                inRange = true;
                lastConnectionTime = Date.now();
                disconnectionCount = 0;
                console.log("       - Connection Time: " + lastConnectionTime);
            }
            // If the signal is weaker than that, treat it as though the phone is not in valid range
            else if ((inRange == true) && (connectionStrength < VICINITY_STRENGTH)) {
                console.log(" - Phone is in the connected state and device is not within preconfigured vicinity.");
                disconnectionCount++;
                console.log("    - Increment Disconnection Count: " + disconnectionCount);
                // Calculate approx. how many times hardware should be probed before disconnect is acknowledged
                if (disconnectionCount >= Math.ceil(DISCONNECTION_DURATION / POLLING_INTERVAL)) {
                    console.log("    - Locking Car");
                    switchPower(lockPin);
                    inRange = false;
                }
            }
        });
    }
    console.log("--------------");
}, POLLING_INTERVAL);<|endoftext|>


<commit_before>/*
Name:             bolcom.js
Description:      Module for node.js to access Bol.com Open API service.
Author:           Franklin van de Meent (https://frankl.in)
Source:           https://github.com/fvdm/nodejs-bolcom
Bugs & feedback:  https://github.com/fvdm/nodejs-bolcom/issues
License:          Unlicense / Public Domain

Service name:     Bol.com
Service docs:     https://developers.bol.com
*/

var https = require('https')
var querystring = require('querystring')
var api_key = null
var api_timeout = 5000

var app = {
  catalog: {},
  utils: {},
  account: {}
}

// Communicate
function talk( cat, method, params, callback ) {
  if( typeof params === 'function' ) {
    var callback = params
    var params = {}
  }
  params = params instanceof Object ? params : {}

  // check api key
  if( typeof api_key === 'string' && api_key.length > 0 ) {
    params.apikey = api_key
  } else {
    doCallback( new Error('missing apikey') )
    return
  }

  // prevent multiple callbacks
  var complete = false
  function doCallback( err, data ) {
    if( !complete ) {
      complete = true
      callback( err, data || null )
    }
  }

  // build request
  params.format = 'json'

  var options = {
    host: 'api.bol.com',
    path: '/'+ cat +'/v4/'+ method +'?'+ querystring.stringify(params),
    method: 'GET',
    headers: {
      'User-Agent': 'bolcom.js (https://frankl.in)'
    }
  }

  var request = https.request(options)

  // process response
  request.on( 'response', function(response) {
    var data = ''

    response.on( 'data', function(ch) { data += ch })

    response.on( 'close', function() {
      doCallback(new Error('request dropped'))
    })

    response.on( 'end', function() {
      var error = null
      if( response.statusCode != 200 ) {
        error = new Error('API error')
      }

      try {
        data = JSON.parse( data )
      } catch(e) {
        error = new Error('invalid response')
        error.err = e
      }

      if( error ) {
        error.code = response.statusCode
        error.headers = response.headers
        error.api = data instanceof Object ? data : {}
        error.body = data instanceof Object ? null : data
      }

      doCallback( error, data )
    })
  })

  // timeout
  request.on( 'socket', function( socket ) {
    if( api_timeout ) {
      socket.setTimeout( api_timeout )
      socket.on( 'timeout', function() {
        request.abort()
      })
    }
  })

  // error
  request.on( 'error', function( err ) {
    if( err == 'ECONNRESET' ) {
      var error = new Error('request timeout')
    } else {
      var error = new Error('request failed')
    }
    error.err = err
    doCallback( error )
  })

  // do it
  request.end()
}

module.exports = function(apikey, timeout) {
  api_key = apikey
  api_timeout = timeout || api_timeout
  return app
}<commit_msg>Added method utils.ping<commit_after>/*
Name:             bolcom.js
Description:      Module for node.js to access Bol.com Open API service.
Author:           Franklin van de Meent (https://frankl.in)
Source:           https://github.com/fvdm/nodejs-bolcom
Bugs & feedback:  https://github.com/fvdm/nodejs-bolcom/issues
License:          Unlicense / Public Domain

Service name:     Bol.com
Service docs:     https://developers.bol.com
*/

var https = require('https')
var querystring = require('querystring')
var api_key = null
var api_timeout = 5000

var app = {
  catalog: {},
  utils: {},
  account: {}
}

app.utils.ping = function( callback ) {
  talk( 'utils', 'ping', callback )
}

// Communicate
function talk( cat, method, params, callback ) {
  if( typeof params === 'function' ) {
    var callback = params
    var params = {}
  }
  params = params instanceof Object ? params : {}

  // check api key
  if( typeof api_key === 'string' && api_key.length > 0 ) {
    params.apikey = api_key
  } else {
    doCallback( new Error('missing apikey') )
    return
  }

  // prevent multiple callbacks
  var complete = false
  function doCallback( err, data ) {
    if( !complete ) {
      complete = true
      callback( err, data || null )
    }
  }

  // build request
  params.format = 'json'

  var options = {
    host: 'api.bol.com',
    path: '/'+ cat +'/v4/'+ method +'?'+ querystring.stringify(params),
    method: 'GET',
    headers: {
      'User-Agent': 'bolcom.js (https://frankl.in)'
    }
  }

  var request = https.request(options)

  // process response
  request.on( 'response', function(response) {
    var data = ''

    response.on( 'data', function(ch) { data += ch })

    response.on( 'close', function() {
      doCallback(new Error('request dropped'))
    })

    response.on( 'end', function() {
      var error = null
      if( response.statusCode != 200 ) {
        error = new Error('API error')
      }

      try {
        data = JSON.parse( data )
      } catch(e) {
        error = new Error('invalid response')
        error.err = e
      }

      if( error ) {
        error.code = response.statusCode
        error.headers = response.headers
        error.api = data instanceof Object ? data : {}
        error.body = data instanceof Object ? null : data
      }

      doCallback( error, data )
    })
  })

  // timeout
  request.on( 'socket', function( socket ) {
    if( api_timeout ) {
      socket.setTimeout( api_timeout )
      socket.on( 'timeout', function() {
        request.abort()
      })
    }
  })

  // error
  request.on( 'error', function( err ) {
    if( err == 'ECONNRESET' ) {
      var error = new Error('request timeout')
    } else {
      var error = new Error('request failed')
    }
    error.err = err
    doCallback( error )
  })

  // do it
  request.end()
}

module.exports = function(apikey, timeout) {
  api_key = apikey
  api_timeout = timeout || api_timeout
  return app
}<|endoftext|>