<commit_before>define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
  function (SortTable, V, d3Interpolate, moment, helper) {
    'use strict';
    V = V.default;

    function showGeoURI(d) {
      if (!helper.hasLocation(d)) {
        return undefined;
      }

      return function (el) {
        var a = document.createElement('a');
        a.textContent = Number(d.nodeinfo.location.latitude.toFixed(6)) + ', ' + Number(d.nodeinfo.location.longitude.toFixed(6));
        a.href = 'geo:' + d.nodeinfo.location.latitude + ',' + d.nodeinfo.location.longitude;
        el.appendChild(a);
      };
    }

    function showStatus(d) {
      return function (el) {
        el.classList.add(d.flags.unseen ? 'unseen' : (d.flags.online ? 'online' : 'offline'));
        el.textContent = _.t((d.flags.online ? 'node.lastOnline' : 'node.lastOffline'), {
          time: d.lastseen.fromNow(),
          date: d.lastseen.format('DD.MM.YYYY, H:mm:ss')
        });
      };
    }

    function showFirmware(d) {
      var release = helper.dictGet(d.nodeinfo, ['software', 'firmware', 'release']);
      var base = helper.dictGet(d.nodeinfo, ['software', 'firmware', 'base']);

      if (release === null || base === null) {
        return undefined;
      }

      return release + ' / ' + base;
    }

    function showSite(d, config) {
      var site = helper.dictGet(d.nodeinfo, ['system', 'site_code']);
      var rt = site;
      if (config.siteNames) {
        config.siteNames.forEach(function (t) {
          if (site === t.site) {
            rt = t.name;
          }
        });
      }
      return rt;
    }

    function showUptime(d) {
      if (!('uptime' in d.statistics)) {
        return undefined;
      }

      return moment.duration(d.statistics.uptime, 'seconds').humanize();
    }

    function showFirstseen(d) {
      if (!('firstseen' in d)) {
        return undefined;
      }

      return d.firstseen.fromNow(true);
    }

    function showClients(d) {
      if (!d.flags.online) {
        return undefined;
      }

      return function (el) {
        el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : _.t('none')));
        el.appendChild(document.createElement('br'));

        var span = document.createElement('span');
        span.classList.add('clients');
        span.innerHTML = ''.repeat(d.statistics.clients);
        el.appendChild(span);
      };
    }

    function showIPs(d) {
      var ips = helper.dictGet(d.nodeinfo, ['network', 'addresses']);
      if (ips === null) {
        return undefined;
      }

      ips.sort();

      return function (el) {
        ips.forEach(function (ip, i) {
          var link = !ip.startsWith('fe80:');

          if (i > 0) {
            el.appendChild(document.createElement('br'));
          }

          if (link) {
            var a = document.createElement('a');
            a.href = 'http://[' + ip + ']/';
            a.textContent = ip;
            el.appendChild(a);
          } else {
            el.appendChild(document.createTextNode(ip));
          }
        });
      };
    }

    function showBar(v, width, warning) {
      var span = document.createElement('span');
      span.classList.add('bar');

      var bar = document.createElement('span');
      bar.style.width = (width * 100) + '%';
      if (warning) {
        span.classList.add('warning');
      }
      span.appendChild(bar);

      var label = document.createElement('label');
      label.textContent = v;
      span.appendChild(label);

      return span;
    }

    function showLoad(d) {
      if (!('loadavg' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = d.statistics.loadavg.toFixed(2);
        var width = d.statistics.loadavg % 1;
        var warning = false;
        if (d.statistics.loadavg >= d.nodeinfo.hardware.nproc) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showRAM(d) {
      if (!('memory_usage' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = Math.round(d.statistics.memory_usage * 100) + ' %';
        var width = d.statistics.memory_usage;
        var warning = false;
        if (d.statistics.memory_usage >= 0.8) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showAutoupdate(d) {
      var au = helper.dictGet(d.nodeinfo, ['software', 'autoupdater']);
      if (!au) {
        return undefined;
      }

      return au.enabled ? _.t('node.activated', { branch: au.branch }) : _.t('node.deactivated');
    }

    function showStatImg(o, d) {
      var subst = {};
      subst['{NODE_ID}'] = d.nodeinfo.node_id;
      subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
      subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
      subst['{LOCALE}'] = _.locale();
      return helper.showStat(o, subst);
    }

    return function (config, el, router, d, gateways) {
      var linkScale = d3Interpolate.interpolate('#F02311', '#04C714');

      function renderNeighbourRow(n) {
        var icons = [];
        icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
        if (helper.hasLocation(n.node)) {
          icons.push(V.h('span', { props: { className: 'ion-location' } }));
        }

        var name = V.h('a', {
          props: {
            className: 'online',
            href: router.generateLink({ node: n.node.nodeinfo.node_id })
          }, on: {
            click: function (e) {
              router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
            }
          }
        }, n.node.nodeinfo.hostname);

        var td1 = V.h('td', icons);
        var td2 = V.h('td', name);
        var td3 = V.h('td', (n.node.statistics.clients ? n.node.statistics.clients.toString() : '0'));
        var td4 = V.h('td', { style: { color: linkScale(1 / n.link.tq) } }, helper.showTq(n.link));
        var td5 = V.h('td', helper.showDistance(n.link));

        return V.h('tr', [td1, td2, td3, td4, td5]);
      }

      var h2 = document.createElement('h2');
      h2.textContent = d.nodeinfo.hostname;
      el.appendChild(h2);

      var attributes = document.createElement('table');
      attributes.classList.add('attributes');

      helper.attributeEntry(attributes, 'node.status', showStatus(d));
      helper.attributeEntry(attributes, 'node.gateway', d.flags.gateway ? 'ja' : null);
      helper.attributeEntry(attributes, 'node.coordinates', showGeoURI(d));

      if (config.nodeInfobox && config.nodeInfobox.contact) {
        helper.attributeEntry(attributes, 'node.contact', helper.dictGet(d.nodeinfo, ['owner', 'contact']));
      }

      helper.attributeEntry(attributes, 'node.hardware', helper.dictGet(d.nodeinfo, ['hardware', 'model']));
      helper.attributeEntry(attributes, 'node.primaryMac', helper.dictGet(d.nodeinfo, ['network', 'mac']));
      helper.attributeEntry(attributes, 'node.id', helper.dictGet(d.nodeinfo, ['node_id']));
      helper.attributeEntry(attributes, 'node.firmware', showFirmware(d));
      helper.attributeEntry(attributes, 'node.site', showSite(d, config));
      helper.attributeEntry(attributes, 'node.uptime', showUptime(d));
      helper.attributeEntry(attributes, 'node.firstSeen', showFirstseen(d));
      if (config.nodeInfobox && config.nodeInfobox.hardwareUsage) {
        helper.attributeEntry(attributes, 'node.systemLoad', showLoad(d));
        helper.attributeEntry(attributes, 'node.ram', showRAM(d));
      }
      helper.attributeEntry(attributes, 'node.ipAddresses', showIPs(d));
      helper.attributeEntry(attributes, 'node.selectedGateway', gateways[helper.dictGet(d.statistics, ['gateway'])]);
      helper.attributeEntry(attributes, 'node.update', showAutoupdate(d));
      helper.attributeEntry(attributes, 'node.clients', showClients(d));

      el.appendChild(attributes);

      if (d.neighbours.length > 0) {
        var h3 = document.createElement('h3');
        h3.textContent = _.t('node.link', d.neighbours.length) + ' (' + d.neighbours.length + ')';
        el.appendChild(h3);

        var headings = [{
          name: ''
        }, {
          name: 'node.nodes',
          sort: function (a, b) {
            return a.node.nodeinfo.hostname.localeCompare(b.node.nodeinfo.hostname);
          },
          reverse: false
        }, {
          name: 'node.clients',
          class: 'ion-people',
          sort: function (a, b) {
            return ('clients' in a.node.statistics ? a.node.statistics.clients : -1) -
              ('clients' in b.node.statistics ? b.node.statistics.clients : -1);
          },
          reverse: true
        }, {
          name: 'node.tq',
          class: 'ion-connection-bars',
          sort: function (a, b) {
            return a.link.tq - b.link.tq;
          },
          reverse: true
        }, {
          name: 'node.distance',
          class: 'ion-arrow-resize',
          sort: function (a, b) {
            return (a.link.distance === undefined ? -1 : a.link.distance) -
              (b.link.distance === undefined ? -1 : b.link.distance);
          },
          reverse: true
        }];

        var table = new SortTable(headings, 1, renderNeighbourRow);
        table.setData(d.neighbours);
        table.el.elm.classList.add('node-links');
        el.appendChild(table.el.elm);
      }

      if (config.nodeInfos) {
        config.nodeInfos.forEach(function (nodeInfo) {
          var h4 = document.createElement('h4');
          h4.textContent = nodeInfo.name;
          el.appendChild(h4);
          el.appendChild(showStatImg(nodeInfo, d));
        });
      }
    };
  });
<commit_msg>[BUGFIX] Show available firmware information<commit_after>define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
  function (SortTable, V, d3Interpolate, moment, helper) {
    'use strict';
    V = V.default;

    function showGeoURI(d) {
      if (!helper.hasLocation(d)) {
        return undefined;
      }

      return function (el) {
        var a = document.createElement('a');
        a.textContent = Number(d.nodeinfo.location.latitude.toFixed(6)) + ', ' + Number(d.nodeinfo.location.longitude.toFixed(6));
        a.href = 'geo:' + d.nodeinfo.location.latitude + ',' + d.nodeinfo.location.longitude;
        el.appendChild(a);
      };
    }

    function showStatus(d) {
      return function (el) {
        el.classList.add(d.flags.unseen ? 'unseen' : (d.flags.online ? 'online' : 'offline'));
        el.textContent = _.t((d.flags.online ? 'node.lastOnline' : 'node.lastOffline'), {
          time: d.lastseen.fromNow(),
          date: d.lastseen.format('DD.MM.YYYY, H:mm:ss')
        });
      };
    }

    function showFirmware(d) {
      return [
        helper.dictGet(d.nodeinfo, ['software', 'firmware', 'release']),
        helper.dictGet(d.nodeinfo, ['software', 'firmware', 'base'])
      ].filter(function (n) {
        return n !== null;
      }).join(' / ') || undefined;
    }

    function showSite(d, config) {
      var site = helper.dictGet(d.nodeinfo, ['system', 'site_code']);
      var rt = site;
      if (config.siteNames) {
        config.siteNames.forEach(function (t) {
          if (site === t.site) {
            rt = t.name;
          }
        });
      }
      return rt;
    }

    function showUptime(d) {
      if (!('uptime' in d.statistics)) {
        return undefined;
      }

      return moment.duration(d.statistics.uptime, 'seconds').humanize();
    }

    function showFirstseen(d) {
      if (!('firstseen' in d)) {
        return undefined;
      }

      return d.firstseen.fromNow(true);
    }

    function showClients(d) {
      if (!d.flags.online) {
        return undefined;
      }

      return function (el) {
        el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : _.t('none')));
        el.appendChild(document.createElement('br'));

        var span = document.createElement('span');
        span.classList.add('clients');
        span.innerHTML = ''.repeat(d.statistics.clients);
        el.appendChild(span);
      };
    }

    function showIPs(d) {
      var ips = helper.dictGet(d.nodeinfo, ['network', 'addresses']);
      if (ips === null) {
        return undefined;
      }

      ips.sort();

      return function (el) {
        ips.forEach(function (ip, i) {
          var link = !ip.startsWith('fe80:');

          if (i > 0) {
            el.appendChild(document.createElement('br'));
          }

          if (link) {
            var a = document.createElement('a');
            a.href = 'http://[' + ip + ']/';
            a.textContent = ip;
            el.appendChild(a);
          } else {
            el.appendChild(document.createTextNode(ip));
          }
        });
      };
    }

    function showBar(v, width, warning) {
      var span = document.createElement('span');
      span.classList.add('bar');

      var bar = document.createElement('span');
      bar.style.width = (width * 100) + '%';
      if (warning) {
        span.classList.add('warning');
      }
      span.appendChild(bar);

      var label = document.createElement('label');
      label.textContent = v;
      span.appendChild(label);

      return span;
    }

    function showLoad(d) {
      if (!('loadavg' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = d.statistics.loadavg.toFixed(2);
        var width = d.statistics.loadavg % 1;
        var warning = false;
        if (d.statistics.loadavg >= d.nodeinfo.hardware.nproc) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showRAM(d) {
      if (!('memory_usage' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = Math.round(d.statistics.memory_usage * 100) + ' %';
        var width = d.statistics.memory_usage;
        var warning = false;
        if (d.statistics.memory_usage >= 0.8) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showAutoupdate(d) {
      var au = helper.dictGet(d.nodeinfo, ['software', 'autoupdater']);
      if (!au) {
        return undefined;
      }

      return au.enabled ? _.t('node.activated', { branch: au.branch }) : _.t('node.deactivated');
    }

    function showStatImg(o, d) {
      var subst = {};
      subst['{NODE_ID}'] = d.nodeinfo.node_id;
      subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
      subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
      subst['{LOCALE}'] = _.locale();
      return helper.showStat(o, subst);
    }

    return function (config, el, router, d, gateways) {
      var linkScale = d3Interpolate.interpolate('#F02311', '#04C714');

      function renderNeighbourRow(n) {
        var icons = [];
        icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
        if (helper.hasLocation(n.node)) {
          icons.push(V.h('span', { props: { className: 'ion-location' } }));
        }

        var name = V.h('a', {
          props: {
            className: 'online',
            href: router.generateLink({ node: n.node.nodeinfo.node_id })
          }, on: {
            click: function (e) {
              router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
            }
          }
        }, n.node.nodeinfo.hostname);

        var td1 = V.h('td', icons);
        var td2 = V.h('td', name);
        var td3 = V.h('td', (n.node.statistics.clients ? n.node.statistics.clients.toString() : '0'));
        var td4 = V.h('td', { style: { color: linkScale(1 / n.link.tq) } }, helper.showTq(n.link));
        var td5 = V.h('td', helper.showDistance(n.link));

        return V.h('tr', [td1, td2, td3, td4, td5]);
      }

      var h2 = document.createElement('h2');
      h2.textContent = d.nodeinfo.hostname;
      el.appendChild(h2);

      var attributes = document.createElement('table');
      attributes.classList.add('attributes');

      helper.attributeEntry(attributes, 'node.status', showStatus(d));
      helper.attributeEntry(attributes, 'node.gateway', d.flags.gateway ? 'ja' : null);
      helper.attributeEntry(attributes, 'node.coordinates', showGeoURI(d));

      if (config.nodeInfobox && config.nodeInfobox.contact) {
        helper.attributeEntry(attributes, 'node.contact', helper.dictGet(d.nodeinfo, ['owner', 'contact']));
      }

      helper.attributeEntry(attributes, 'node.hardware', helper.dictGet(d.nodeinfo, ['hardware', 'model']));
      helper.attributeEntry(attributes, 'node.primaryMac', helper.dictGet(d.nodeinfo, ['network', 'mac']));
      helper.attributeEntry(attributes, 'node.id', helper.dictGet(d.nodeinfo, ['node_id']));
      helper.attributeEntry(attributes, 'node.firmware', showFirmware(d));
      helper.attributeEntry(attributes, 'node.site', showSite(d, config));
      helper.attributeEntry(attributes, 'node.uptime', showUptime(d));
      helper.attributeEntry(attributes, 'node.firstSeen', showFirstseen(d));
      if (config.nodeInfobox && config.nodeInfobox.hardwareUsage) {
        helper.attributeEntry(attributes, 'node.systemLoad', showLoad(d));
        helper.attributeEntry(attributes, 'node.ram', showRAM(d));
      }
      helper.attributeEntry(attributes, 'node.ipAddresses', showIPs(d));
      helper.attributeEntry(attributes, 'node.selectedGateway', gateways[helper.dictGet(d.statistics, ['gateway'])]);
      helper.attributeEntry(attributes, 'node.update', showAutoupdate(d));
      helper.attributeEntry(attributes, 'node.clients', showClients(d));

      el.appendChild(attributes);

      if (d.neighbours.length > 0) {
        var h3 = document.createElement('h3');
        h3.textContent = _.t('node.link', d.neighbours.length) + ' (' + d.neighbours.length + ')';
        el.appendChild(h3);

        var headings = [{
          name: ''
        }, {
          name: 'node.nodes',
          sort: function (a, b) {
            return a.node.nodeinfo.hostname.localeCompare(b.node.nodeinfo.hostname);
          },
          reverse: false
        }, {
          name: 'node.clients',
          class: 'ion-people',
          sort: function (a, b) {
            return ('clients' in a.node.statistics ? a.node.statistics.clients : -1) -
              ('clients' in b.node.statistics ? b.node.statistics.clients : -1);
          },
          reverse: true
        }, {
          name: 'node.tq',
          class: 'ion-connection-bars',
          sort: function (a, b) {
            return a.link.tq - b.link.tq;
          },
          reverse: true
        }, {
          name: 'node.distance',
          class: 'ion-arrow-resize',
          sort: function (a, b) {
            return (a.link.distance === undefined ? -1 : a.link.distance) -
              (b.link.distance === undefined ? -1 : b.link.distance);
          },
          reverse: true
        }];

        var table = new SortTable(headings, 1, renderNeighbourRow);
        table.setData(d.neighbours);
        table.el.elm.classList.add('node-links');
        el.appendChild(table.el.elm);
      }

      if (config.nodeInfos) {
        config.nodeInfos.forEach(function (nodeInfo) {
          var h4 = document.createElement('h4');
          h4.textContent = nodeInfo.name;
          el.appendChild(h4);
          el.appendChild(showStatImg(nodeInfo, d));
        });
      }
    };
  });
<|endoftext|>


<commit_before>'use strict';

var Installation = require('./schema.js'),
    moment = require('moment'),
    _ = require('lodash');

var InstallationModel = function (connection, collection) {

        var model,
            schema,

            createInstallation = function (installation, user, cb) {

                //installation.updatedAt.date = moment();
                //installation.updatedAt.user = user;

                var thisInstallation = new model(installation);

                thisInstallation
                    .save(function (err) {
                        if (err) {
                            cb(err, null);
                        } else {
                            cb(null, thisInstallation);
                        }
                    });
            },

            allInstallations = function (cb) {

                model.find(function (err, installations) {
                    if (err) {
                        cb(err, null);
                    } else {
                        cb(null, installations);
                    }
                });
            },

            getInstallation = function (id, cb) {

                model.findOne({_id: id}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        cb(null, installation);
                    }
                });
            },

            updateInstallation = function (id, user, installation, cb) {

//            installation.updatedAt.date = moment();
//            installation.updatedAt.user = user;

                model.findOneAndUpdate({_id: id}, installation, function (err, installation) {
                    if (err) {
                        cb(err);
                    } else {
                        cb(null);
                    }
                });
            },

            removeInstallation = function (id, cb) {

                model.findOneAndRemove({_id: id}, function (err) {
                    if (err) {
                        cb(err);
                    } else {
                        cb(null);
                    }

                });

            },

            getDevice = function (deviceid, cb) {

                model.findOne({devices: {$elemMatch: {_id: deviceid }}}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            installation.devices.forEach(function (d) {
                                if (d._id == deviceid) {
                                    cb(null, d);
                                }
                            });
                        }
                        else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                })
            },

            updateDevice = function (deviceid, device, cb) {

                model.findOne({'devices._id': deviceid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            model.update({ 'devices._id': deviceid }, { '$set': { 'devices.$': device }}, function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                });
            },

            newDevice = function (id, device, cb) {

                model.findOne({'devices._id': id}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            installation.devices.push(device);
                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find installation: " + deviceid);
                        }
                    }
                });
            },

            removeDevice = function (deviceid, cb) {

                model.findOne({'devices._id': deviceid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            model.update({_id: installation._id}, { "$pull": { "devices": { "_id": deviceid }}}, function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                });
            },

            getControl = function (controlid, cb) {

                model.findOne({'devices.controls._id': controlid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.controls.forEach(function (c) {
                                    if (c._id == controlid) {
                                        return cb(null, c);
                                    }
                                });
                            });

                        } else {
                            cb(null, "Couldn't find device: " + controlid);
                        }
                    }
                });
            },

            updateControl = function (controlid, control, cb) {

                model.findOne({'devices.controls._id': controlid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.controls.forEach(function (c) {
                                    if (c._id == controlid) {
                                        c.set(control);
                                    }
                                });
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });

                        } else {
                            cb(null, "Couldn't find device: " + controlid);
                        }
                    }
                });
            },

            newControl = function (id, control, cb) {

                model.findOne({'devices._id': id}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            installation.devices.forEach(function (d) {
                                if (d._id == id) {
                                    d.controls.push(control);
                                }
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find installation: " + controlid);
                        }
                    }
                });
            },

            removeControl = function (controlid, cb) {

                model.findOne({'devices.controls._id': controlid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.controls.forEach(function (c) {
                                    if (c._id == controlid) {
                                        d.controls.pull(c);
                                    }
                                });
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find device: " + controlid);
                        }
                    }
                });
            },

            updateTriggerValue = function (deviceid, triggerIndex, value, cb) {

                model.findOne({devices: {$elemMatch: {id: deviceid }}}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            var index = _.findIndex(installation.devices, { 'id': deviceid })
                            if (_.isNumber(index)) {
                                var installationDoc = installation.toObject();
                                installationDoc.devices[index].triggers[triggerIndex].triggered_value = value;
                                model.update({_id: installation._id}, installationDoc, {upsert: true}, function (err) {
                                    if (err) {
                                        cb(err, null);
                                    } else {
                                        cb(null, null);
                                    }
                                });
                            }
                        } else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                });
            };

        function init(connection, collection) {

            if (connection.modelNames().indexOf(collection) >= 0) {
                model = connection.model(collection);
            } else {
                schema = Installation;
                connection.model(collection, schema);
                model = connection.model(collection);
            }
        }

        init(connection, collection);

        /* Return model api */
        return {
            createInstallation: createInstallation,
            allInstallations: allInstallations,
            getInstallation: getInstallation,
            updateInstallation: updateInstallation,
            removeInstallation: removeInstallation,
            getDevice: getDevice,
            newDevice: newDevice,
            updateDevice: updateDevice,
            removeDevice: removeDevice,
            getControl: getControl,
            newControl: newControl,
            updateControl: updateControl,
            removeControl: removeControl,

            updateTriggerValue: updateTriggerValue
        };
    }
    ;

