<commit_before>"use strict";

var Cylon = require('cylon')
var tilted = false;
var talking = false;
var leds = {red:2,blue:3,green:4};
var color = "";
var whiteArray = {red:0,blue:0,green:0};
var blackArray = {red:0,blue:0,green:0};
var colorArray = {red:0,blue:0,green:0};

Cylon.robot({
  connections: {
    edison: { adaptor: 'intel-iot' }
  },
  devices: {
    //outputs:
    laser: { driver: 'led', pin: 7 },
    rgb_led: { driver: 'rgb-led', redPin: 4, greenPin: 5, bluePin: 6 },

    //inputs:
    tilt: { driver: 'button', pin: 3 },
    button: { driver: 'button', pin: 2 },
    ambient: { driver: 'analog-sensor', pin: 3, lowerLimit: 100, upperLimit: 900 },
    color_detector: { driver: 'analog-sensor', pin: 0, lowerLimit: 0, upperLimit: 1024 },

  },
  work: function(my) {
    my.button.on('push', function() {
      my.laser.toggle();
    });
  },

  detect_color: function() {

  },

  output_sound: function(color) {
    console.log(color + " detected");
    if (!talking){
        if (color === "red"){

        }
        if (color === "green"){

        }
        if (color === "blue"){

        }
    }
  },

  warn_tilt: function() {
    my.tilt.on('push', function() {
      console.log("Tilt Activated");
      tilted = true;
    });
    my.tilt.on('release', function() {
      console.log("Tilt Deactivated");
      tilted = false;
    });

},
  setup: function(my) {
    var setRed = function(){
        my.rgb_led.setRGB("FF0000")
    };
    var setBlue = function(){
        my.rgb_led.setRGB("0000FF")
    }
    var setGreen = function(){
        my.rgb_led.setRGB("00FF00")
    }
    var setOff = function(){
        my.rgb_led.setRGB("000000")
    }

    var calibrate = function(cb){
            setRed();
            after((0.01).seconds(), function() {
                getReading(5, function(avgRead){
                    whiteArray.red = avgRead;
                    console.log("Set white red to "+avgRead);
                    setBlue();
                    after((0.01).seconds(), function() {
                        getReading(5, function(avgRead){
                            whiteArray.blue = avgRead;
                            console.log("Set white blue to "+avgRead);
                            setGreen();
                            after((0.01).seconds(), function() {
                                getReading(5, function(avgRead){
                                    whiteArray.green = avgRead;
                                    console.log("Set white green to "+avgRead);
                                    setOff();
                                    after((5).seconds(), function() {
                                        setRed();
                                        after((0.01).seconds(), function() {
                                            getReading(5, function(avgRead){
                                                blackArray.red = avgRead;
                                                console.log("Set black red to "+avgRead);
                                                setBlue();
                                                after((0.01).seconds(), function() {
                                                    getReading(5, function(avgRead){
                                                        blackArray.blue = avgRead;
                                                        console.log("Set black blue to "+avgRead);
                                                        setGreen();
                                                        after((0.01).seconds(), function() {
                                                            getReading(5, function(avgRead){
                                                                blackArray.green = avgRead;
                                                                console.log("Set black green to "+avgRead);
                                                                after((0.01).seconds(), function() {
                                                                    cb();
                                                                });
                                                            });
                                                        });
                                                    });
                                                });
                                            });
                                        });
                                    });
                                });
                            });
                        });
                    });
                });
            });
        };

    var getReading = function(times, cb, tally){
        if (times ===0){
            var avgRead = (tally) / times;
            cb(avgRead);
        }
        if (!tally){
            tally=0;
        }

        var reading = my.ambient.analogRead();
        tally = reading + tally;
        after((0.01).seconds(), function() {
            getReading(times-1, cb, tally);
        });
    };

    every((1).seconds(), function() {
      console.log("Hello, human!");
    });

    after((5).seconds(), function() {
        calibrate(function(){
            every((1).seconds(), function() {
              console.log("Check color");
                    setRed();
                    after((0.01).seconds(), function() {
                        getReading(5, function(avgRead){
                            colorArray.red = avgRead;
                            console.log("Set colorArray red to "+avgRead);
                            var greydiff = whiteArray.red - blackArray.red;
                            colorArray.red = (colorArray.red - blackArray.red) / (greyDiff) * 255;//the reading returned minus the lowest value divided by the possible range multiplied by 255 is a value roughly between 0-255 representing the value
                            //for the current reflectivity(for the color it is exposed to) of what is being scanned
                            avgArray.red = (avgArray.red + colorArray.red) / 2;

                            setBlue();
                            after((0.01).seconds(), function() {
                                getReading(5, function(avgRead){
                                    colorArray.blue = avgRead;
                                    console.log("Set colorArray blue to "+avgRead);
                                    var greydiff = whiteArray.blue - blackArray.blue;
                                    colorArray.blue = (colorArray.blue - blackArray.blue) / (greyDiff) * 255;//the reading returned minus the lowest value divided by the possible range multiplied by 255 is a value roughly between 0-255 representing the value
                                    //for the current reflectivity(for the color it is exposed to) of what is being scanned
                                    avgArray.blue = (avgArray.blue + colorArray.blue) / 2;
                                    setGreen();
                                    after((0.01).seconds(), function() {
                                        getReading(5, function(avgRead){
                                            colorArray.green = avgRead;
                                            console.log("Set colorArray green to "+avgRead);
                                            var greydiff = whiteArray.green - blackArray.green;
                                            colorArray.green = (colorArray.green - blackArray.green) / (greyDiff) * 255;//the reading returned minus the lowest value divided by the possible range multiplied by 255 is a value roughly between 0-255 representing the value
                                            //for the current reflectivity(for the color it is exposed to) of what is being scanned
                                            avgArray.green = (avgArray.green + colorArray.green) / 2;
                                            after((0.01).seconds(), function() {
                                                setOff();
                                                if(avgArray.red > avgArray.green && avgArray.red > avgArray.blue) {
                                                    console.log("Detected Red");
                                                    output_sound("red");
                                                }
                                                else if(avgArray.green > avgArray.red && avgArray.green > avgArray.blue) {
                                                    console.log("Detected Green");
                                                    output_sound("green");

                                                }
                                                else {
                                                    console.log("Detected Blue");
                                                    output_sound("blue");
                                                }

                                            });
                                        });
                                    });
                                });
                            });
                        });
                    });
              });
            });
        });

    } //end setup

}).start();
<commit_msg>Add shell<commit_after>"use strict";

var Cylon = require('cylon')
var tilted = false;
var talking = false;
var leds = {red:2,blue:3,green:4};
var color = "";
var whiteArray = {red:0,blue:0,green:0};
var blackArray = {red:0,blue:0,green:0};
var colorArray = {red:0,blue:0,green:0};