module.exports = InstallationModel;
<commit_msg>Add trigger api<commit_after>'use strict';

var Installation = require('./schema.js'),
    moment = require('moment'),
    _ = require('lodash');

var InstallationModel = function (connection, collection) {

        var model,
            schema,

            createInstallation = function (installation, user, cb) {

                //installation.updatedAt.date = moment();
                //installation.updatedAt.user = user;

                var thisInstallation = new model(installation);

                thisInstallation
                    .save(function (err) {
                        if (err) {
                            cb(err, null);
                        } else {
                            cb(null, thisInstallation);
                        }
                    });
            },

            allInstallations = function (cb) {

                model.find(function (err, installations) {
                    if (err) {
                        cb(err, null);
                    } else {
                        cb(null, installations);
                    }
                });
            },

            getInstallation = function (id, cb) {

                model.findOne({_id: id}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        cb(null, installation);
                    }
                });
            },

            updateInstallation = function (id, user, installation, cb) {

//            installation.updatedAt.date = moment();
//            installation.updatedAt.user = user;

                model.findOneAndUpdate({_id: id}, installation, function (err, installation) {
                    if (err) {
                        cb(err);
                    } else {
                        cb(null);
                    }
                });
            },

            removeInstallation = function (id, cb) {

                model.findOneAndRemove({_id: id}, function (err) {
                    if (err) {
                        cb(err);
                    } else {
                        cb(null);
                    }

                });

            },

            getDevice = function (deviceid, cb) {

                model.findOne({devices: {$elemMatch: {_id: deviceid }}}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            installation.devices.forEach(function (d) {
                                if (d._id == deviceid) {
                                    cb(null, d);
                                }
                            });
                        }
                        else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                })
            },

            updateDevice = function (deviceid, device, cb) {

                model.findOne({'devices._id': deviceid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            model.update({ 'devices._id': deviceid }, { '$set': { 'devices.$': device }}, function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                });
            },

            newDevice = function (id, device, cb) {

                model.findOne({'_id': id}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            installation.devices.push(device);
                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find installation: " + id);
                        }
                    }
                });
            },

            removeDevice = function (deviceid, cb) {

                model.findOne({'devices._id': deviceid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            model.update({_id: installation._id}, { "$pull": { "devices": { "_id": deviceid }}}, function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                });
            },

            getControl = function (controlid, cb) {

                model.findOne({'devices.controls._id': controlid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.controls.forEach(function (c) {
                                    if (c._id == controlid) {
                                        return cb(null, c);
                                    }
                                });
                            });

                        } else {
                            cb(null, "Couldn't find control: " + controlid);
                        }
                    }
                });
            },

            updateControl = function (controlid, control, cb) {

                model.findOne({'devices.controls._id': controlid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.controls.forEach(function (c) {
                                    if (c._id == controlid) {
                                        c.set(control);
                                    }
                                });
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });

                        } else {
                            cb(null, "Couldn't find control: " + controlid);
                        }
                    }
                });
            },

            newControl = function (id, control, cb) {

                model.findOne({'devices._id': id}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            installation.devices.forEach(function (d) {
                                if (d._id == id) {
                                    d.controls.push(control);
                                }
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find control: " + controlid);
                        }
                    }
                });
            },

            removeControl = function (controlid, cb) {

                model.findOne({'devices.controls._id': controlid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.controls.forEach(function (c) {
                                    if (c._id == controlid) {
                                        d.controls.pull(c);
                                    }
                                });
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find control: " + controlid);
                        }
                    }
                });
            },

        /* triggers */
            getTrigger = function (triggerid, cb) {

                model.findOne({'devices.triggers._id': triggerid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.triggers.forEach(function (t) {
                                    if (t._id == triggerid) {
                                        return cb(null, t);
                                    }
                                });
                            });

                        } else {
                            cb(null, "Couldn't find trigger: " + triggerid);
                        }
                    }
                });
            },

            updateTrigger = function (triggerid, trigger, cb) {

                model.findOne({'devices.triggers._id': triggerid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.triggers.forEach(function (t) {
                                    if (t._id == triggerid) {
                                        t.set(trigger);
                                    }
                                });
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });

                        } else {
                            cb(null, "Couldn't find trigger: " + triggerid);
                        }
                    }
                });
            },

            newTrigger = function (id, trigger, cb) {

                model.findOne({'devices._id': id}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            installation.devices.forEach(function (d) {
                                if (d._id == id) {
                                    d.triggers.push(trigger);
                                }
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find trigger: " + triggerid);
                        }
                    }
                });
            },

            removeTrigger = function (triggerid, cb) {

                model.findOne({'devices.triggers._id': triggerid }, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {

                            installation.devices.forEach(function (d) {
                                d.triggers.forEach(function (t) {
                                    if (t._id == triggerid) {
                                        d.triggers.pull(t);
                                    }
                                });
                            });

                            installation.save(function (err, data) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, data);
                                }
                            });
                        } else {
                            cb(null, "Couldn't find trigger: " + triggerid);
                        }
                    }
                });
            },

            updateTriggerValue = function (deviceid, triggerIndex, value, cb) {

                model.findOne({devices: {$elemMatch: {id: deviceid }}}, function (err, installation) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (installation) {
                            var index = _.findIndex(installation.devices, { 'id': deviceid })
                            if (_.isNumber(index)) {
                                var installationDoc = installation.toObject();
                                installationDoc.devices[index].triggers[triggerIndex].triggered_value = value;
                                model.update({_id: installation._id}, installationDoc, {upsert: true}, function (err) {
                                    if (err) {
                                        cb(err, null);
                                    } else {
                                        cb(null, null);
                                    }
                                });
                            }
                        } else {
                            cb(null, "Couldn't find device: " + deviceid);
                        }
                    }
                });
            };

        function init(connection, collection) {

            if (connection.modelNames().indexOf(collection) >= 0) {
                model = connection.model(collection);
            } else {
                schema = Installation;
                connection.model(collection, schema);
                model = connection.model(collection);
            }
        }

        init(connection, collection);

        /* Return model api */
        return {
            createInstallation: createInstallation,
            allInstallations: allInstallations,
            getInstallation: getInstallation,
            updateInstallation: updateInstallation,
            removeInstallation: removeInstallation,
            getDevice: getDevice,
            newDevice: newDevice,
            updateDevice: updateDevice,
            removeDevice: removeDevice,
            getControl: getControl,
            newControl: newControl,
            updateControl: updateControl,
            removeControl: removeControl,
            getTrigger: getTrigger,
            newTrigger: newTrigger,
            updateTrigger: updateTrigger,
            removeTrigger: removeTrigger,
            updateTriggerValue: updateTriggerValue
        };
    }
    ;