Cylon.robot({
  connections: {
    edison: { adaptor: 'intel-iot' }
  },
  devices: {
    //outputs:
    laser: { driver: 'led', pin: 7 },
    rgb_led: { driver: 'rgb-led', redPin: 4, greenPin: 5, bluePin: 6 },

    //inputs:
    tilt: { driver: 'button', pin: 3 },
    button: { driver: 'button', pin: 2 },
    ambient: { driver: 'analog-sensor', pin: 3, lowerLimit: 100, upperLimit: 900 },
    color_detector: { driver: 'analog-sensor', pin: 0, lowerLimit: 0, upperLimit: 1024 },

  },
  work: function(my) {
    my.button.on('push', function() {
      my.laser.toggle();
    });
  },

  detect_color: function() {

  },

  output_sound: function(color) {
    console.log(color + " detected");
    if (!talking){
        if (color === "red"){
            exec('sh red.sh');
        }
        if (color === "green"){
            exec('sh green.sh');
        }
        if (color === "blue"){
            exec('sh blue.sh');
        }
    }
  },

  warn_tilt: function() {
    my.tilt.on('push', function() {
      console.log("Tilt Activated");
      tilted = true;
    });
    my.tilt.on('release', function() {
      console.log("Tilt Deactivated");
      tilted = false;
    });

},
  setup: function(my) {
    var setRed = function(){
        my.rgb_led.setRGB("FF0000")
    };
    var setBlue = function(){
        my.rgb_led.setRGB("0000FF")
    }
    var setGreen = function(){
        my.rgb_led.setRGB("00FF00")
    }
    var setOff = function(){
        my.rgb_led.setRGB("000000")
    }

    var calibrate = function(cb){
            setRed();
            after((0.01).seconds(), function() {
                getReading(5, function(avgRead){
                    whiteArray.red = avgRead;
                    console.log("Set white red to "+avgRead);
                    setBlue();
                    after((0.01).seconds(), function() {
                        getReading(5, function(avgRead){
                            whiteArray.blue = avgRead;
                            console.log("Set white blue to "+avgRead);
                            setGreen();
                            after((0.01).seconds(), function() {
                                getReading(5, function(avgRead){
                                    whiteArray.green = avgRead;
                                    console.log("Set white green to "+avgRead);
                                    setOff();
                                    after((5).seconds(), function() {
                                        setRed();
                                        after((0.01).seconds(), function() {
                                            getReading(5, function(avgRead){
                                                blackArray.red = avgRead;
                                                console.log("Set black red to "+avgRead);
                                                setBlue();
                                                after((0.01).seconds(), function() {
                                                    getReading(5, function(avgRead){
                                                        blackArray.blue = avgRead;
                                                        console.log("Set black blue to "+avgRead);
                                                        setGreen();
                                                        after((0.01).seconds(), function() {
                                                            getReading(5, function(avgRead){
                                                                blackArray.green = avgRead;
                                                                console.log("Set black green to "+avgRead);
                                                                after((0.01).seconds(), function() {
                                                                    cb();
                                                                });
                                                            });
                                                        });
                                                    });
                                                });
                                            });
                                        });
                                    });
                                });
                            });
                        });
                    });
                });
            });
        };

    var getReading = function(times, cb, tally){
        if (times ===0){
            var avgRead = (tally) / times;
            cb(avgRead);
        }
        if (!tally){
            tally=0;
        }

        var reading = my.ambient.analogRead();
        tally = reading + tally;
        after((0.01).seconds(), function() {
            getReading(times-1, cb, tally);
        });
    };

    every((1).seconds(), function() {
      console.log("Hello, human!");
    });

    after((5).seconds(), function() {
        calibrate(function(){
            every((1).seconds(), function() {
              console.log("Check color");
                    setRed();
                    after((0.01).seconds(), function() {
                        getReading(5, function(avgRead){
                            colorArray.red = avgRead;
                            console.log("Set colorArray red to "+avgRead);
                            var greydiff = whiteArray.red - blackArray.red;
                            colorArray.red = (colorArray.red - blackArray.red) / (greyDiff) * 255;//the reading returned minus the lowest value divided by the possible range multiplied by 255 is a value roughly between 0-255 representing the value
                            //for the current reflectivity(for the color it is exposed to) of what is being scanned
                            avgArray.red = (avgArray.red + colorArray.red) / 2;

                            setBlue();
                            after((0.01).seconds(), function() {
                                getReading(5, function(avgRead){
                                    colorArray.blue = avgRead;
                                    console.log("Set colorArray blue to "+avgRead);
                                    var greydiff = whiteArray.blue - blackArray.blue;
                                    colorArray.blue = (colorArray.blue - blackArray.blue) / (greyDiff) * 255;//the reading returned minus the lowest value divided by the possible range multiplied by 255 is a value roughly between 0-255 representing the value
                                    //for the current reflectivity(for the color it is exposed to) of what is being scanned
                                    avgArray.blue = (avgArray.blue + colorArray.blue) / 2;
                                    setGreen();
                                    after((0.01).seconds(), function() {
                                        getReading(5, function(avgRead){
                                            colorArray.green = avgRead;
                                            console.log("Set colorArray green to "+avgRead);
                                            var greydiff = whiteArray.green - blackArray.green;
                                            colorArray.green = (colorArray.green - blackArray.green) / (greyDiff) * 255;//the reading returned minus the lowest value divided by the possible range multiplied by 255 is a value roughly between 0-255 representing the value
                                            //for the current reflectivity(for the color it is exposed to) of what is being scanned
                                            avgArray.green = (avgArray.green + colorArray.green) / 2;
                                            after((0.01).seconds(), function() {
                                                setOff();
                                                if(avgArray.red > avgArray.green && avgArray.red > avgArray.blue) {
                                                    console.log("Detected Red");
                                                    output_sound("red");
                                                }
                                                else if(avgArray.green > avgArray.red && avgArray.green > avgArray.blue) {
                                                    console.log("Detected Green");
                                                    output_sound("green");

                                                }
                                                else {
                                                    console.log("Detected Blue");
                                                    output_sound("blue");
                                                }

                                            });
                                        });
                                    });
                                });
                            });
                        });
                    });
              });
            });
        });

    } //end setup

}).start();
<|endoftext|>


<commit_before>module.exports = {
  'no-console': 0, // http://eslint.org/docs/rules/no-console.html
  'no-unused-vars': [2, { // http://eslint.org/docs/rules/no-unused-vars.html
    args: 'none'
  }],
  'comma-dangle': [2, 'never'], // eslint.org/docs/rules/comma-dangle.html
  'default-case': 0, // http://eslint.org/docs/rules/default-case.html,
  'id-length': 0,
  'func-names': 0,
  'object-curly-spacing': [2, 'always'],
  'object-shorthand': [2, 'always'],
  'no-const-assign': 2,
  'arrow-parens': [2, 'as-needed'],
  'arrow-spacing': [2, { before: true, after: true }],
  'prefer-spread': 2,
  'constructor-super': 2,
  'space-before-function-paren': [2, 'never'],
  'no-param-reassign': [2, { props: false }]
};
<commit_msg>Disable no-confusing-arrow<commit_after>module.exports = {
  'no-console': 0, // http://eslint.org/docs/rules/no-console.html
  'no-unused-vars': [2, { // http://eslint.org/docs/rules/no-unused-vars.html
    args: 'none'
  }],
  'comma-dangle': [2, 'never'], // eslint.org/docs/rules/comma-dangle.html
  'default-case': 0, // http://eslint.org/docs/rules/default-case.html,
  'id-length': 0,
  'func-names': 0,
  'object-curly-spacing': [2, 'always'],
  'object-shorthand': [2, 'always'],
  'no-const-assign': 2,
  'arrow-parens': [2, 'as-needed'],
  'arrow-spacing': [2, { before: true, after: true }],
  'prefer-spread': 2,
  'constructor-super': 2,
  'space-before-function-paren': [2, 'never'],
  'no-param-reassign': [2, { props: false }],
  'no-confusing-arrow': 0
};
<|endoftext|>