module.exports = InstallationModel;
<|endoftext|>


<commit_before>'use strict';

var net   = require('net');
var debug = require('debug')('instrumental');

const VERSION = require('../package.json').version;

class Instrumental {

  constructor() {
    this.queuedCalls = [];
    this.enabled = false;
  }

  configure(options){
    this.apiKey  = options.apiKey;
    this.enabled = options.enabled === undefined ? true : options.enabled;
    this.host    = options.host || 'collector.instrumentalapp.com';
  }

  connect(){
    if(this.socket){ return; }

    debug('Opening Instrumental connection');
    this.socket = net.createConnection({ host: this.host, port: 8000 });
    this.socket.setEncoding('ascii');

    this.socket.on('connect', () => {
      debug('Authenticating Instrumental connection');
      this.socket.write('hello version node/instrumental_agent/' + VERSION + '\n' +
                        'authenticate ' + this.apiKey + '\n');
    });

    this.socket.on('error', (err) => {
      debug('Connection Error ' + err);
    });

    this.socket.on('close', (hadError) => {
      debug('Closing Instrumental connection - ' + hadError);
      if (hadError) { this.socket.destroy(); }
      this.socket.removeAllListeners();
      this.connected = false;
      this.socket = null;
      if(this.queuedCalls.length > 0){
        setTimeout(() => { this.connect(); }, 5000);
      }
    });

    this.socket.on('data', (data) => {
      if (data === 'ok\nok\n') {
        debug('Instrumental connected!');
        this.connected = true;
        this.socket.write(this.queuedCalls.join('\n'));
        this.queuedCalls = [];
      } else if (data === 'ok\nfail\n') {
        debug('Instrumental authentication failed!');
        this.connected = false;
        this.socket.end();
      } else {
        debug('Unexpected response received - ' + data);
      }
    });
  }