<commit_before>module.exports.getTemplate = (currentMode) => {
  function isChecked(mode) { return currentMode == mode }
  function onClick(mode) { return () => { ipcRenderer.send('setNotificationMode', mode); } }

  return [
    {
      label: 'idobata-electron',
      submenu: [
        {
          label: 'About idobata-electron',
          selector: 'orderFrontStandardAboutPanel:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Notification',
          submenu: [
            {
              label: 'All messages',
              type: 'radio',
              checked: isChecked('all'),
              click: onClick('all')
            },
            {
              label: 'Mentions',
              type: 'radio',
              checked: isChecked('mention'),
              click: onClick('mention')
            },
            {
              label: 'Never',
              type: 'radio',
              checked: isChecked('never'),
              click: onClick('never')
            }
          ],
          accelerator: 'Command+,'
        },
        {
          type: 'separator'
        },
        {
          label: 'Services',
          submenu: []
        },
        {
          type: 'separator'
        },
        {
          label: 'Hide idobata-electron',
          accelerator: 'Command+H',
          selector: 'hide:'
        },
        {
          label: 'Hide Others',
          accelerator: 'Command+Shift+H',
          selector: 'hideOtherApplications:'
        },
        {
          label: 'Show All',
          selector: 'unhideAllApplications:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Quit',
          accelerator: 'Command+Q',
          selector: 'terminate:'
        },
      ]
    },
    {
      label: 'Edit',
      submenu: [
        {
          label: 'Undo',
          accelerator: 'Command+Z',
          selector: 'undo:'
        },
        {
          label: 'Redo',
          accelerator: 'Shift+Command+Z',
          selector: 'redo:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Cut',
          accelerator: 'Command+X',
          selector: 'cut:'
        },
        {
          label: 'Copy',
          accelerator: 'Command+C',
          selector: 'copy:'
        },
        {
          label: 'Paste',
          accelerator: 'Command+V',
          selector: 'paste:'
        },
        {
          label: 'Select All',
          accelerator: 'Command+A',
          selector: 'selectAll:'
        }
      ]
    },
    {
      label: 'View',
      submenu: [
        {
          label: 'Reload',
          accelerator: 'Command+R',
          click: function() { remote.getCurrentWindow().reload(); }
        },
        {
          label: 'Toggle DevTools',
          accelerator: 'Alt+Command+I',
          click: function() { remote.getCurrentWindow().toggleDevTools(); }
        },
      ]
    },
    {
      label: 'Window',
      submenu: [
        {
          label: 'Minimize',
          accelerator: 'Command+M',
          selector: 'performMiniaturize:'
        },
        {
          label: 'Close',
          accelerator: 'Command+W',
          selector: 'performClose:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Bring All to Front',
          selector: 'arrangeInFront:'
        }
      ]
    },
    {
      label: 'Help',
      submenu: []
    }
  ];
}
<commit_msg>Use `role` property<commit_after>module.exports.getTemplate = (currentMode) => {
  function isChecked(mode) { return currentMode == mode }
  function onClick(mode) { return () => { ipcRenderer.send('setNotificationMode', mode); } }

  return [
    {
      label: 'idobata-electron',
      submenu: [
        {
          role: 'about' // only macOS
        },
        {
          type: 'separator'
        },
        {
          label: 'Notification',
          submenu: [
            {
              label: 'All messages',
              type: 'radio',
              checked: isChecked('all'),
              click: onClick('all')
            },
            {
              label: 'Mentions',
              type: 'radio',
              checked: isChecked('mention'),
              click: onClick('mention')
            },
            {
              label: 'Never',
              type: 'radio',
              checked: isChecked('never'),
              click: onClick('never')
            }
          ]
        },
        {
          type: 'separator'
        },
        {
          role: 'services', // only macOS
          submenu: []
        },
        {
          type: 'separator'
        },
        {
          role: 'hide' // only macOS
        },
        {
          role: 'hideothers' // only macOS
        },
        {
          role: 'unhide' // only macOS
        },
        {
          type: 'separator'
        },
        {
          role: 'quit'
        },
      ]
    },
    {
      label: 'Edit',
      submenu: [
        {
          role: 'undo'
        },
        {
          role: 'redo'
        },
        {
          type: 'separator'
        },
        {
          role: 'cut'
        },
        {
          role: 'copy'
        },
        {
          role: 'paste'
        },
        {
          role: 'pasteandmatchstyle'
        },
        {
          role: 'delete'
        },
        {
          role: 'selectall'
        }
      ]
    },
    {
      label: 'View',
      submenu: [
        {
          label: 'Reload',
          accelerator: 'Command+R',
          click() { remote.getCurrentWindow().reload(); }
        },
        {
          label: 'Toggle DevTools',
          accelerator: 'Alt+Command+I',
          click() { remote.getCurrentWindow().toggleDevTools(); }
        },
        {
          type: 'separator'
        },
        {
          role: 'togglefullscreen'
        }
      ]
    },
    {
      role: 'window', // only macOS
      submenu: [
        {
          role: 'minimize'
        },
        {
          role: 'zoom' // only macOS
        },
        {
          role: 'close'
        },
        {
          type: 'separator'
        },
        {
          role: 'front' // only macOS
        }
      ]
    },
    {
      role: 'help', // only macOS
      submenu: [
        {
          label: 'Learn More',
          click() {
            require('electron').shell.openExternal('https://github.com/hrysd/idobata-electron');
          }
        }
      ]
    }
  ];
}
<|endoftext|>


<commit_before>/**
 * Filters the passed value and returns `undefined` if either:
 * – An [array] or an {object} is empty.
 * – `null` has been passed.
 * – `NaN` has been passed.
 *
 * @flow
 * @param {*} a – The passed data.
 * @return {*|undefined} – Either `undefined` or the passed data.
 */

function filterEmpty(a: mixed): mixed {
  if (typeof a === "object") {
    // typeof null => "object"
    if (a === null) return undefined;

    return Object.keys(a).length > 0 ? a : undefined;
  }

  // isNaN("a") => true
  // Number.isNaN("a") => false
  if (Number.isNaN(a)) return undefined;

  return a;
}

export { filterEmpty };<commit_msg>Optimize filterEmpty<commit_after>/**
 * Filters the passed value and returns `undefined` if either:
 * – An [array] or an {object} is empty.
 * – `null` has been passed.
 * – `NaN` has been passed.
 *
 * @flow
 * @param {*} a – The passed data.
 * @return {*|undefined} – Either `undefined` or the passed data.
 */

function filterEmpty(a: mixed): mixed {
  if (typeof a === "object") {
    // typeof null => "object"
    if (a === null) return undefined;

    // Get the first key, reassign it and break the loop
    // If there are no keys, it doesn't do anything
    let key = undefined;
    for (key in a) break;

    return key !== undefined ? a : undefined;
  }

  if (Number.isNaN(a)) return undefined;

  return a;
}

export { filterEmpty };<|endoftext|>


<commit_before>/**
 *      ioBroker.ctrl (ioBroker Controller)
 *
 *      Controls Adapter-Processes
 *
 *
 */

var version = '0.0.13';
var title = 'iobroker.ctrl';
process.title = title;

var schedule =      require('node-schedule');
var os =            require('os');
var fs =            require('fs');
var cp =            require('child_process');
var ObjectsCouch =  require(__dirname + '/lib/couch.js');
var StatesRedis =   require(__dirname + '/lib/redis.js');
var logger =        require(__dirname + '/lib/logger.js');