  apiCall(type, metric, value, time, count){
    if(!this.enabled){ return; }
    if(!time){ time = Date.now(); }
    setImmediate(() => { this.apiCallInner(type, metric, value, time, count); });
  }

  apiCallInner(type, metric, value, time, count){
    if(!metric){
      debug('Metric name required');
      return;
    }

    value = Number(value);
    if(!isFinite(value)){
      debug('Metric value is invalid');
      return;
    }

    if(count === null || count === undefined){ count = 1; }
    count = Number(count);
    if(!isFinite(count)){
      debug('Metric count is invalid');
      return;
    }

    if(!time){ time = Date.now(); }
    time = Math.round(Number(time) / 1000);

    var line = [type, metric, value, time, count].join(' ') + '\n';
    if(this.connected){
      this.socket.write(line);
    } else {
      if(!this.socket){ this.connect(); }
      if(this.queuedCalls.length > 1000){
        debug('Queue too large - dropping metric');
        return;
      }
      this.queuedCalls.push(line);
    }
  }

  noticeApiCallInner(type, time, duration, desc) {
  if(!this.enabled){ return; }
  if (!time) {
    time = Date.now();
  }
  time = Math.round(Number(time) / 1000);
  if(duration === null || duration === undefined){ duration = 0; }
  duration = Number(duration);
  if(!isFinite(duration)){
    debug('duration is invalid');
    return;
  }

  var line = [type, time, duration, desc].join(' ') + '\n';
  if (this.connected) {
    this.socket.write(line);
  }
  else {
    if (!this.socket) {
      this.connect();
    }
    if (this.queuedCalls.length > 1000) {
      debug('Queue too large - dropping notice event');
      return;
    }
    this.queuedCalls.push(line);
  }
  };

  increment(metric, value, time, count){
    if(value === 0){ return; }
    if(value === null || value === undefined){ value = 1; }
    this.apiCall('increment', metric, value, time, count);
  }

  gauge(metric, value, time, count){
    this.apiCall('gauge', metric, value, time, count);
  }

  notice(time, duration, description) {
    if (!time) {
    time = Date.now();
    }
     setImmediate(() => {
    this.noticeApiCallInner('notice', time, duration, description);
    });
  }

}

module.exports = Instrumental;
<commit_msg>tabs-to-spaces<commit_after>'use strict';

var net   = require('net');
var debug = require('debug')('instrumental');

const VERSION = require('../package.json').version;

class Instrumental {

  constructor() {
    this.queuedCalls = [];
    this.enabled = false;
  }

  configure(options){
    this.apiKey  = options.apiKey;
    this.enabled = options.enabled === undefined ? true : options.enabled;
    this.host    = options.host || 'collector.instrumentalapp.com';
  }

  connect(){
    if(this.socket){ return; }

    debug('Opening Instrumental connection');
    this.socket = net.createConnection({ host: this.host, port: 8000 });
    this.socket.setEncoding('ascii');

    this.socket.on('connect', () => {
      debug('Authenticating Instrumental connection');
      this.socket.write('hello version node/instrumental_agent/' + VERSION + '\n' +
                        'authenticate ' + this.apiKey + '\n');
    });

    this.socket.on('error', (err) => {
      debug('Connection Error ' + err);
    });

    this.socket.on('close', (hadError) => {
      debug('Closing Instrumental connection - ' + hadError);
      if (hadError) { this.socket.destroy(); }
      this.socket.removeAllListeners();
      this.connected = false;
      this.socket = null;
      if(this.queuedCalls.length > 0){
        setTimeout(() => { this.connect(); }, 5000);
      }
    });

    this.socket.on('data', (data) => {
      if (data === 'ok\nok\n') {
        debug('Instrumental connected!');
        this.connected = true;
        this.socket.write(this.queuedCalls.join('\n'));
        this.queuedCalls = [];
      } else if (data === 'ok\nfail\n') {
        debug('Instrumental authentication failed!');
        this.connected = false;
        this.socket.end();
      } else {
        debug('Unexpected response received - ' + data);
      }
    });
  }

  apiCall(type, metric, value, time, count){
    if(!this.enabled){ return; }
    if(!time){ time = Date.now(); }
    setImmediate(() => { this.apiCallInner(type, metric, value, time, count); });
  }

  apiCallInner(type, metric, value, time, count){
    if(!metric){
      debug('Metric name required');
      return;
    }

    value = Number(value);
    if(!isFinite(value)){
      debug('Metric value is invalid');
      return;
    }

    if(count === null || count === undefined){ count = 1; }
    count = Number(count);
    if(!isFinite(count)){
      debug('Metric count is invalid');
      return;
    }

    if(!time){ time = Date.now(); }
    time = Math.round(Number(time) / 1000);

    var line = [type, metric, value, time, count].join(' ') + '\n';
    if(this.connected){
      this.socket.write(line);
    } else {
      if(!this.socket){ this.connect(); }
      if(this.queuedCalls.length > 1000){
        debug('Queue too large - dropping metric');
        return;
      }
      this.queuedCalls.push(line);
    }
  }

  noticeApiCallInner(type, time, duration, desc) {
    if(!this.enabled){ return; }
    if (!time) {
      time = Date.now();
    }
    time = Math.round(Number(time) / 1000);
    if(duration === null || duration === undefined){ duration = 0; }
    duration = Number(duration);
    if(!isFinite(duration)){
      debug('duration is invalid');
      return;
    }

    var line = [type, time, duration, desc].join(' ') + '\n';
    if (this.connected) {
      this.socket.write(line);
    }
    else {
      if (!this.socket) {
        this.connect();
      }
      if (this.queuedCalls.length > 1000) {
        debug('Queue too large - dropping notice event');
        return;
      }
      this.queuedCalls.push(line);
    }
  }

  increment(metric, value, time, count){
    if(value === 0){ return; }
    if(value === null || value === undefined){ value = 1; }
    this.apiCall('increment', metric, value, time, count);
  }