var config;
if (!fs.existsSync(__dirname + '/conf/iobroker.json')) {
    logger.error('ctrl conf/iobroker.json missing - call node iobroker.js setup');
    process.exit(1);
} else {
    config = JSON.parse(fs.readFileSync(__dirname + '/conf/iobroker.json'));
}

// Find first non-loopback ip
var ifaces = os.networkInterfaces();
var ipArr = [];
for (var dev in ifaces) {
    /*jshint loopfunc:true */
    ifaces[dev].forEach(function (details) {
        if (!details.internal) ipArr.push(details.address);
    });
}
var firstIp = ipArr[0];

logger.info('ioBroker.ctrl version ' + version + ' starting');
logger.info('ctrl ip: ' + ipArr.join(' '));

var procs = {};

var states = new StatesRedis({

    redis: {
        host: config.redis.host,
        port: config.redis.port,
        options: config.redis.options
    },
    logger: logger,
    change: function (id, state) {
        //console.log('state ' + id + ' = ' + state);
    }
});
//states.subscribe('*');

var objects = new ObjectsCouch({
    host: config.couch.host,
    port: config.couch.port,
    user: config.couch.user,
    pass: config.couch.pass,
    logger: logger,
    connected: function () {
        logger.info('ctrl couchdb connected');
        setMeta();
        getInstances();
        startAliveInterval();
    },
    change: function (id, obj) {
        if (!id.match(/^system\.adapter\.[a-zA-Z0-9-_]+\.[0-9]+$/)) return;
        logger.info('ctrl object change ' + id);
        if (procs[id]) {
            // known adapter
            procs[id].config = obj;
            if (procs[id].process) {
                stopInstance(id, function () {
                    if (ipArr.indexOf(obj.common.host) !== -1) {
                        if (obj.common.enabled) startInstance(id);
                    } else {
                        delete procs[id];
                    }
                });
            } else {
                if (ipArr.indexOf(obj.common.host) !== -1) {
                    if (obj.common.enabled) startInstance(id);
                } else {
                    delete procs[id];
                }
            }

        } else {
            // unknown adapter
            if (ipArr.indexOf(obj.common.host) !== -1) {
                procs[id] = {config: obj};
                if (obj.common.enabled) startInstance(id);
            }
        }
    }

});

objects.subscribe('system.adapter.*');

function startAliveInterval() {
    reportStatus();
    setInterval(function () {
        reportStatus();
    }, 15000);
}

function reportStatus() {
    var id = 'system.host.' + firstIp;
    states.setState(id + '.alive', {val: true, ack: true, expire: 30});
    states.setState(id + '.load', {val: os.loadavg()[0].toFixed(2), ack: true});
    states.setState(id + '.memfree', {val: (100 * os.freemem() / os.totalmem()).toFixed(0), ack: true});

}
function setMeta() {
    var hostname = os.hostname();
    var id = 'system.host.' + hostname;
    var obj = {
        _id: id,
        type: 'host',
        common: {
            name:       id,
            process:    title,
            version:    version,
            platform:   'javascript/Node.js',
            cmd:        process.argv[0] + ' ' + process.execArgv.join(' ') + ' ' + process.argv.slice(1).join(' '),
            hostname:   hostname,
            address:    ipArr
        },
        native: {
            process: {
                title:      process.title,
                pid:        process.pid,
                versions:   process.versions,
                env:        process.env
            },
            os: {
                hostname:   hostname,
                type:       os.type(),
                platform:   os.platform(),
                arch:       os.arch(),
                release:    os.release(),
                uptime:     os.uptime(),
                endianness: os.endianness(),
                tmpdir:     os.tmpdir()
            },
            hardware: {
                cpus:       os.cpus(),
                totalmem:   os.totalmem(),
                networkInterfaces: os.networkInterfaces()
            }
        }
    };
    objects.setObject(id, obj);
    var idMem = id + ".mem";
    obj = {
        _id: idMem,
        type: 'state',
        parent: id,
        common: {
            type: 'number',
            name: 'Memory usage',
            unit: '%',
            min: 0,
            max: 100
        },
        native: {}
    };
    objects.setObject(idMem, obj);
    var idLoad = id + ".load";
    obj = {
        _id: idLoad,
        type: 'state',
        parent: id,
        common: {
            unit: '',
            type: 'number',
            name: 'Load Average 1min'
        },
        native: {}
    };
    objects.setObject(idLoad, obj);
    var idAlive = id + ".alive";
    obj = {
        _id: idAlive,
        type: 'state',
        parent: id,
        common: {
            name: 'Host alive',
            type: 'boolean'
        },
        native: {}
    };
    objects.setObject(idAlive, obj);
}

function getInstances() {

    objects.getObjectView('system', 'instance', {}, function (err, doc) {
        if (err && err.status_code === 404) {
            logger.error('ctrl _design/system missing - call node iobroker.js setup');
            process.exit(1);
            return;
        } else if (doc.rows.length === 0) {
            logger.info('ctrl no instances found');
        } else {
            logger.info('ctrl ' + doc.rows.length + ' instance' + (doc.rows.length === 1 ? '' : 's') + ' found');
            for (var i = 0; i < doc.rows.length; i++) {

                var instance = doc.rows[i].value;

                if (ipArr.indexOf(instance.common.host) !== -1) {
                    procs[instance._id] = {config: instance};
                }
            }
            if (procs.length > 0) {
                logger.info('ctrl starting ' + procs.length + ' instances');
            }

        }

        initInstances();
    });
}

function initInstances() {
    var c = 0;
    for (var id in procs) {
        if (procs[id].config.common.enabled) {

            setTimeout(function (_id) {
                startInstance(_id);
            }, 2000 * c++, id);

            c += 1;
        }
    }
}

function startInstance(id) {
    var instance = procs[id].config;
    var name = id.split('.')[2];

    switch (instance.common.mode) {
        case 'daemon':
            if (!procs[id].process) {
                allInstancesStopped = false;
                var args = [instance._id.split('.').pop(), instance.common.loglevel || 'info'];
                procs[id].process = cp.fork(__dirname + '/adapter/' + name + '/' + name + '.js', args);
                procs[id].process.on('exit', function (code, signal) {
                    states.setState(id + '.alive', {val: false, ack: true});
                    states.setState(id + '.connected', {val: false, ack: true});
                    if (signal) {
                        logger.warn('ctrl instance ' + id + ' terminated due to ' + signal);
                    } else if (code === null) {
                        logger.error('ctrl instance ' + id + ' terminated abnormally');
                    } else {
                        if (procs[id].stopping || isStopping) {
                            logger.info('ctrl instance ' + id + ' terminated with code ' + code);
                            delete procs[id].stopping;
                            delete procs[id].process;
                            if (isStopping) {
                                for (var i in procs) {
                                    if (procs[i].process) {
                                        return;
                                    }
                                }
                                allInstancesStopped = true;
                            }
                            return;
                        } else {
                            logger.error('ctrl instance ' + id + ' terminated with code ' + code);
                        }
                    }
                    delete procs[id].process;
                    startInstance(id);
                });
                logger.info('ctrl instance ' + instance._id + ' started with pid ' + procs[id].process.pid);
            } else {
                logger.warn('ctrl instance ' + instance._id + ' already running with pid ' + procs[id].process.pid);
            }
            break;
        case 'schedule':
            if (!instance.common.schedule) {
                logger.error(instance._id + ' schedule attribute missing');
                break;
            }
            if (procs[id].schedule) {
                procs[id].schedule.cancel();
                logger.info('ctrl instance canceled schedule ' + instance._id);
            }
            procs[id].schedule = schedule.scheduleJob(instance.common.schedule, function () {

                var args = [instance._id.split('.').pop(), instance.common.loglevel || 'info'];
                procs[id].process = cp.fork(__dirname + '/adapter/' + name + '/' + name + '.js', args);
                logger.info('ctrl instance ' + instance._id + ' started with pid ' + procs[id].process.pid);

                procs[id].process.on('exit', function (code, signal) {
                    states.setState(id + '.alive', {val: false, ack: true});
                    if (signal) {
                        logger.warn('ctrl instance ' + id + ' terminated due to ' + signal);
                    } else if (code === null) {
                        logger.error('ctrl instance ' + id + ' terminated abnormally');
                    } else {
                        if (code === 0 || code === '0') {
                            logger.info('ctrl instance ' + id + ' terminated with code ' + code);
                            return;
                        } else {
                            logger.error('ctrl instance ' + id + ' terminated with code ' + code);
                        }
                    }
                    delete procs[id].process;
                });

            });
            logger.info('ctrl instance scheduled ' + instance._id + ' ' + instance.common.schedule);

            break;
        case 'subscribe':
            // TODO
            break;
        default:
            logger.error(instance._id + ' invalid mode');

    }

}

function stopInstance(id, callback) {
    var instance = procs[id].config;
    switch (instance.common.mode) {
        case 'daemon':
            if (!procs[id].process) {
                logger.warn('ctrl instance ' + instance._id + ' not running');
                if (typeof callback === 'function') callback();
            } else {
                logger.info('ctrl instance ' + instance._id + ' stopping with pid ' + procs[id].process.pid);
                procs[id].stopping = true;
                procs[id].process.kill();
                delete(procs[id].process);
                if (typeof callback === 'function') callback();
            }
            break;
        case 'schedule':
            if (!procs[id].schedule) {
                logger.warn('ctrl instance ' + instance._id + ' not scheduled');
            } else {
                procs[id].schedule.cancel();
                delete procs[id].schedule;
                logger.info('ctrl instance canceled schedule ' + instance._id);
            }
            if (typeof callback === 'function') callback();
            break;
        default:
    }
}

function restartInstance(id) {
    stopInstance(id, function () {
        startInstance(id);
    });
}

var isStopping = false;
var stopArr = [];
var allInstancesStopped = false;

function stop() {
    if (isStopping) {

        states.setState('system.host.' + firstIp + '.alive', {val: false, ack: true}, function () {
            logger.info('ctrl force terminating');
            process.exit(1);
            return;
        });

    }

    isStopping = true;

    function waitForInstances() {
        if (!allInstancesStopped) {
            setTimeout(waitForInstances, 100);
        } else {
            states.setState('system.host.' + firstIp + '.alive', {val: false, ack: true}, function () {
                logger.info('ctrl terminated');
                process.exit(0);
            });

        }
    }

    waitForInstances();

    // force after 5s
    setTimeout(function () {
        states.setState('system.host.' + firstIp + '.alive', {val: false, ack: true}, function () {
            logger.info('ctrl force terminated after 5s');
            process.exit(1);
        });
    }, 5000);
}

process.on('SIGINT', stop);
process.on('SIGTERM', stop);<commit_msg>fixed system.host id<commit_after>/**
 *      ioBroker.ctrl (ioBroker Controller)
 *
 *      Controls Adapter-Processes
 *
 *
 */

var version = '0.0.13';
var title = 'iobroker.ctrl';
process.title = title;

var schedule =      require('node-schedule');
var os =            require('os');
var fs =            require('fs');
var cp =            require('child_process');
var ObjectsCouch =  require(__dirname + '/lib/couch.js');
var StatesRedis =   require(__dirname + '/lib/redis.js');
var logger =        require(__dirname + '/lib/logger.js');

var config;
if (!fs.existsSync(__dirname + '/conf/iobroker.json')) {
    logger.error('ctrl conf/iobroker.json missing - call node iobroker.js setup');
    process.exit(1);
} else {
    config = JSON.parse(fs.readFileSync(__dirname + '/conf/iobroker.json'));
}

// Find first non-loopback ip
var ifaces = os.networkInterfaces();
var ipArr = [];
for (var dev in ifaces) {
    /*jshint loopfunc:true */
    ifaces[dev].forEach(function (details) {
        if (!details.internal) ipArr.push(details.address);
    });
}
var firstIp = ipArr[0];

logger.info('ioBroker.ctrl version ' + version + ' starting');
logger.info('ctrl ip: ' + ipArr.join(' '));

var procs = {};

var states = new StatesRedis({

    redis: {
        host: config.redis.host,
        port: config.redis.port,
        options: config.redis.options
    },
    logger: logger,
    change: function (id, state) {
        //console.log('state ' + id + ' = ' + state);
    }
});
//states.subscribe('*');

var objects = new ObjectsCouch({
    host: config.couch.host,
    port: config.couch.port,
    user: config.couch.user,
    pass: config.couch.pass,
    logger: logger,
    connected: function () {
        logger.info('ctrl couchdb connected');
        setMeta();
        getInstances();
        startAliveInterval();
    },
    change: function (id, obj) {
        if (!id.match(/^system\.adapter\.[a-zA-Z0-9-_]+\.[0-9]+$/)) return;
        logger.info('ctrl object change ' + id);
        if (procs[id]) {
            // known adapter
            procs[id].config = obj;
            if (procs[id].process) {
                stopInstance(id, function () {
                    if (ipArr.indexOf(obj.common.host) !== -1) {
                        if (obj.common.enabled) startInstance(id);
                    } else {
                        delete procs[id];
                    }
                });
            } else {
                if (ipArr.indexOf(obj.common.host) !== -1) {
                    if (obj.common.enabled) startInstance(id);
                } else {
                    delete procs[id];
                }
            }

        } else {
            // unknown adapter
            if (ipArr.indexOf(obj.common.host) !== -1) {
                procs[id] = {config: obj};
                if (obj.common.enabled) startInstance(id);
            }
        }
    }

});

objects.subscribe('system.adapter.*');

function startAliveInterval() {
    reportStatus();
    setInterval(function () {
        reportStatus();
    }, 15000);
}

function reportStatus() {
    var id = 'system.host.' + hostname;
    states.setState(id + '.alive', {val: true, ack: true, expire: 30});
    states.setState(id + '.load', {val: os.loadavg()[0].toFixed(2), ack: true});
    states.setState(id + '.memfree', {val: (100 * os.freemem() / os.totalmem()).toFixed(0), ack: true});

}
function setMeta() {
    var hostname = os.hostname();
    var id = 'system.host.' + hostname;
    var obj = {
        _id: id,
        type: 'host',
        common: {
            name:       id,
            process:    title,
            version:    version,
            platform:   'javascript/Node.js',
            cmd:        process.argv[0] + ' ' + process.execArgv.join(' ') + ' ' + process.argv.slice(1).join(' '),
            hostname:   hostname,
            address:    ipArr
        },
        native: {
            process: {
                title:      process.title,
                pid:        process.pid,
                versions:   process.versions,
                env:        process.env
            },
            os: {
                hostname:   hostname,
                type:       os.type(),
                platform:   os.platform(),
                arch:       os.arch(),
                release:    os.release(),
                uptime:     os.uptime(),
                endianness: os.endianness(),
                tmpdir:     os.tmpdir()
            },
            hardware: {
                cpus:       os.cpus(),
                totalmem:   os.totalmem(),
                networkInterfaces: os.networkInterfaces()
            }
        }
    };
    objects.setObject(id, obj);
    var idMem = id + ".mem";
    obj = {
        _id: idMem,
        type: 'state',
        parent: id,
        common: {
            type: 'number',
            name: 'Memory usage',
            unit: '%',
            min: 0,
            max: 100
        },
        native: {}
    };
    objects.setObject(idMem, obj);
    var idLoad = id + ".load";
    obj = {
        _id: idLoad,
        type: 'state',
        parent: id,
        common: {
            unit: '',
            type: 'number',
            name: 'Load Average 1min'
        },
        native: {}
    };
    objects.setObject(idLoad, obj);
    var idAlive = id + ".alive";
    obj = {
        _id: idAlive,
        type: 'state',
        parent: id,
        common: {
            name: 'Host alive',
            type: 'boolean'
        },
        native: {}
    };
    objects.setObject(idAlive, obj);
}