  gauge(metric, value, time, count){
    this.apiCall('gauge', metric, value, time, count);
  }

  notice(time, duration, description) {
    if (!time) {
    time = Date.now();
    }
     setImmediate(() => {
    this.noticeApiCallInner('notice', time, duration, description);
    });
  }

}

module.exports = Instrumental;
<|endoftext|>


<commit_before>var readline = require('readline'),
	pivotal = require('pivotal'),
	colors = require('colors'),
	exec = require('child_process').exec;

var ask = {
	/* Prompts for a pivotal API key until a non-blank string is entered,
	 * then stores the value in git local config. */
	pivotalAPIKey: function (callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});

		rl.question("Pivotal API key (https://www.pivotaltracker.com/profile): ", function (answer) {
			var trimmed = answer.trim();
			if(trimmed === "") {
				rl.write("You need to supply a key.")
				rl.close();
				ask.pivotalAPIKey(callback);
			}
			else {
				rl.close();
				exec('git config --local --add pivotal.apikey ' + trimmed, function (err, stdout, stderr) {
					if(err) {
						callback(new Error("Could not save to git config: " + stderr))
					}
					else {
						callback(trimmed);
					}
				});
			}
		});
	},

	/* prompts for a pivotal user name until a non-blank string is entered,
	 * then stores the value in git local config. */
	pivotalUserName: function (callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});

		rl.question("Pivotal user name: ", function (answer) {
			var trimmed = answer.trim();
			if(trimmed === "") {
				rl.write("You need to supply a user name.");
				rl.close();
				ask.pivotalUserName(callback);
			}
			else {
				rl.close();
				exec('git config --local --add pivotal.username ' + trimmed, function (err, stdout, stderr) {
					if(err) {
						callback(new Error("Could not save to git config: " + stderr))
					}
					else {
						callback(null, trimmed);
					}
				});
			}
		});
	},

	/* prompts for a pivotal project after displaying a list of projects,
	 * and saves in local git config */
	pivotalProject: function (apikey, callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});

		pivotal.useToken(apikey);

		pivotal.getProjects(function (err, res) {
			if(err) {
				throw err;
			}

			var projects;

			if(Object.prototype.toString.call( res.project ) === '[object Array]'){
				projects = res.project.map(function (project, index) {
					return {
						index: index + 1,
						id: ~~project.id,
						name: project.name
					}
				});
			}
			else{
				projects = [{
					index: 1,
					id: ~~res.project.id,
					name: res.project.name
				}];
			}

			if(projects.length === 0) {
				throw new Error("No projects found for " + apikey);
			}

			projects.forEach(function (project) {
				rl.write((project.index + ". " + project.name).cyan + '\n');
			});

			rl.question("Choose your project: ", function (answer) {
				var choice = ~~answer.trim();
				if(choice < 1 || choice > projects.length) {
					rl.write("Please enter a number between 1 and " + (projects.length) + "\n");
					rl.close();
					ask.pivotalProject(apikey, callback);
				}
				else {
					rl.close();
					exec('git config --local --replace-all pivotal.project "' + projects[choice - 1].id + '"', function (err, stdout, stderr) {
						if(err) {
							callback(new Error("Could not save to git config: " + stderr))
						}
						else {
							callback(null, projects[choice - 1].id);
						}
					});
				}
			});
		});
	},

	/* prompts for a story choice after displaying a list of stories,
	 * calls back with the chosen story */
 	pivotalStory: function (stories, callback) {
 		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});
 		var choices = stories.map(function (story, index) {
 			return {
				index: index + 1,
				id: story.id,
				name: story.name,
				estimate: story.estimate === undefined ? -1 : ~~story.estimate,
				state: story.current_state,
				type: story.story_type
			}
		})

		choices.forEach(function (story) {
			displayEstimate = (story.estimate < 0) ? "-" : (story.estimate).toString();
			var type = story.type.toUpperCase();
			if(type == "BUG") {
				type = ("B" + displayEstimate).red;
			}
			else if(type == "FEATURE") {
				type = ("F" + displayEstimate).yellow;
			}
			else if(type == "CHORE") {
				type = ("C" + displayEstimate).gray;
			}

			var state = story.state;
			if(state == "unstarted") {
				state = " " + state.green;
			}
			else if(state == "started") {
				state = " " + state.blue;
			}
			else if(state == "rejected") {
				state = " " + state.red;
			}
			else {
				state = " " + state.gray;
			}

			rl.write((story.index + ". ").cyan + type + " " + state + (" " + story.name).cyan + "\n");
		});

		rl.question("Choose a story: ", function (answer) {
			var choice = ~~answer.trim();
			if(choice < 1 || choice > stories.length) {
				rl.write("Please enter a number between 1 and " + (stories.length));
				rl.close();
				ask.pivotalStory(stories, callback)
			}
			else {
				rl.close();
				callback(null, choices[choice - 1])
			}
		});
	},

	branchName: function (story, callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout,
			completer: function (line) {
				var hits = completions.filter(function(c) { return c.indexOf(line) == 0 })
				// show all completions if none found
				return [hits.length ? hits : completions, line]
			}
		});

		var suggestedName = story.name.replace(/\s+/g, '-').toLowerCase();
		var split = suggestedName.split('-')
		var completions = split.map(function (segment, index) {
			return split.slice(0, index).join('-');
		});

		rl.question("branch name (" + suggestedName + "): ", function (answer) {
			var name = answer.trim() || suggestedName;
			name = name + '-' + story.id;
			rl.close();
			callback(null, name);
		})
	}
}

module.exports = ask;<commit_msg>remove dangerous chars from branch name<commit_after>var readline = require('readline'),
	pivotal = require('pivotal'),
	colors = require('colors'),
	exec = require('child_process').exec;

var ask = {
	/* Prompts for a pivotal API key until a non-blank string is entered,
	 * then stores the value in git local config. */
	pivotalAPIKey: function (callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});

		rl.question("Pivotal API key (https://www.pivotaltracker.com/profile): ", function (answer) {
			var trimmed = answer.trim();
			if(trimmed === "") {
				rl.write("You need to supply a key.")
				rl.close();
				ask.pivotalAPIKey(callback);
			}
			else {
				rl.close();
				exec('git config --local --add pivotal.apikey ' + trimmed, function (err, stdout, stderr) {
					if(err) {
						callback(new Error("Could not save to git config: " + stderr))
					}
					else {
						callback(trimmed);
					}
				});
			}
		});
	},

	/* prompts for a pivotal user name until a non-blank string is entered,
	 * then stores the value in git local config. */
	pivotalUserName: function (callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});

		rl.question("Pivotal user name: ", function (answer) {
			var trimmed = answer.trim();
			if(trimmed === "") {
				rl.write("You need to supply a user name.");
				rl.close();
				ask.pivotalUserName(callback);
			}
			else {
				rl.close();
				exec('git config --local --add pivotal.username ' + trimmed, function (err, stdout, stderr) {
					if(err) {
						callback(new Error("Could not save to git config: " + stderr))
					}
					else {
						callback(null, trimmed);
					}
				});
			}
		});
	},

	/* prompts for a pivotal project after displaying a list of projects,
	 * and saves in local git config */
	pivotalProject: function (apikey, callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});

		pivotal.useToken(apikey);

		pivotal.getProjects(function (err, res) {
			if(err) {
				throw err;
			}

			var projects;

			if(Object.prototype.toString.call( res.project ) === '[object Array]'){
				projects = res.project.map(function (project, index) {
					return {
						index: index + 1,
						id: ~~project.id,
						name: project.name
					}
				});
			}
			else{
				projects = [{
					index: 1,
					id: ~~res.project.id,
					name: res.project.name
				}];
			}

			if(projects.length === 0) {
				throw new Error("No projects found for " + apikey);
			}

			projects.forEach(function (project) {
				rl.write((project.index + ". " + project.name).cyan + '\n');
			});

			rl.question("Choose your project: ", function (answer) {
				var choice = ~~answer.trim();
				if(choice < 1 || choice > projects.length) {
					rl.write("Please enter a number between 1 and " + (projects.length) + "\n");
					rl.close();
					ask.pivotalProject(apikey, callback);
				}
				else {
					rl.close();
					exec('git config --local --replace-all pivotal.project "' + projects[choice - 1].id + '"', function (err, stdout, stderr) {
						if(err) {
							callback(new Error("Could not save to git config: " + stderr))
						}
						else {
							callback(null, projects[choice - 1].id);
						}
					});
				}
			});
		});
	},

	/* prompts for a story choice after displaying a list of stories,
	 * calls back with the chosen story */
 	pivotalStory: function (stories, callback) {
 		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});
 		var choices = stories.map(function (story, index) {
 			return {
				index: index + 1,
				id: story.id,
				name: story.name,
				estimate: story.estimate === undefined ? -1 : ~~story.estimate,
				state: story.current_state,
				type: story.story_type
			}
		})

		choices.forEach(function (story) {
			displayEstimate = (story.estimate < 0) ? "-" : (story.estimate).toString();
			var type = story.type.toUpperCase();
			if(type == "BUG") {
				type = ("B" + displayEstimate).red;
			}
			else if(type == "FEATURE") {
				type = ("F" + displayEstimate).yellow;
			}
			else if(type == "CHORE") {
				type = ("C" + displayEstimate).gray;
			}

			var state = story.state;
			if(state == "unstarted") {
				state = " " + state.green;
			}
			else if(state == "started") {
				state = " " + state.blue;
			}
			else if(state == "rejected") {
				state = " " + state.red;
			}
			else {
				state = " " + state.gray;
			}

			rl.write((story.index + ". ").cyan + type + " " + state + (" " + story.name).cyan + "\n");
		});

		rl.question("Choose a story: ", function (answer) {
			var choice = ~~answer.trim();
			if(choice < 1 || choice > stories.length) {
				rl.write("Please enter a number between 1 and " + (stories.length));
				rl.close();
				ask.pivotalStory(stories, callback)
			}
			else {
				rl.close();
				callback(null, choices[choice - 1])
			}
		});
	},

	branchName: function (story, callback) {
		var rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout,
			completer: function (line) {
				var hits = completions.filter(function(c) { return c.indexOf(line) == 0 })
				// show all completions if none found
				return [hits.length ? hits : completions, line]
			}
		});

		var suggestedName = story.name.replace(/\s+/g, '-')
			.replace(/[!\'\"]/g, '')
			.toLowerCase();
		var split = suggestedName.split('-')
		var completions = split.map(function (segment, index) {
			return split.slice(0, index).join('-');
		});

		rl.question("branch name (" + suggestedName + "): ", function (answer) {
			var name = answer.trim() || suggestedName;
			name = name + '-' + story.id;
			rl.close();
			callback(null, name);
		})
	}
}