function getInstances() {

    objects.getObjectView('system', 'instance', {}, function (err, doc) {
        if (err && err.status_code === 404) {
            logger.error('ctrl _design/system missing - call node iobroker.js setup');
            process.exit(1);
            return;
        } else if (doc.rows.length === 0) {
            logger.info('ctrl no instances found');
        } else {
            logger.info('ctrl ' + doc.rows.length + ' instance' + (doc.rows.length === 1 ? '' : 's') + ' found');
            for (var i = 0; i < doc.rows.length; i++) {

                var instance = doc.rows[i].value;

                if (ipArr.indexOf(instance.common.host) !== -1) {
                    procs[instance._id] = {config: instance};
                }
            }
            if (procs.length > 0) {
                logger.info('ctrl starting ' + procs.length + ' instances');
            }

        }

        initInstances();
    });
}

function initInstances() {
    var c = 0;
    for (var id in procs) {
        if (procs[id].config.common.enabled) {

            setTimeout(function (_id) {
                startInstance(_id);
            }, 2000 * c++, id);

            c += 1;
        }
    }
}

function startInstance(id) {
    var instance = procs[id].config;
    var name = id.split('.')[2];

    switch (instance.common.mode) {
        case 'daemon':
            if (!procs[id].process) {
                allInstancesStopped = false;
                var args = [instance._id.split('.').pop(), instance.common.loglevel || 'info'];
                procs[id].process = cp.fork(__dirname + '/adapter/' + name + '/' + name + '.js', args);
                procs[id].process.on('exit', function (code, signal) {
                    states.setState(id + '.alive', {val: false, ack: true});
                    states.setState(id + '.connected', {val: false, ack: true});
                    if (signal) {
                        logger.warn('ctrl instance ' + id + ' terminated due to ' + signal);
                    } else if (code === null) {
                        logger.error('ctrl instance ' + id + ' terminated abnormally');
                    } else {
                        if (procs[id].stopping || isStopping) {
                            logger.info('ctrl instance ' + id + ' terminated with code ' + code);
                            delete procs[id].stopping;
                            delete procs[id].process;
                            if (isStopping) {
                                for (var i in procs) {
                                    if (procs[i].process) {
                                        return;
                                    }
                                }
                                allInstancesStopped = true;
                            }
                            return;
                        } else {
                            logger.error('ctrl instance ' + id + ' terminated with code ' + code);
                        }
                    }
                    delete procs[id].process;
                    startInstance(id);
                });
                logger.info('ctrl instance ' + instance._id + ' started with pid ' + procs[id].process.pid);
            } else {
                logger.warn('ctrl instance ' + instance._id + ' already running with pid ' + procs[id].process.pid);
            }
            break;
        case 'schedule':
            if (!instance.common.schedule) {
                logger.error(instance._id + ' schedule attribute missing');
                break;
            }
            if (procs[id].schedule) {
                procs[id].schedule.cancel();
                logger.info('ctrl instance canceled schedule ' + instance._id);
            }
            procs[id].schedule = schedule.scheduleJob(instance.common.schedule, function () {

                var args = [instance._id.split('.').pop(), instance.common.loglevel || 'info'];
                procs[id].process = cp.fork(__dirname + '/adapter/' + name + '/' + name + '.js', args);
                logger.info('ctrl instance ' + instance._id + ' started with pid ' + procs[id].process.pid);

                procs[id].process.on('exit', function (code, signal) {
                    states.setState(id + '.alive', {val: false, ack: true});
                    if (signal) {
                        logger.warn('ctrl instance ' + id + ' terminated due to ' + signal);
                    } else if (code === null) {
                        logger.error('ctrl instance ' + id + ' terminated abnormally');
                    } else {
                        if (code === 0 || code === '0') {
                            logger.info('ctrl instance ' + id + ' terminated with code ' + code);
                            return;
                        } else {
                            logger.error('ctrl instance ' + id + ' terminated with code ' + code);
                        }
                    }
                    delete procs[id].process;
                });

            });
            logger.info('ctrl instance scheduled ' + instance._id + ' ' + instance.common.schedule);

            break;
        case 'subscribe':
            // TODO
            break;
        default:
            logger.error(instance._id + ' invalid mode');

    }

}

function stopInstance(id, callback) {
    var instance = procs[id].config;
    switch (instance.common.mode) {
        case 'daemon':
            if (!procs[id].process) {
                logger.warn('ctrl instance ' + instance._id + ' not running');
                if (typeof callback === 'function') callback();
            } else {
                logger.info('ctrl instance ' + instance._id + ' stopping with pid ' + procs[id].process.pid);
                procs[id].stopping = true;
                procs[id].process.kill();
                delete(procs[id].process);
                if (typeof callback === 'function') callback();
            }
            break;
        case 'schedule':
            if (!procs[id].schedule) {
                logger.warn('ctrl instance ' + instance._id + ' not scheduled');
            } else {
                procs[id].schedule.cancel();
                delete procs[id].schedule;
                logger.info('ctrl instance canceled schedule ' + instance._id);
            }
            if (typeof callback === 'function') callback();
            break;
        default:
    }
}

function restartInstance(id) {
    stopInstance(id, function () {
        startInstance(id);
    });
}

var isStopping = false;
var stopArr = [];
var allInstancesStopped = false;

function stop() {
    if (isStopping) {

        states.setState('system.host.' + firstIp + '.alive', {val: false, ack: true}, function () {
            logger.info('ctrl force terminating');
            process.exit(1);
            return;
        });

    }

    isStopping = true;

    function waitForInstances() {
        if (!allInstancesStopped) {
            setTimeout(waitForInstances, 100);
        } else {
            states.setState('system.host.' + firstIp + '.alive', {val: false, ack: true}, function () {
                logger.info('ctrl terminated');
                process.exit(0);
            });

        }
    }

    waitForInstances();

    // force after 5s
    setTimeout(function () {
        states.setState('system.host.' + firstIp + '.alive', {val: false, ack: true}, function () {
            logger.info('ctrl force terminated after 5s');
            process.exit(1);
        });
    }, 5000);
}

process.on('SIGINT', stop);
process.on('SIGTERM', stop);<|endoftext|>


<commit_before>function findValue (parent, dotNot) {

    if (!dotNot) return undefined;

    var splits = dotNot.split(".");
    var value;

    for (var i = 0; i < splits.length; i++) {
        value = parent[splits[i]];
        if (value === undefined) return undefined;
        if (typeof value === "object") parent = value;
    }

    return value;
}

function findFunction (parent, dotNot) {

    var func = findValue(parent, dotNot);

    if (typeof func !== "function") {
        return undefined;
    }

    return func;
}

var Bind = module.exports = function (bind, dataContext) {

    var self = this;

    var context = $(this.dom);
    if (bind.context) {
        context = $(bind.context, context);
    }
    var target = context;
    if (bind.target) {
        target = $(bind.target, context);
    }

    dataContext = dataContext || {};

    function computeStringOrSourceDataValue(dataType, dataContext) {
        var value = "";
        if (typeof dataType === "string") {
            value = dataType;
        } else {
            value = computeDataValue(dataType, dataContext);
        }
        return value;
    }

    function computeDataValue(dataType, dataContext) {

        var dataSource = undefined;

        // if the source is $ the value the data context will be considered the value
        if (dataType.source === "$") {
            dataSource = dataContext.toString();
        } else {
            dataSource = findValue(dataContext, dataType.source);
        }

        if (dataSource === undefined || dataSource === null) {
            if (typeof dataType["default"] === "string") {
                value = dataType["default"];
            } else {
                value = "?" + dataType.source + "?";
            }
        } else if (typeof dataSource === "object") {
            var locale = M.getLocale();
            value = dataSource[locale] || "Missing value for '" + locale + "' language";
        } else {
            value = dataSource;
        }

        var filterFunction = findFunction(self, dataType.filter) || findFunction(window, dataType.filter);
        if (typeof filterFunction === "function") {
            value = filterFunction(self, dataContext, dataType.source, value);
        }

        return value;
    };

    var domManipulators = {

        // add/modify attribute
        /* Examples:
         *  "binds": [
         *      {
         *          "attr": [
         *              {
         *                  "name": "the_attribute name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "the_attribute name",
         *                  "value": {
         *                      "source": "the_field_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        attr: function(target, context, attrTypes, dataContext) {
            if (!attrTypes || !attrTypes.length) {
                return;
            }
            for (var i = 0; i < attrTypes.length; ++i) {
                var value = computeStringOrSourceDataValue(attrTypes[i].value, dataContext);
                target.attr(attrTypes[i].name, value);
            }
        },

        // add/modify properties
        /* Examples:
         *  "binds": [
         *      {
         *          "prop": [
         *              {
         *                  "name": "prop name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "prop name",
         *                  "value": {
         *                      "source": "the_prop_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        prop: function(target, context, propTypes, dataContext) {
            if (!propTypes || !propTypes.length) {
                return;
            }
            for (var i = 0; i < propTypes.length; ++i) {
                var value = computeStringOrSourceDataValue(propTypes[i].value, dataContext);
                target.prop(propTypes[i].name, value);
            }
        },

        // add class
        /* Examples:
         *  "binds": [
         *      {
         *          "addClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        addClass: function(target, context, classes, dataContext) {
            if (!classes || !classes.length) {
                return;
            }
            for (var i = 0; i < classes.length; ++i) {
                target.addClass(classes[i]);
            }
        },

        // remove class
        /* Examples:
         *  "binds": [
         *      {
         *          "removeClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        removeClass: function(target, context, classes, dataContext) {
            if (!classes || !classes.length) {
                return;
            }
            for (var i = 0; i < classes.length; ++i) {
                target.removeClass(classes[i]);
            }
        },

        // innerHTML
        /* Examples:
         *  "binds": [
         *      {
         *          "html": "a_string_value"
         *      },
         *
         *      {
         *          "html": {
         *              "source": "the_field_name_from_a_source"
         *          }
         *      }
         *  ]
         */
        html: function(target, context, dataType, dataContext) {
            var value = computeStringOrSourceDataValue(dataType, dataContext);
            if (value === undefined || value === null) {
                value = '';
            } else {
                value = value.toString();
            }
            target.html(value);
        },

        // repeat the target for each item in array source
        /*
         *   "binds": [
         *       {
         *           "repeat": {
         *               "source": "the_array_name_from_a_source",
         *               "preFilter": "handler_name",
         *               "postFilter": "handler_name",
         *               "binds": [
         *                   ...
         *               ]
         *           }
         *       }
         *   ]
         */
        repeat: function(target, context, bindTemplate, dataContext) {

            if (!target.length) {
                console.warn("Empty bind 'repeat' target");
                return;
            }

            if (typeof dataContext !== "object" || !dataContext) {
                console.warn("A bind 'repeat' can only be used with an object data context");
                return;
            }

            var sourceArray = dataContext[bindTemplate.source] || [];

            if (Object.prototype.toString.call(sourceArray) !== "[object Array]" ) {
                console.warn("A bind 'repeat' did not find an array in the source field of the data context");
                return;
            }

            var template = target.clone();
            var container = target.parent();

            // run the pre-filtering handler
            var filterFunction = findFunction(self, bindTemplate.preFilter) || findFunction(window, bindTemplate.prefilter);
            if (filterFunction) {
                sourceArray = filterFunction(self, dataContext, bindTemplate.source, sourceArray, container);
            }

            // run the binds for each item
            for (var i = 0; i < sourceArray.length; ++i) {

                var newDom = template.clone();

                if (!bindTemplate.binds || !bindTemplate.binds.length) {
                    continue;
                }

                for (var j = 0; j < bindTemplate.binds.length; ++j) {
                    var bind = bindTemplate.binds[j];
                    bind.context = newDom;
                    Bind.call(self, bind, sourceArray[i]);
                }

                container.append(newDom);
            }

            // run the post-filtering handler
            filterFunction = findFunction(self, bindTemplate.postFilter) || findFunction(window, bindTemplate.postFilter);
            if (filterFunction) {
                sourceArray = filterFunction(self, dataContext, bindTemplate.source, sourceArray, container);
            }

            target.remove();
        }
    }

    for (var key in bind) {
        if (!bind.hasOwnProperty(key)) continue;

        if (domManipulators[key]) {
            domManipulators[key](target, context, bind[key], dataContext);
        }
    }

    if (bind.on) {
        for (var i = 0; i < bind.on.length; ++i) {
            var curOn = bind.on[i];
            if (curOn.handler || curOn.emit) {
                (function (curOn) {
                    var t = target;
                    var s = null;

                    // of the delegated option is set, this bind will work for future DOM insertions
                    if (curOn.delegated) {
                        t = context;
                        s = target.selector;
                    }

                    t.on(curOn.name, s,function(event) {
                        event.stopPropagation();

                        var name = curOn.handler;
                        var args = [];

                        if (typeof name === "object") {
                            args = name.args || [];
                            name = name.name;
                        }

                        // if the noEvent option is set, the DOM event will not be passed to the called handler or emitted event
                        if (!curOn.noEvent) {
                            args.push(event);
                        }
                        args.push(dataContext);

                        if (typeof name === "function") {
                            name.apply(self, args);
                            return false;
                        }

                        var handler = findFunction(self, name) || findFunction(window, name);

                        if (typeof handler === "function") {
                            handler.apply(self, args);
                        }

                        if (curOn.emit) {
                            self.emit(curOn.emit, dataContext);
                        }

                        return false;
                    });
                })(curOn);
            }
        }
    }

    for (var key in bind.listen) {
        if (!bind.listen.hasOwnProperty(key)) continue;

        var curListen = bind.listen[key];
        self.on(curListen.name, curListen.miid, self[curListen.handler]);
    }
};
<commit_msg>Removed unwanted spaces<commit_after>function findValue (parent, dotNot) {

    if (!dotNot) return undefined;

    var splits = dotNot.split(".");
    var value;

    for (var i = 0; i < splits.length; i++) {
        value = parent[splits[i]];
        if (value === undefined) return undefined;
        if (typeof value === "object") parent = value;
    }

    return value;
}