module.exports = ask;<|endoftext|>


<commit_before>"use strict";

/*jslint bitwise: true*/

var expat = require('node-expat');
var nodefn = require('when/node/function');
var subprocess = require('child_process');
var util = require('util');
var when = require('when');
var BigNum = require('bignumber.js');

function communicate(cmd, args) {
    var deferred, stdout_deferred, stderr_deferred, process,
        stdout_buffer, stderr_buffer;

    deferred = when.defer();
    stdout_deferred = when.defer();
    stderr_deferred = when.defer();

    stdout_buffer = new Buffer(0);
    stderr_buffer = new Buffer(0);

    console.log(util.format('INFO spawning %s %j', cmd, args));
    process = subprocess.spawn(cmd, args);
    deferred.notify(process);

    process.stdout.on('data', function (data) {
        stdout_buffer = Buffer.concat([stdout_buffer, data]);
    });
    process.stderr.on('data', function (data) {
        stderr_buffer = Buffer.concat([stderr_buffer, data]);
    });

    process.stdout.on('end', function () {
        stdout_deferred.resolve(stdout_buffer.toString('utf8'));
    });
    process.stderr.on('end', function () {
        stderr_deferred.resolve(stderr_buffer.toString('utf8'));
    });

    process.on('exit', function (rc) {
        console.log(util.format('INFO %s %j finished with %d', cmd, args, rc));

        if (stdout_deferred.promise.inspect().state === 'pending') {
            stdout_deferred.resolve('');
        }

        if (stderr_deferred.promise.inspect().state === 'pending') {
            stderr_deferred.resolve('');
        }

        when.settle(
            [stdout_deferred.promise, stderr_deferred.promise]
        ).done(function (results) {
            if (rc !== 0) {
                deferred.reject(util.format(
                    'cmd %s %j failed with return code %d: [\n%s]',
                    cmd,
                    args,
                    rc,
                    results[1].value.toString()
                ));
                return;
            }

            console.log(util.format('INFO cmd %s %j has finished', cmd, args));

            deferred.resolve(
                [
                    results[0].state === 'fulfilled' ? results[0].value : '',
                    results[1].state === 'fulfilled' ? results[1].value : ''
                ]
            );
        });
    });

    return deferred.promise;
}