function findFunction (parent, dotNot) {

    var func = findValue(parent, dotNot);

    if (typeof func !== "function") {
        return undefined;
    }

    return func;
}

var Bind = module.exports = function (bind, dataContext) {

    var self = this;

    var context = $(this.dom);
    if (bind.context) {
        context = $(bind.context, context);
    }
    var target = context;
    if (bind.target) {
        target = $(bind.target, context);
    }

    dataContext = dataContext || {};

    function computeStringOrSourceDataValue(dataType, dataContext) {
        var value = "";
        if (typeof dataType === "string") {
            value = dataType;
        } else {
            value = computeDataValue(dataType, dataContext);
        }
        return value;
    }

    function computeDataValue(dataType, dataContext) {

        var dataSource = undefined;

        // if the source is $ the value the data context will be considered the value
        if (dataType.source === "$") {
            dataSource = dataContext.toString();
        } else {
            dataSource = findValue(dataContext, dataType.source);
        }

        if (dataSource === undefined || dataSource === null) {
            if (typeof dataType["default"] === "string") {
                value = dataType["default"];
            } else {
                value = "?" + dataType.source + "?";
            }
        } else if (typeof dataSource === "object") {
            var locale = M.getLocale();
            value = dataSource[locale] || "Missing value for '" + locale + "' language";
        } else {
            value = dataSource;
        }

        var filterFunction = findFunction(self, dataType.filter) || findFunction(window, dataType.filter);
        if (typeof filterFunction === "function") {
            value = filterFunction(self, dataContext, dataType.source, value);
        }

        return value;
    };

    var domManipulators = {

        // add/modify attribute
        /* Examples:
         *  "binds": [
         *      {
         *          "attr": [
         *              {
         *                  "name": "the_attribute name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "the_attribute name",
         *                  "value": {
         *                      "source": "the_field_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        attr: function(target, context, attrTypes, dataContext) {
            if (!attrTypes || !attrTypes.length) {
                return;
            }
            for (var i = 0; i < attrTypes.length; ++i) {
                var value = computeStringOrSourceDataValue(attrTypes[i].value, dataContext);
                target.attr(attrTypes[i].name, value);
            }
        },

        // add/modify properties
        /* Examples:
         *  "binds": [
         *      {
         *          "prop": [
         *              {
         *                  "name": "prop name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "prop name",
         *                  "value": {
         *                      "source": "the_prop_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        prop: function(target, context, propTypes, dataContext) {
            if (!propTypes || !propTypes.length) {
                return;
            }
            for (var i = 0; i < propTypes.length; ++i) {
                var value = computeStringOrSourceDataValue(propTypes[i].value, dataContext);
                target.prop(propTypes[i].name, value);
            }
        },

        // add class
        /* Examples:
         *  "binds": [
         *      {
         *          "addClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        addClass: function(target, context, classes, dataContext) {
            if (!classes || !classes.length) {
                return;
            }
            for (var i = 0; i < classes.length; ++i) {
                target.addClass(classes[i]);
            }
        },

        // remove class
        /* Examples:
         *  "binds": [
         *      {
         *          "removeClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        removeClass: function(target, context, classes, dataContext) {
            if (!classes || !classes.length) {
                return;
            }
            for (var i = 0; i < classes.length; ++i) {
                target.removeClass(classes[i]);
            }
        },

        // innerHTML
        /* Examples:
         *  "binds": [
         *      {
         *          "html": "a_string_value"
         *      },
         *
         *      {
         *          "html": {
         *              "source": "the_field_name_from_a_source"
         *          }
         *      }
         *  ]
         */
        html: function(target, context, dataType, dataContext) {
            var value = computeStringOrSourceDataValue(dataType, dataContext);
            if (value === undefined || value === null) {
                value = '';
            } else {
                value = value.toString();
            }
            target.html(value);
        },

        // repeat the target for each item in array source
        /*
         *   "binds": [
         *       {
         *           "repeat": {
         *               "source": "the_array_name_from_a_source",
         *               "preFilter": "handler_name",
         *               "postFilter": "handler_name",
         *               "binds": [
         *                   ...
         *               ]
         *           }
         *       }
         *   ]
         */
        repeat: function(target, context, bindTemplate, dataContext) {

            if (!target.length) {
                console.warn("Empty bind 'repeat' target");
                return;
            }

            if (typeof dataContext !== "object" || !dataContext) {
                console.warn("A bind 'repeat' can only be used with an object data context");
                return;
            }

            var sourceArray = dataContext[bindTemplate.source] || [];

            if (Object.prototype.toString.call(sourceArray) !== "[object Array]" ) {
                console.warn("A bind 'repeat' did not find an array in the source field of the data context");
                return;
            }

            var template = target.clone();
            var container = target.parent();

            // run the pre-filtering handler
            var filterFunction = findFunction(self, bindTemplate.preFilter) || findFunction(window, bindTemplate.prefilter);
            if (filterFunction) {
                sourceArray = filterFunction(self, dataContext, bindTemplate.source, sourceArray, container);
            }

            // run the binds for each item
            for (var i = 0; i < sourceArray.length; ++i) {

                var newDom = template.clone();

                if (!bindTemplate.binds || !bindTemplate.binds.length) {
                    continue;
                }

                for (var j = 0; j < bindTemplate.binds.length; ++j) {
                    var bind = bindTemplate.binds[j];
                    bind.context = newDom;
                    Bind.call(self, bind, sourceArray[i]);
                }

                container.append(newDom);
            }

            // run the post-filtering handler
            filterFunction = findFunction(self, bindTemplate.postFilter) || findFunction(window, bindTemplate.postFilter);
            if (filterFunction) {
                sourceArray = filterFunction(self, dataContext, bindTemplate.source, sourceArray, container);
            }

            target.remove();
        }
    }

    for (var key in bind) {
        if (!bind.hasOwnProperty(key)) continue;

        if (domManipulators[key]) {
            domManipulators[key](target, context, bind[key], dataContext);
        }
    }

    if (bind.on) {
        for (var i = 0; i < bind.on.length; ++i) {
            var curOn = bind.on[i];
            if (curOn.handler || curOn.emit) {
                (function (curOn) {
                    var t = target;
                    var s = null;

                    // of the delegated option is set, this bind will work for future DOM insertions
                    if (curOn.delegated) {
                        t = context;
                        s = target.selector;
                    }

                    t.on(curOn.name, s,function(event) {
                        event.stopPropagation();

                        var name = curOn.handler;
                        var args = [];

                        if (typeof name === "object") {
                            args = name.args || [];
                            name = name.name;
                        }

                        // if the noEvent option is set, the DOM event will not be passed to the called handler or emitted event
                        if (!curOn.noEvent) {
                            args.push(event);
                        }
                        args.push(dataContext);

                        if (typeof name === "function") {
                            name.apply(self, args);
                            return false;
                        }

                        var handler = findFunction(self, name) || findFunction(window, name);

                        if (typeof handler === "function") {
                            handler.apply(self, args);
                        }

                        if (curOn.emit) {
                            self.emit(curOn.emit, dataContext);
                        }

                        return false;
                    });
                })(curOn);
            }
        }
    }

    for (var key in bind.listen) {
        if (!bind.listen.hasOwnProperty(key)) continue;

        var curListen = bind.listen[key];
        self.on(curListen.name, curListen.miid, self[curListen.handler]);
    }
};
<|endoftext|>