function version(optional_runner) {
    var run = optional_runner || communicate;

    function parse_version(version_str) {
        var first_line, match;

        first_line = version_str.split('\n')[0];

        match = first_line.match(/Ledger ([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?/);
        if (match) {
            return [match[1] | 0, 0 | match[2], 0 | match[3]];
        }

        throw util.format("cannot parse version '%s'", first_line);
    }

    return run('ledger', ['--version']).then(
        function (streams) {
            return parse_version(streams[0]);
        }
    );
}

function ledger_date_to_tuple(text) {
    var match = text.match(/([0-9]+)\/([0-9]+)\/([0-9]+)/);
    if (!match) {
        return;
    }

    return [match[1] | 0, match[2] | 0, match[3] | 0];
}

function amount(qty, commodity) {
    return {
        quantity: new BigNum(qty),
        commodity: commodity,
    };
}

function xml_stream(data) {
    var deferred = when.defer(),
        parser = new expat.Parser('UTF-8'),
        result = {
            transactions: [],
        },
        stack = [],
        curr;

    parser.on('startElement', function (name, attrs) {
        curr = {
            element: {
                name: name,
                attr: attrs
            },
        };
        curr.parent = stack.length > 0 ? stack[stack.length - 1] : curr;

        stack.push(curr);
    });

    parser.on('text', function (text) {
        var text_elements, prependif;

        text_elements = {
            date: true,
            payee: true,
            name: true,
            symbol: true,
            quantity: true
        };

        prependif =
            function (val, suffix) {
                return (val || '') + suffix;
            };

        if (text_elements[curr.element.name]) {
            curr.element.text = prependif(curr.element.text, text);
        }
    });

    parser.on('endElement', function () {
        var appendif, prev, version;

        appendif =
            function (val, appended) {
                var arr = val || [];
                arr.push(appended);
                return arr;
            };

        prev = stack.pop();
        curr = prev.parent;

        if (prev.element.name === 'transaction') {
            result.transactions.push({
                state: prev.element.attr.state,
                date: prev.element.attr.date,
                payee: prev.element.attr.payee,
                postings: prev.element.attr.postings,
            });
        } else if (prev.element.name === 'ledger' && curr === prev) {
            version = prev.element.attr.version;
            if (version !== '196608') {
                deferred.reject(util.format('untested version "%s"', version));
                return;
            }
        } else if (prev.element.name === 'posting') {
            prev.element.value = {
                account: prev.element.attr.account,
                amount: prev.element.amount,
            };
        } else if (prev.element.name === 'amount') {
            prev.element.value = amount(prev.element.quantity,
                                        prev.element.commodity);
        }

        if (curr.element.name === 'transaction') {
            if (prev.element.name === 'date') {
                curr.element.attr.date = ledger_date_to_tuple(prev.element.text);
                if (!curr.element.attr.date) {
                    deferred.reject(util.format('parse error at %j', prev));
                    return;
                }
            } else if (prev.element.name === 'payee') {
                curr.element.attr.payee = prev.element.text;
            } else if (prev.element.name === 'postings') {
                curr.element.attr.postings = prev.element.value;
            }
        } else if (curr.element.name === 'account' && prev.element.name === 'name') {
            curr.element.value = prev.element.text;
        } else if (curr.element.name === 'posting') {
            if (prev.element.name === 'account') {
                curr.element.attr.account = { name: prev.element.value };
            } else if (prev.element.name === 'post-amount') {
                curr.element.amount = prev.element.value;
            }
        } else if (curr.element.name === 'postings' && prev.element.name === 'posting') {
            curr.element.value = appendif(curr.element.value, prev.element.value);
        } else if (curr.element.name === 'post-amount' && prev.element.name === 'amount') {
            curr.element.value = prev.element.value;
        } else if (curr.element.name === 'commodity' && prev.element.name === 'symbol') {
            curr.element.value = prev.element.text;
        } else if (curr.element.name === 'amount' && prev.element.name === 'commodity') {
            curr.element.commodity = prev.element.value;
        } else if (curr.element.name === 'amount' && prev.element.name === 'quantity') {
            curr.element.quantity = new BigNum(prev.element.text);
        }

    });

    parser.on('error', function (err) {
        deferred.reject(err);
    });

    parser.on('close', function () {
        deferred.resolve(result);
    });

    parser.end(data);

    return deferred.promise;
}

function query(ledgerfile, args, optional_runner) {
    var run = optional_runner || communicate,
        params = ['-f', ledgerfile, 'xml'];

    if (args) {
        params = params.concat(args);
    }

    return run('ledger', params).then(function (streams) {
        return xml_stream(streams[0]);
    });
}

exports.version = version;
exports.query = query;
exports.amount = amount;
<commit_msg>fix missing input due to being too eager to close stdout/stderr<commit_after>"use strict";

/*jslint bitwise: true*/

var expat = require('node-expat');
var nodefn = require('when/node/function');
var subprocess = require('child_process');
var util = require('util');
var when = require('when');
var BigNum = require('bignumber.js');

function communicate(cmd, args) {
    var deferred, stdout_deferred, stderr_deferred, process,
        stdout_buffer, stderr_buffer;

    deferred = when.defer();
    stdout_deferred = when.defer();
    stderr_deferred = when.defer();

    stdout_buffer = new Buffer(0);
    stderr_buffer = new Buffer(0);

    console.log(util.format('INFO spawning %s %j', cmd, args));
    process = subprocess.spawn(cmd, args);
    deferred.notify(process);

    process.stdout.on('data', function (data) {
        stdout_buffer = Buffer.concat([stdout_buffer, data]);
    });
    process.stderr.on('data', function (data) {
        stderr_buffer = Buffer.concat([stderr_buffer, data]);
    });

    process.stdout.on('end', function () {
        stdout_deferred.resolve(stdout_buffer.toString('utf8'));
    });
    process.stderr.on('end', function () {
        stderr_deferred.resolve(stderr_buffer.toString('utf8'));
    });

    process.on('exit', function (rc) {
        console.log(util.format('INFO %s %j finished with %d', cmd, args, rc));

        when.all(
            [stdout_deferred.promise, stderr_deferred.promise]
        ).done(function (results) {
            if (rc !== 0) {
                deferred.reject(util.format(
                    'cmd %s %j failed with return code %d: [\n%s]',
                    cmd,
                    args,
                    rc,
                    results[1].value.toString()
                ));
                return;
            }

            console.log(util.format('INFO cmd %s %j has finished', cmd, args));

            deferred.resolve([ results[0], results[1] ]);
        });
    });

    return deferred.promise;
}

function version(optional_runner) {
    var run = optional_runner || communicate;

    function parse_version(version_str) {
        var first_line, match;

        first_line = version_str.split('\n')[0];

        match = first_line.match(/Ledger ([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?/);
        if (match) {
            return [match[1] | 0, 0 | match[2], 0 | match[3]];
        }

        throw util.format("cannot parse version '%s'", first_line);
    }

    return run('ledger', ['--version']).then(
        function (streams) {
            return parse_version(streams[0]);
        }
    );
}

function ledger_date_to_tuple(text) {
    var match = text.match(/([0-9]+)\/([0-9]+)\/([0-9]+)/);
    if (!match) {
        return;
    }

    return [match[1] | 0, match[2] | 0, match[3] | 0];
}

function amount(qty, commodity) {
    return {
        quantity: new BigNum(qty),
        commodity: commodity,
    };
}

function xml_stream(data) {
    var deferred = when.defer(),
        parser = new expat.Parser('UTF-8'),
        result = {
            transactions: [],
        },
        stack = [],
        curr;

    parser.on('startElement', function (name, attrs) {
        curr = {
            element: {
                name: name,
                attr: attrs
            },
        };
        curr.parent = stack.length > 0 ? stack[stack.length - 1] : curr;

        stack.push(curr);
    });

    parser.on('text', function (text) {
        var text_elements, prependif;

        text_elements = {
            date: true,
            payee: true,
            name: true,
            symbol: true,
            quantity: true
        };

        prependif =
            function (val, suffix) {
                return (val || '') + suffix;
            };

        if (text_elements[curr.element.name]) {
            curr.element.text = prependif(curr.element.text, text);
        }
    });

    parser.on('endElement', function () {
        var appendif, prev, version;

        appendif =
            function (val, appended) {
                var arr = val || [];
                arr.push(appended);
                return arr;
            };

        prev = stack.pop();
        curr = prev.parent;

        if (prev.element.name === 'transaction') {
            result.transactions.push({
                state: prev.element.attr.state,
                date: prev.element.attr.date,
                payee: prev.element.attr.payee,
                postings: prev.element.attr.postings,
            });
        } else if (prev.element.name === 'ledger' && curr === prev) {
            version = prev.element.attr.version;
            if (version !== '196608') {
                throw util.format('untested version "%s"', version);
            }
        } else if (prev.element.name === 'posting') {
            prev.element.value = {
                account: prev.element.attr.account,
                amount: prev.element.amount,
            };
        } else if (prev.element.name === 'amount') {
            prev.element.value = amount(prev.element.quantity,
                                        prev.element.commodity);
        }

        if (curr.element.name === 'transaction') {
            if (prev.element.name === 'date') {
                curr.element.attr.date = ledger_date_to_tuple(prev.element.text);
                if (!curr.element.attr.date) {
                    throw util.format('parse error at %j', prev);
                }
            } else if (prev.element.name === 'payee') {
                curr.element.attr.payee = prev.element.text;
            } else if (prev.element.name === 'postings') {
                curr.element.attr.postings = prev.element.value;
            }
        } else if (curr.element.name === 'account' && prev.element.name === 'name') {
            curr.element.value = prev.element.text;
        } else if (curr.element.name === 'posting') {
            if (prev.element.name === 'account') {
                curr.element.attr.account = { name: prev.element.value };
            } else if (prev.element.name === 'post-amount') {
                curr.element.amount = prev.element.value;
            }
        } else if (curr.element.name === 'postings' && prev.element.name === 'posting') {
            curr.element.value = appendif(curr.element.value, prev.element.value);
        } else if (curr.element.name === 'post-amount' && prev.element.name === 'amount') {
            curr.element.value = prev.element.value;
        } else if (curr.element.name === 'commodity' && prev.element.name === 'symbol') {
            curr.element.value = prev.element.text;
        } else if (curr.element.name === 'amount' && prev.element.name === 'commodity') {
            curr.element.commodity = prev.element.value;
        } else if (curr.element.name === 'amount' && prev.element.name === 'quantity') {
            curr.element.quantity = new BigNum(prev.element.text);
        }

    });

    parser.on('error', function (err) {
        throw err;
    });

    parser.on('end', function () {
        console.log('parsed query w/ count: ' + result.transactions.length);
        if (result.transactions.length === 0) {
            console.log('data: ' + data);
        }
        deferred.resolve(result);
    });

    // send data to parser
    parser.end(data);

    return deferred.promise;
}

function query(ledgerfile, args, optional_runner) {
    var run = optional_runner || communicate,
        params = ['-f', ledgerfile, 'xml'];

    if (args) {
        params = params.concat(args);
    }

    return run('ledger', params).then(function (streams) {
        return xml_stream(streams[0]);
    });
}

exports.version = version;
exports.query = query;
exports.amount = amount;
<|endoftext|>


<commit_before>var fs = require('fs');
var dirname = require('path').dirname;
var mkdirp = require('mkdirp');

module.exports = {
  readFile: function(path, callback) {
    fs.readFile(path, function(err, buffer) {
      if (err) {
        if (err.code == 'ENOENT') return callback();
        return callback(err);
      }
      callback(null, buffer);
    });
  },
  writeFile: function(path, buffer, callback) {
    mkdirp(dirname(path), function(err) {
      if (err) return callback(err);
      fs.writeFile(path, buffer, callback);
    });
  },
  readDir: function(path, callback) {
    fs.readdir(path, function(err, results) {
      if (err) {
        if (err.code == 'ENOENT') return callback();
        return callback(err);
      }
      return callback(null, results);
    });
  },
  readChunk: function(path, start, end, callback) {
    fs.open(path, 'r', function(err, fd) {
      if (err) {
        if (err.code == 'ENOENT') return callback();
        return callback(err);
      }
      if (end < 0) {
        end = fs.statSync(path)['size'] + end;
      }
      var chunkSize = end - start;
      var buf = new Buffer(chunkSize);
      fs.read(fd, buf, 0, chunkSize, start, function(err, bytesRead, buffer) {
        return callback(err, buffer);
      });
    });
  },
  rename: function(oldPath, newPath, callback) {
    return fs.rename(oldPath, newPath, callback);
  }
}<commit_msg>Close fd after read in fs-db<commit_after>var fs = require('fs');
var dirname = require('path').dirname;
var mkdirp = require('mkdirp');

module.exports = {
  readFile: function(path, callback) {
    fs.readFile(path, function(err, buffer) {
      if (err) {
        if (err.code == 'ENOENT') return callback();
        return callback(err);
      }
      callback(null, buffer);
    });
  },
  writeFile: function(path, buffer, callback) {
    mkdirp(dirname(path), function(err) {
      if (err) return callback(err);
      fs.writeFile(path, buffer, callback);
    });
  },
  readDir: function(path, callback) {
    fs.readdir(path, function(err, results) {
      if (err) {
        if (err.code == 'ENOENT') return callback();
        return callback(err);
      }
      return callback(null, results);
    });
  },
  readChunk: function(path, start, end, callback) {
    fs.open(path, 'r', function(err, fd) {
      if (err) {
        if (err.code == 'ENOENT') return callback();
        return callback(err);
      }
      if (end < 0) {
        end = fs.statSync(path)['size'] + end;
      }
      var chunkSize = end - start;
      var buf = new Buffer(chunkSize);
      fs.read(fd, buf, 0, chunkSize, start, function(err, bytesRead, buffer) {
        fs.close(fd, function(closeErr) {
          return callback(err || closeErr, buffer);
        });
      });
    });
  },
  rename: function(oldPath, newPath, callback) {
    return fs.rename(oldPath, newPath, callback);
  }
}<|endoftext|>


<commit_before>var map;

Map = {
  last_zoom_auto_set: 0,
  initialized: false,
  layers: {},
  open_marker: null,
  open_in_progress: false,

  clear_layer: function(lname) {
    Map.hide_layer(lname, true);
  },

  hide_layer: function(lname, clear) {
    var layer = Map.layers[lname];
    if (!layer) return;
    if (clear) { layer.empty = true; layer.mgr.clearMarkers(); }
    layer.mgr.hide();
    layer.unshown = true;
  },

  show_layer: function(lname, zoom) {
    var markers;
    var layer = Map.layers[lname];
    if (layer && layer.mgr && layer.mgr.visible()) return;
    if (!layer)       layer   = Map.layers[lname] = { unshown: true, empty: true };
    if (layer.empty)  markers = Map.layers[lname + '_f']().compact();
    if (zoom)         Map.set_bounds_from_lat_lngs(markers);
    if (!layer.mgr)   layer.mgr = new MarkerManager(map, {maxZoom: 19});

    if (layer.empty) {
      layer.mgr.addMarkers(markers, 0);
      layer.empty = false;
    }

    if (layer.unshown) {
      console.log('showing layer '+lname);
      layer.mgr.show();
      layer.unshown = false;
    }
  },

  add_to_layer: function(lname, markers) {
    var layer = Map.layers[lname];
    if (!layer)       layer   = Map.layers[lname] = { unshown: true, empty: true };
    if (!layer.mgr)   layer.mgr = new MarkerManager(map, {maxZoom: 19});

    console.log('addign '+ markers.length+' markers to layer '+lname);
    layer.mgr.addMarkers(markers, 0);
    layer.mgr.addMarkers(markers, Map.Gmap.getZoom());
    layer.empty = false;

    if (true || layer.unshown) {
      console.log('showing layer '+lname);
      layer.mgr.show();
      layer.unshown = false;
    }
  },

  open: function(marker, content) {
    if (this.open_marker == marker) {
      return Map.Gmap.updateCurrentTab(function(tab){ tab.contentElem = content; });
    }
    this.open_marker = marker;
    this.open_in_progress = true;
    // alert('opening new window');
    this.open_marker.openInfoWindow(content, {noCloseOnClick: true});
  },

  // public

  // add: function(markers) {
  //   markers = markers.compact();
  //   $.each(markers, function(){ Map.Gmap.addOverlay(this); });
  // },

  // replace_marker: function(old_marker, new_marker) {
  //   if (!Map.Gmap) return;  // for disconnected testing
  //   if (old_marker) Map.Gmap.removeOverlay(old_marker);
  //   if (new_marker) Map.Gmap.addOverlay(new_marker);
  // },

  // private

  establish: function(){
    var map_div = $("#map_div");
    map = Map.Gmap = new GMap2(map_div[0], {
      mapTypes: [G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP, G_PHYSICAL_MAP]
    });
    // Map.Gmap.enableContinuousZoom();
    Map.Gmap.enableScrollWheelZoom();
    new GKeyboardHandler(Map.Gmap);
    var bRight = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(29,5));
    var bRightSnug = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(5,5));
    var bLeftFurther = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(160,5));
    Map.Gmap.addControl(new GSmallZoomControl(), bRightSnug);
    Map.Gmap.addControl(new GMenuMapTypeControl(), bRight);
    GEvent.addListener(map, "infowindowopen", function(){ Map.open_in_progress = false; });
    GEvent.addListener(map, "click", function(overlay, latlng) {
      if (!latlng) return;
      This.click_latlng = latlng;
      This.click_lat = latlng.lat();
      This.click_lng = latlng.lng();
      go('#map_clicked');
    });
  },

  bounds_including_all_points: function(points) {
    var bounds = new GLatLngBounds(points[0], points[0]);
    for (var i=1; i < points.length; i++) bounds.extend(points[i]);
    return bounds;
  },

  median_of_all_points: function(points) {
    var lat = points.map(function(x){ return x.lat(); }).median();
    var lng = points.map(function(x){ return x.lng(); }).median();
    return new GLatLng(lat, lng);
  },

  set_bounds_from_lat_lngs: function(items) {
    if (!Map.Gmap) return;  // for disconnected testing
    var latlngs = items.map(function(x){
      if(x.lat && x.lng) return new GLatLng(x.lat, x.lng);
      if(x.getLatLng) return x.getLatLng();
    }).compact();
    if (latlngs.length == 0) { alert('map reset problem: no items'); return; }

    var bounds = Map.bounds_including_all_points(latlngs);
    var center = bounds.getCenter();
    var zoom = Map.Gmap.getBoundsZoomLevel(bounds);
    if (zoom > 3 && zoom < 12) {
      center = Map.median_of_all_points(latlngs);
      zoom = 14;
    }

    Map.Gmap.setCenter(center, zoom);
    if (!Map.initialized) {
      trigger('map_init', Map.Gmap);
      Map.initialized = true;
    }
    Map.last_zoom_auto_set = zoom;
  }

};
<commit_msg>fixed a bug in returning to worldwide view<commit_after>var map;

Map = {
  last_zoom_auto_set: 0,
  initialized: false,
  layers: {},
  open_marker: null,
  open_in_progress: false,

  clear_layer: function(lname) {
    Map.hide_layer(lname, true);
  },

  hide_layer: function(lname, clear) {
    var layer = Map.layers[lname];
    if (!layer) return;
    if (clear) { layer.empty = true; layer.mgr.clearMarkers(); }
    layer.mgr.hide();
    layer.unshown = true;
  },

  show_layer: function(lname, zoom) {
    var markers;
    var layer = Map.layers[lname];
    if (layer && layer.mgr && layer.mgr.visible()) return;
    if (!layer)       layer   = Map.layers[lname] = { unshown: true, empty: true };
    if (layer.empty)  layer.markers = Map.layers[lname + '_f']().compact();
    if (!layer.markers && zoom) alert('no markers for zoom: ' + lname);
    if (layer.markers && zoom)         Map.set_bounds_from_lat_lngs(layer.markers);
    if (!layer.mgr)   layer.mgr = new MarkerManager(map, {maxZoom: 19});

    if (layer.empty) {
      layer.mgr.addMarkers(layer.markers, 0);
      layer.empty = false;
    }

    if (layer.unshown) {
      console.log('showing layer '+lname);
      layer.mgr.show();
      layer.unshown = false;
    }
  },

  add_to_layer: function(lname, markers) {
    var layer = Map.layers[lname];
    if (!layer)       layer   = Map.layers[lname] = { unshown: true, empty: true };
    if (!layer.mgr)   layer.mgr = new MarkerManager(map, {maxZoom: 19});

    console.log('addign '+ markers.length+' markers to layer '+lname);
    layer.mgr.addMarkers(markers, 0);
    layer.mgr.addMarkers(markers, Map.Gmap.getZoom());
    layer.empty = false;

    if (true || layer.unshown) {
      console.log('showing layer '+lname);
      layer.mgr.show();
      layer.unshown = false;
    }
  },

  open: function(marker, content) {
    if (this.open_marker == marker) {
      return Map.Gmap.updateCurrentTab(function(tab){ tab.contentElem = content; });
    }
    this.open_marker = marker;
    this.open_in_progress = true;
    // alert('opening new window');
    this.open_marker.openInfoWindow(content, {noCloseOnClick: true});
  },

  // public

  // add: function(markers) {
  //   markers = markers.compact();
  //   $.each(markers, function(){ Map.Gmap.addOverlay(this); });
  // },

  // replace_marker: function(old_marker, new_marker) {
  //   if (!Map.Gmap) return;  // for disconnected testing
  //   if (old_marker) Map.Gmap.removeOverlay(old_marker);
  //   if (new_marker) Map.Gmap.addOverlay(new_marker);
  // },

  // private

  establish: function(){
    var map_div = $("#map_div");
    map = Map.Gmap = new GMap2(map_div[0], {
      mapTypes: [G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP, G_PHYSICAL_MAP]
    });
    // Map.Gmap.enableContinuousZoom();
    Map.Gmap.enableScrollWheelZoom();
    new GKeyboardHandler(Map.Gmap);
    var bRight = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(29,5));
    var bRightSnug = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(5,5));
    var bLeftFurther = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(160,5));
    Map.Gmap.addControl(new GSmallZoomControl(), bRightSnug);
    Map.Gmap.addControl(new GMenuMapTypeControl(), bRight);
    GEvent.addListener(map, "infowindowopen", function(){ Map.open_in_progress = false; });
    GEvent.addListener(map, "click", function(overlay, latlng) {
      if (!latlng) return;
      This.click_latlng = latlng;
      This.click_lat = latlng.lat();
      This.click_lng = latlng.lng();
      go('#map_clicked');
    });
  },

  bounds_including_all_points: function(points) {
    var bounds = new GLatLngBounds(points[0], points[0]);
    for (var i=1; i < points.length; i++) bounds.extend(points[i]);
    return bounds;
  },

  median_of_all_points: function(points) {
    var lat = points.map(function(x){ return x.lat(); }).median();
    var lng = points.map(function(x){ return x.lng(); }).median();
    return new GLatLng(lat, lng);
  },

  set_bounds_from_lat_lngs: function(items) {
    if (!Map.Gmap) return;  // for disconnected testing
    var latlngs = items.map(function(x){
      if(x.lat && x.lng) return new GLatLng(x.lat, x.lng);
      if(x.getLatLng) return x.getLatLng();
    }).compact();
    if (latlngs.length == 0) { alert('map reset problem: no items'); return; }

    var bounds = Map.bounds_including_all_points(latlngs);
    var center = bounds.getCenter();
    var zoom = Map.Gmap.getBoundsZoomLevel(bounds);
    if (zoom > 3 && zoom < 12) {
      center = Map.median_of_all_points(latlngs);
      zoom = 14;
    }

    Map.Gmap.setCenter(center, zoom);
    if (!Map.initialized) {
      trigger('map_init', Map.Gmap);
      Map.initialized = true;
    }
    Map.last_zoom_auto_set = zoom;
  }

};
<|endoftext|>