<commit_before>/**
 * @file TLS certificate tools.
 * @author zdying
 */

'use strict';

var fs = require('fs');
var os = require('os');
var https = require('https');
var path = require('path');
var forge = require('node-forge');
var pki = forge.pki;
var md5 = forge.md.md5;
var mkdirp = require('./mkdirp');
var dirtool = require('../helpers/dirTool');
var certDir = dirtool.getCertificateDir();
var defaultAttrs = [
  {
    name: 'countryName',
    value: 'CN'
  },
  {
    name: 'stateOrProvinceName',
    value: 'Bei Jing'
  },
  {
    name: 'localityName',
    value: 'Hai Dian'
  },
  {
    name: 'organizationName',
    value: 'Hiproxy'
  },
  {
    name: 'organizationalUnitName',
    value: 'Development'
  }
];
var DEFAULT_CA_NAME = 'Hiproxy-Custom-CA-' + os.hostname().replace(/[._]/g, '-');
var _cache = {};

mkdirp(certDir);

module.exports = {
  /**
   * 获取CA证书，优选读取已经存在的证书，如果不存在会自动创建
   * @param {String} [CAName] CA名称
   */
  getCACertificate: function(CAName) {
    CAName = CAName || DEFAULT_CA_NAME;
    var fileName = getFileNameByCN(CAName);
    var certInfo = this.getCertificateByFileName(fileName);
    if (certInfo) {
      return certInfo;
    } else {
      log.debug('create new CA certificate, CA name:', CAName);
      var attrs = [
        {
          name: 'commonName',
          value: CAName
        }
      ].concat(defaultAttrs);
      var exts = [
        {
          name: 'basicConstraints',
          critical: true,
          cA: true
        },
        {
          name: 'keyUsage',
          critical: true,
          keyCertSign: true
        },
        {
          name: 'subjectKeyIdentifier'
        }
      ];
      return this._createCert(attrs, attrs, exts, null, CAName);
    }
  },

  /**
   * 创建域名证书
   * @param {String} domain
   * @param {String} CAName
   * @param {Cert} certInfo
   */
  getDomainCertificate: function(domain, CAName, certInfo) {
    var promise = _cache[domain];
    var _certInfoPromise = null;
    var hasCertInfo = certInfo && typeof certInfo === 'object';
    var self = this;

    if (!promise) {
      _certInfoPromise = hasCertInfo ? Promise.resolve(certInfo) : this.getCertInfoByHostsName(domain);

      promise = _certInfoPromise.then(function(certInfo) {
        var caCert = self.getCACertificate(CAName);
        var CN = (certInfo.subject && certInfo.subject.CN) || domain;
        var fileName = getFileNameByCN(CN);
        var cachedCert = self.getCertificateByFileName(fileName);
        var cert = cachedCert;

        if (!cachedCert) {
          log.debug('No cached cetrificate', CN ? 'CN:' + CN : '');
          // cert = self._createCertificate(caCert, domain, null, certInfo);
          cert = self._createDomainCert(caCert, domain, certInfo);
        } else {
          log.debug('Use cached certificate', CN ? 'CN:' + CN : '');
        }

        return cert;
      });
      _cache[domain] = promise;
    } else {
      log.debug(
        domain,
        'certificate is created or creating, return the cached promise'
      );
    }

    return promise;
  },

    /**
   * 读取证书文件，转换成证书
   * @param {String} fileName 文件名称
   */
  getCertificateByFileName: function(fileName) {
    var filePath = path.join(certDir, fileName);
    var keyPath = filePath + '.key';
    var crtPath = filePath + '.pem';
    var keyContent = '';
    var crtContent = '';
    var certificate = null;
    var privateKey = null;

    if (fs.existsSync(keyPath) && fs.existsSync(crtPath)) {
      try {
        keyContent = fs.readFileSync(keyPath);
        crtContent = fs.readFileSync(crtPath);
        certificate = pki.certificateFromPem(crtContent);
        privateKey = pki.privateKeyFromPem(keyContent);

        log.debug('get certificate file:', [keyPath, crtPath]);

        return {
          privateKey: privateKey,
          publicKey: certificate.publicKey,
          certificate: certificate,
          certificatePem: crtContent,
          privateKeyPem: keyContent
        };
      } catch (e) {
        return null;
      }
    } else {
      log.debug('certificate file:', [keyPath, crtPath], 'not exists.');
      return null;
    }
  },

  /**
   * 获取线上证书的信息
   */
  getCertInfoByHostsName: function(hostname, callback) {
    return new Promise(function(resolve, reject) {
      var options = {
        host: hostname,
        port: 443,
        method: 'GET'
      };

      var req = https.request(options, function(res) {
        resolve(res.connection.getPeerCertificate());
      });

      req.on('error', function(err) {
        log.error('get certificate info for', hostname, 'error: ', err);
        resolve({});
      });

      req.end();
    });
  },

  /**
   * 创建证书（具体是CA还是普通域名证书，这里不关心，取决于传递的参数）
   * 证书过期时间为100年
   * @param {Array} attrs
   * @param {Array} issuers
   * @param {Array} exts
   * @param {Cert}  caCert
   * @param {String} domain
   */
  _createCert(attrs, issuers, exts, caCert, domain) {
    log.debug('Generate new certificate:', domain);

    var keys = pki.rsa.generateKeyPair(1024);
    var cert = pki.createCertificate();
    var certId = md5.create().update(domain).digest().toHex();

    cert.publicKey = keys.publicKey;
    cert.serialNumber = certId;
    cert.validity.notBefore = new Date();
    cert.validity.notAfter = new Date();
    cert.validity.notAfter.setFullYear(
      cert.validity.notAfter.getFullYear() + 100
    );

    cert.setSubject(attrs);
    cert.setIssuer(issuers);
    cert.setExtensions(exts);
    cert.sign((caCert || keys).privateKey, forge.md.sha256.create());

    var certPem = pki.certificateToPem(cert);
    var keyPem = pki.privateKeyToPem(keys.privateKey);
    var pubKeyPem = pki.publicKeyToPem(keys.publicKey);

    // fs.writeFile(
    //   '/Users/zdying/.hiproxy/cert/' + domain + '.key',
    //   keyPem,
    //   function() {}
    // );
    // fs.writeFile(
    //   '/Users/zdying/.hiproxy/cert/' + domain + '.pem',
    //   certPem,
    //   function() {}
    // );

    var fileName = getFileNameByCN(domain);
    writeFile(fileName + '.key', certDir, keyPem);
    writeFile(fileName + '.pem', certDir, certPem);

    return {
      privateKey: keys.privateKey,
      publicKey: keys.publicKey,
      certificate: cert,
      privateKeyPem: keyPem,
      publicKeyPem: pubKeyPem,
      certificatePem: certPem
    };
  },

  _createDomainCert(caCert, domain, certInfo) {
    var attrs = [
      {
        name: 'commonName',
        value: domain
      }
    ].concat(defaultAttrs);
    var issuers = caCert.certificate.issuer.attributes;
    var exts = [
      {
        name: 'basicConstraints',
        critical: true,
        cA: false
      },
      {
        name: 'keyUsage',
        critical: true,
        digitalSignature: true,
        contentCommitment: true,
        keyEncipherment: true,
        dataEncipherment: true,
        keyAgreement: true,
        keyCertSign: true,
        cRLSign: true,
        encipherOnly: true,
        decipherOnly: true
      },
      {
        name: 'subjectKeyIdentifier'
      },
      {
        name: 'extKeyUsage',
        serverAuth: true,
        clientAuth: true,
        codeSigning: true,
        emailProtection: true,
        timeStamping: true
      },
      {
        name: 'authorityKeyIdentifier'
      },
      {
        name: 'subjectAltName',
        altNames: [
          {
            type: 6, // URI
            value: 'http://hiproxy.org/'
          }
        ]
      }
    ];

    var sanExt = exts[exts.length - 1];
    var hasSubjectAltName = certInfo && typeof certInfo.subjectaltname === 'string';
    var subjectaltname = hasSubjectAltName ? certInfo.subjectaltname.split(/,\s*/) : ['DNS:' + domain];
    var has127 = false;

    subjectaltname.forEach(function(sn) {
      var info = sn.split(':');
      var map = { IP: 7, DNS: 2 };
      var type = map[info[0]];
      var obj = {};

      if (type) {
        obj.type = type;
        obj[type === 7 ? 'ip' : 'value'] = info[1];
        sanExt.altNames.push(obj);

        if (info[1] === '127.0.0.1') {
          has127 = true;
        }
      }
    });

    if (domain === 'localhost' && !has127) {
      sanExt.altNames.push({
        type: 7,
        ip: '127.0.0.1'
      });
    }

    return this._createCert(attrs, issuers, exts, caCert, domain);
  }
};

/* istanbul ignore next */
function writeFile(fileName, basedir, content) {
  fs.writeFile(
    path.join(basedir, fileName),
    content.replace(/\r\n/g, '\n'),
    function(err) {
      if (err) {
        log.error(err);
      }
    }
  );
}

/* istanbul ignore next */
function getFileNameByCN(CN) {
  return CN.replace(/\s+/g, '_').replace(/\*\./, '');
}

// test
// var log = {debug: function(){}};
// var tool = module.exports;
// var cert = tool.createCertificate('www.fuck-you.com');
// console.log(cert);
<commit_msg>update key length to 2048<commit_after>/**
 * @file TLS certificate tools.
 * @author zdying
 */

'use strict';

var fs = require('fs');
var os = require('os');
var https = require('https');
var path = require('path');
var forge = require('node-forge');
var pki = forge.pki;
var md5 = forge.md.md5;
var mkdirp = require('./mkdirp');
var dirtool = require('../helpers/dirTool');
var certDir = dirtool.getCertificateDir();
var defaultAttrs = [
  {
    name: 'countryName',
    value: 'CN'
  },
  {
    name: 'stateOrProvinceName',
    value: 'Bei Jing'
  },
  {
    name: 'localityName',
    value: 'Hai Dian'
  },
  {
    name: 'organizationName',
    value: 'Hiproxy'
  },
  {
    name: 'organizationalUnitName',
    value: 'Development'
  }
];
var DEFAULT_CA_NAME = 'Hiproxy-Custom-CA-' + os.hostname().replace(/[._]/g, '-');
var _cache = {};

mkdirp(certDir);

module.exports = {
  /**
   * 获取CA证书，优选读取已经存在的证书，如果不存在会自动创建
   * @param {String} [CAName] CA名称
   */
  getCACertificate: function(CAName) {
    CAName = CAName || DEFAULT_CA_NAME;
    var fileName = getFileNameByCN(CAName);
    var certInfo = this.getCertificateByFileName(fileName);
    if (certInfo) {
      return certInfo;
    } else {
      log.debug('create new CA certificate, CA name:', CAName);
      var attrs = [
        {
          name: 'commonName',
          value: CAName
        }
      ].concat(defaultAttrs);
      var exts = [
        {
          name: 'basicConstraints',
          critical: true,
          cA: true
        },
        {
          name: 'keyUsage',
          critical: true,
          keyCertSign: true
        },
        {
          name: 'subjectKeyIdentifier'
        }
      ];
      return this._createCert(attrs, attrs, exts, null, CAName);
    }
  },

  /**
   * 创建域名证书
   * @param {String} domain
   * @param {String} CAName
   * @param {Cert} certInfo
   */
  getDomainCertificate: function(domain, CAName, certInfo) {
    var promise = _cache[domain];
    var _certInfoPromise = null;
    var hasCertInfo = certInfo && typeof certInfo === 'object';
    var self = this;

    if (!promise) {
      _certInfoPromise = hasCertInfo ? Promise.resolve(certInfo) : this.getCertInfoByHostsName(domain);

      promise = _certInfoPromise.then(function(certInfo) {
        var caCert = self.getCACertificate(CAName);
        var CN = (certInfo.subject && certInfo.subject.CN) || domain;
        var fileName = getFileNameByCN(CN);
        var cachedCert = self.getCertificateByFileName(fileName);
        var cert = cachedCert;

        if (!cachedCert) {
          log.debug('No cached cetrificate', CN ? 'CN:' + CN : '');
          // cert = self._createCertificate(caCert, domain, null, certInfo);
          cert = self._createDomainCert(caCert, domain, certInfo);
        } else {
          log.debug('Use cached certificate', CN ? 'CN:' + CN : '');
        }

        return cert;
      });
      _cache[domain] = promise;
    } else {
      log.debug(
        domain,
        'certificate is created or creating, return the cached promise'
      );
    }

    return promise;
  },

    /**
   * 读取证书文件，转换成证书
   * @param {String} fileName 文件名称
   */
  getCertificateByFileName: function(fileName) {
    var filePath = path.join(certDir, fileName);
    var keyPath = filePath + '.key';
    var crtPath = filePath + '.pem';
    var keyContent = '';
    var crtContent = '';
    var certificate = null;
    var privateKey = null;

    if (fs.existsSync(keyPath) && fs.existsSync(crtPath)) {
      try {
        keyContent = fs.readFileSync(keyPath);
        crtContent = fs.readFileSync(crtPath);
        certificate = pki.certificateFromPem(crtContent);
        privateKey = pki.privateKeyFromPem(keyContent);

        log.debug('get certificate file:', [keyPath, crtPath]);

        return {
          privateKey: privateKey,
          publicKey: certificate.publicKey,
          certificate: certificate,
          certificatePem: crtContent,
          privateKeyPem: keyContent
        };
      } catch (e) {
        return null;
      }
    } else {
      log.debug('certificate file:', [keyPath, crtPath], 'not exists.');
      return null;
    }
  },

  /**
   * 获取线上证书的信息
   */
  getCertInfoByHostsName: function(hostname, callback) {
    return new Promise(function(resolve, reject) {
      var options = {
        host: hostname,
        port: 443,
        method: 'GET'
      };

      var req = https.request(options, function(res) {
        resolve(res.connection.getPeerCertificate());
      });

      req.on('error', function(err) {
        log.error('get certificate info for', hostname, 'error: ', err);
        resolve({});
      });

      req.end();
    });
  },

  /**
   * 创建证书（具体是CA还是普通域名证书，这里不关心，取决于传递的参数）
   * 证书过期时间为100年
   * @param {Array} attrs
   * @param {Array} issuers
   * @param {Array} exts
   * @param {Cert}  caCert
   * @param {String} domain
   */
  _createCert(attrs, issuers, exts, caCert, domain) {
    log.debug('Generate new certificate:', domain);

    var keys = pki.rsa.generateKeyPair(2048);
    var cert = pki.createCertificate();
    var certId = md5.create().update(domain).digest().toHex();

    cert.publicKey = keys.publicKey;
    cert.serialNumber = certId;
    cert.validity.notBefore = new Date();
    cert.validity.notAfter = new Date();
    cert.validity.notAfter.setFullYear(
      cert.validity.notAfter.getFullYear() + 100
    );

    cert.setSubject(attrs);
    cert.setIssuer(issuers);
    cert.setExtensions(exts);
    cert.sign((caCert || keys).privateKey, forge.md.sha256.create());

    var certPem = pki.certificateToPem(cert);
    var keyPem = pki.privateKeyToPem(keys.privateKey);
    var pubKeyPem = pki.publicKeyToPem(keys.publicKey);

    // fs.writeFile(
    //   '/Users/zdying/.hiproxy/cert/' + domain + '.key',
    //   keyPem,
    //   function() {}
    // );
    // fs.writeFile(
    //   '/Users/zdying/.hiproxy/cert/' + domain + '.pem',
    //   certPem,
    //   function() {}
    // );

    var fileName = getFileNameByCN(domain);
    writeFile(fileName + '.key', certDir, keyPem);
    writeFile(fileName + '.pem', certDir, certPem);

    return {
      privateKey: keys.privateKey,
      publicKey: keys.publicKey,
      certificate: cert,
      privateKeyPem: keyPem,
      publicKeyPem: pubKeyPem,
      certificatePem: certPem
    };
  },

  _createDomainCert(caCert, domain, certInfo) {
    var attrs = [
      {
        name: 'commonName',
        value: domain
      }
    ].concat(defaultAttrs);
    var issuers = caCert.certificate.issuer.attributes;
    var exts = [
      {
        name: 'basicConstraints',
        critical: true,
        cA: false
      },
      {
        name: 'keyUsage',
        critical: true,
        digitalSignature: true,
        contentCommitment: true,
        keyEncipherment: true,
        dataEncipherment: true,
        keyAgreement: true,
        keyCertSign: true,
        cRLSign: true,
        encipherOnly: true,
        decipherOnly: true
      },
      {
        name: 'subjectKeyIdentifier'
      },
      {
        name: 'extKeyUsage',
        serverAuth: true,
        clientAuth: true,
        codeSigning: true,
        emailProtection: true,
        timeStamping: true
      },
      {
        name: 'authorityKeyIdentifier'
      },
      {
        name: 'subjectAltName',
        altNames: [
          {
            type: 6, // URI
            value: 'http://hiproxy.org/'
          }
        ]
      }
    ];

    var sanExt = exts[exts.length - 1];
    var hasSubjectAltName = certInfo && typeof certInfo.subjectaltname === 'string';
    var subjectaltname = hasSubjectAltName ? certInfo.subjectaltname.split(/,\s*/) : ['DNS:' + domain];
    var has127 = false;

    subjectaltname.forEach(function(sn) {
      var info = sn.split(':');
      var map = { IP: 7, DNS: 2 };
      var type = map[info[0]];
      var obj = {};

      if (type) {
        obj.type = type;
        obj[type === 7 ? 'ip' : 'value'] = info[1];
        sanExt.altNames.push(obj);

        if (info[1] === '127.0.0.1') {
          has127 = true;
        }
      }
    });

    if (domain === 'localhost' && !has127) {
      sanExt.altNames.push({
        type: 7,
        ip: '127.0.0.1'
      });
    }

    return this._createCert(attrs, issuers, exts, caCert, domain);
  }
};

/* istanbul ignore next */
function writeFile(fileName, basedir, content) {
  fs.writeFile(
    path.join(basedir, fileName),
    content.replace(/\r\n/g, '\n'),
    function(err) {
      if (err) {
        log.error(err);
      }
    }
  );
}

/* istanbul ignore next */
function getFileNameByCN(CN) {
  return CN.replace(/\s+/g, '_').replace(/\*\./, '');
}

// test
// var log = {debug: function(){}};
// var tool = module.exports;
// var cert = tool.createCertificate('www.fuck-you.com');
// console.log(cert);
<|endoftext|>


<commit_before>openerp.suvit_web_tree = function(instance, local) {
  var QWeb = instance.web.qweb;
  var _t = instance.web._t;
  var _lt = instance.web._lt;

  /********* Custom domain for List & Tree Views in same Action ********/
  instance.web.FormView.include({
      init: function(parent, dataset, view_id, options) {
        var self = this;
        this._super(parent, dataset, view_id, options);
        if (self.dataset.context && self.dataset.context.tree_ids && self.dataset.context.tree_ids.length) {
            self.dataset.ids = self.dataset.context.tree_ids;
            self.dataset.index = self.dataset.ids.indexOf(self.dataset.context.active_id);
        }
      },
      on_button_save: function(e) {
          var self = this;
          _.each(this.ViewManager.ActionManager.breadcrumbs, function(br){
            br.need_update = true;
          });

          return self._super(e).then(function(){
              if (self.ViewManager.views.tree)
                self.ViewManager.views.tree.controller.switch_mode()
          });
      },
      on_button_create: function() {
          var self = this;
          self._super();
          if (self.ViewManager.views.tree)
            self.ViewManager.views.tree.controller.switch_mode()
      }
  });

  instance.web.TreeView.include({
    init: function (parent, dataset, view_id, options) {
        if (parent.action && parent.action.context.tree_domain){
          var domain = new instance.web.CompoundDomain(dataset.domain, parent.action.context.tree_domain);
          dataset = new instance.web.DataSetSearch(this, parent.action.res_model, dataset.context, domain);
        }
        this._super(parent, dataset, view_id, options);
    },
    switch_mode: function () {
      this.$el.find(".oe-treeview-table > tbody").empty();
      _(this.fields_view.arch.children).each(function (field) {
          if (field.attrs.modifiers && typeof(field.attrs.modifiers) == 'object') {
              field.attrs.modifiers = JSON.stringify(field.attrs.modifiers);
          }
      });
      this.view_loading(this.fields_view);
    },
    hook_row_click: function () {
      this.$el.undelegate('.treeview-tr', 'click');
      this._super();
    },

    getdata: function (id, children_ids) {
        // do not getdata twice, this class stop loading
        this.$el.find('#treerow_' + id).addClass('oe_open');

        var self = this;

        self.dataset.read_ids(children_ids, this.fields_list()).done(function(records) {
            _(records).each(function (record) {
                self.records[record.id] = record;
            });
            var $curr_node = self.$el.find('#treerow_' + id);
            var children_rows = QWeb.render('TreeView.rows', {
                'records': records,
                'children_field': self.children_field,
                'fields_view': self.fields_view.arch.children,
                'fields': self.fields,
                'level': $curr_node.data('level') || 0,
                'render': instance.web.format_value,
                'color_for': self.color_for,
                'row_parent_id': id
            });
            if ($curr_node.length) {
                $curr_node.addClass('oe_open');
                $curr_node.after(children_rows);
            } else {
                self.$el.find('tbody').html(children_rows);
            }
        }).then(function(){
          if (self.ViewManager.action && self.ViewManager.action.id) {
            view_id = self.ViewManager.action.id;
            var open_trees = JSON.parse(localStorage.getItem('open_trees') || '{}');
                if (!open_trees[view_id]) {open_trees[view_id] = {};}
            open_trees[view_id][id] = true;
            localStorage["open_trees"] = JSON.stringify(open_trees);
            for(k in open_trees[view_id]){
              if (open_trees[view_id][k]) {
                $('#treerow_'+k+':not(.oe_open) .treeview-tr').click();
              }
            }
          }
        });
    },
    activate: function(id) {
      if (this.ViewManager.ActionManager) {
        parent = false;
        for (i in this.records) {
          if (_.indexOf(this.records[i].child_ids, id)+1) {
            parent = i;
            break;
          }
        }
        if (parent) {
          our_ids = this.records[parent].child_ids
        } else {
          our_ids = this.dataset.ids
        }
        this.ViewManager.ActionManager.tree_context = {
          tree_ids: our_ids
        };
      }
      this._super(id);
    },

    showcontent: function (curnode,record_id, show) {
      this._super(curnode,record_id, show);
      if (this.ViewManager && this.ViewManager.action) {
        view_id = this.ViewManager.action.id;
        var open_trees = JSON.parse(localStorage.getItem('open_trees') || '{}');
        if (!open_trees[view_id]) {open_trees[view_id] = {};}
        open_trees[view_id][record_id] = show;
        localStorage["open_trees"] = JSON.stringify(open_trees);
      }
    },
  });
  instance.web.ActionManager.include({
    select_breadcrumb: function(index, subindex) {
      var self = this;
      var item = this.breadcrumbs[index];
      if (item.widget.views.tree && item.need_update) {
        item.need_update=false;
        item.widget.views.tree.controller.switch_mode();
      }
      return this._super(index, subindex);
    },
    do_action: function(action, options) {
      if (this.tree_context) {
        action.context.tree_ids = this.tree_context.tree_ids;
      }
      this._super(action, options);
    }
  });

  /********* Many2Many Tree Field ********/
  local.Many2ManyTreeField = instance.web.form.FieldMany2Many.extend({
    initialize_content: function() {
        if (!(this.field.type == 'many2many' || this.field.type == 'one2many'))
            return this._super();
        this.list_view = new instance.web.TreeView(this, this.dataset, false, {
                    'addable': false,
                    'deletable': false,
                    'selectable': false,
                    'sortable': false,
                    'reorderable': false,
                    'import_enabled': false,
            });
        this.$el.empty();
        this.list_view.appendTo(this.$el);
    },
    render_value: function() {
      this.initialize_content();
      return this._super();
    }
  });

  instance.web.form.widgets.add('many2many_tree', 'instance.suvit_web_tree.Many2ManyTreeField');
};
<commit_msg>temp comment tree_ids set under dataset<commit_after>openerp.suvit_web_tree = function(instance, local) {
  var QWeb = instance.web.qweb;
  var _t = instance.web._t;
  var _lt = instance.web._lt;

  /********* Custom domain for List & Tree Views in same Action ********/
  instance.web.FormView.include({
      init: function(parent, dataset, view_id, options) {
        var self = this;
        this._super(parent, dataset, view_id, options);
        //if (self.dataset.context && self.dataset.context.tree_ids && self.dataset.context.tree_ids.length) {
        //    self.dataset.ids = self.dataset.context.tree_ids;
        //    self.dataset.index = self.dataset.ids.indexOf(self.dataset.context.active_id);
        //}
      },
      on_button_save: function(e) {
          var self = this;
          _.each(this.ViewManager.ActionManager.breadcrumbs, function(br){
            br.need_update = true;
          });

          return self._super(e).then(function(){
              if (self.ViewManager.views.tree)
                self.ViewManager.views.tree.controller.switch_mode()
          });
      },
      on_button_create: function() {
          var self = this;
          self._super();
          if (self.ViewManager.views.tree)
            self.ViewManager.views.tree.controller.switch_mode()
      }
  });

  instance.web.TreeView.include({
    init: function (parent, dataset, view_id, options) {
        if (parent.action && parent.action.context.tree_domain){
          var domain = new instance.web.CompoundDomain(dataset.domain, parent.action.context.tree_domain);
          dataset = new instance.web.DataSetSearch(this, parent.action.res_model, dataset.context, domain);
        }
        this._super(parent, dataset, view_id, options);
    },
    switch_mode: function () {
      this.$el.find(".oe-treeview-table > tbody").empty();
      _(this.fields_view.arch.children).each(function (field) {
          if (field.attrs.modifiers && typeof(field.attrs.modifiers) == 'object') {
              field.attrs.modifiers = JSON.stringify(field.attrs.modifiers);
          }
      });
      this.view_loading(this.fields_view);
    },
    hook_row_click: function () {
      this.$el.undelegate('.treeview-tr', 'click');
      this._super();
    },
    getdata: function (id, children_ids) {
        // do not getdata twice, this class stop loading
        this.$el.find('#treerow_' + id).addClass('oe_open');

        var self = this;

        self.dataset.read_ids(children_ids, this.fields_list()).done(function(records) {
            _(records).each(function (record) {
                self.records[record.id] = record;
            });
            var $curr_node = self.$el.find('#treerow_' + id);
            var children_rows = QWeb.render('TreeView.rows', {
                'records': records,
                'children_field': self.children_field,
                'fields_view': self.fields_view.arch.children,
                'fields': self.fields,
                'level': $curr_node.data('level') || 0,
                'render': instance.web.format_value,
                'color_for': self.color_for,
                'row_parent_id': id
            });
            if ($curr_node.length) {
                $curr_node.addClass('oe_open');
                $curr_node.after(children_rows);
            } else {
                self.$el.find('tbody').html(children_rows);
            }
        }).then(function(){
          if (self.ViewManager.action && self.ViewManager.action.id) {
            view_id = self.ViewManager.action.id;
            var open_trees = JSON.parse(localStorage.getItem('open_trees') || '{}');
                if (!open_trees[view_id]) {open_trees[view_id] = {};}
            open_trees[view_id][id] = true;
            localStorage["open_trees"] = JSON.stringify(open_trees);
            for(k in open_trees[view_id]){
              if (open_trees[view_id][k]) {
                $('#treerow_'+k+':not(.oe_open) .treeview-tr').click();
              }
            }
          }
        });
    },
    activate: function(id) {
      if (this.ViewManager.ActionManager) {
        parent = false;
        for (i in this.records) {
          if (_.indexOf(this.records[i].child_ids, id)+1) {
            parent = i;
            break;
          }
        }
        if (parent) {
          our_ids = this.records[parent].child_ids
        } else {
          our_ids = this.dataset.ids
        }
        this.ViewManager.ActionManager.tree_context = {
          tree_ids: our_ids
        };
      }
      this._super(id);
    },

    showcontent: function (curnode,record_id, show) {
      this._super(curnode,record_id, show);
      if (this.ViewManager && this.ViewManager.action) {
        view_id = this.ViewManager.action.id;
        var open_trees = JSON.parse(localStorage.getItem('open_trees') || '{}');
        if (!open_trees[view_id]) {open_trees[view_id] = {};}
        open_trees[view_id][record_id] = show;
        localStorage["open_trees"] = JSON.stringify(open_trees);
      }
    },
  });
  instance.web.ActionManager.include({
    select_breadcrumb: function(index, subindex) {
      var self = this;
      var item = this.breadcrumbs[index];
      if (item.widget.views.tree && item.need_update) {
        item.need_update=false;
        item.widget.views.tree.controller.switch_mode();
      }
      return this._super(index, subindex);
    },
    do_action: function(action, options) {
      if (this.tree_context) {
        action.context.tree_ids = this.tree_context.tree_ids;
      }
      this._super(action, options);
    }
  });

  /********* Many2Many Tree Field ********/
  local.Many2ManyTreeField = instance.web.form.FieldMany2Many.extend({
    initialize_content: function() {
        if (!(this.field.type == 'many2many' || this.field.type == 'one2many'))
            return this._super();
        this.list_view = new instance.web.TreeView(this, this.dataset, false, {
                    'addable': false,
                    'deletable': false,
                    'selectable': false,
                    'sortable': false,
                    'reorderable': false,
                    'import_enabled': false,
            });
        this.$el.empty();
        this.list_view.appendTo(this.$el);
    },
    render_value: function() {
      this.initialize_content();
      return this._super();
    }
  });

  instance.web.form.widgets.add('many2many_tree', 'instance.suvit_web_tree.Many2ManyTreeField');
};
<|endoftext|>


<commit_before>var grid = document.getElementById('grid');

var table = new Handsontable(grid, {
    data: [
        [1, null, 2],
        [null, null, null],
        [null, null, null],
        [1, null, 2]
    ]
});

var cols = table.countEmptyCols();
var rows = table.countEmptyRows();

console.log('cols=' + cols + ', rows=' + rows);
<commit_msg>countEmptyCols<commit_after>var grid = document.getElementById('grid');

var table = new Handsontable(grid, {
    data: [
        [   1, null,    2],
        [null, null, null],
        [null, null,    2],
        [   1, null,    2],
        [null, null, null]
    ]
});

var cols = table.countEmptyCols();
var rows = table.countEmptyRows();

console.log('cols=' + cols + ', rows=' + rows);
<|endoftext|>


<commit_before>/**
 * model/core/base.js
 */

/**
 * @type {RegExp}
 * @const
 */
var rgxEventSplitter = /[. :]+/;

/**
 * baseModel
 * @constructor
 */
var baseModel = {
    isModel: true,
    make: function (opts) {
        var self = this;
        // Each TBone model/collection is an augmented copy of this TBoneModel function
        var instance = function TBoneModel (arg0, arg1, arg2) {
            if (typeof arg0 === 'function') {
                return autorun(arg0, arg1, arg2);
            } else if (typeof arg1 === 'function' && !isQueryable(arg1)) {
                return instance['query'](arg0, boundModel.extend({ 'state': arg1 }).make());
            } else {
                return (arguments.length === 0 ? instance['query']() :
                        arguments.length === 1 ? instance['query'](arg0) :
                        arguments.length === 2 ? instance['query'](arg0, arg1) :
                                                 instance['query'](arg0, arg1, arg2));
            }
        };
        _.extend(instance, self, isFunction(opts) ? { 'state': opts } : opts || {});

        // Initialize the model instance
        delete instance['tboneid'];
        delete instance['attributes'];
        instance._events = {};
        instance._removeCallbacks = {};
        uniqueId(instance);
        instance['initialize']();

        return instance;
    },
    'extend': function (subclass) {
        return _.extend({}, this, subclass);
    },
    'initialize': noop,
    'on': function (name, callback, context) {
        var parts = name.split(rgxEventSplitter);
        var events = this._events;
        var arg;

        while ((arg = parts.shift()) != null) {
            if (arg === '') {
                continue;
            }
            if (!events[arg]) {
                events[arg] = {};
            }
            events = events[arg];
        }
        var callbacks = events[''];
        if (!callbacks) {
            callbacks = events[''] = [];
        }
        callbacks.push({ callback: callback, context: context });

        /**
         * Wake up and reset this and other models that may be sleeping because
         * they did not need to be updated.
         */
        this.wake({});
    },
    'off': function (name, callback, context) {
        // XXX name & callback not supported.
        // XXX doesn't clean up when callbacks list goes to zero length
        var stack = [ this._events ];
        var next, callbacks, k;

        while (!!(next = stack.pop())) {
            for (k in next) {
                if (k === '') {
                    var newCallbacks = [];
                    callbacks = next[''];
                    for (var i = 0; i < next[k].length; i++) {
                        if (callbacks[i].context !== context) {
                            newCallbacks.push(callbacks[i]);
                        }
                    }
                    next[''] = newCallbacks;
                } else {
                    stack.push(next[k]);
                }
            }
        }
    },
    'trigger': function (name) {
        var self = this;
        var events = self._events;
        var parts = name.split(rgxEventSplitter);
        var arg;
        while ((arg = parts.shift()) != null) {
            if (arg === '') {
                continue;
            }
            if (!events[arg]) {
                events[arg] = {};
            }
            events = events[arg];
        }
        var callbacks = events[QUERY_SELF] || [];
        for (var i = 0; i < callbacks.length; i++) {
            callbacks[i].callback.call(callbacks[i].context);
        }
    },

    'query': query,

    'queryModel': function (prop) {
        return this['query'](DONT_GET_DATA, prop);
    },

    'idAttribute': 'id',

    'queryId': function () {
        return this['query'](this['idAttribute']);
    },

    'toggle': function (prop) {
        this['query'](QUERY_TOGGLE, prop);
    },

    'push': function (prop, value) {
        if (arguments.length === 1) {
            value = prop;
            prop = '';
        }
        this['query'](QUERY_PUSH, prop, value);
    },

    'unshift': function (prop, value) {
        if (arguments.length === 1) {
            value = prop;
            prop = '';
        }
        this['query'](QUERY_UNSHIFT, prop, value);
    },

    'removeFirst': function (prop) {
        this['query'](QUERY_REMOVE_FIRST, prop);
    },

    'removeLast': function (prop) {
        this['query'](QUERY_REMOVE_LAST, prop);
    },

    'unset': function (prop) {
        this['query'](QUERY_UNSET, prop);
    },

    'increment': function (prop, value) {
        this['query'](QUERY_INCREMENT, prop, value != null ? value : 1);
    },

    'clear': function () {
        this['query']('', undefined);
    },

    'toJSON': function () {
        return this.attributes;
    },

    wake: noop,

    'queryText': queryText, // deprecated
    'text': queryText, // deprecated
    'lookup': query, // deprecated
    'lookupText': queryText, // deprecated
    'set': query, // deprecated
    'get': query // deprecated
};

if (TBONE_DEBUG) {
    baseModel['find'] = function (obj) {
        function recurse(o, depth) {
            if (depth > 10) {
                return [];
            }
            if (o === obj) {
                return [];
            }
            if (isQueryable(o)) {
                if (!!(result = recurse(o.attributes, depth + 1))) {
                    return result;
                }
            } else if (o !== null && typeof o === 'object') {
                var result;
                if (o.push) {
                    for (var i = 0; i < o.length; i++) {
                        if (!!(result = recurse(o[i], depth + 1))) {
                            result.unshift(k);
                            return result;
                        }
                    }
                } else {
                    for (var k in o) {
                        if (!!(result = recurse(o[k], depth + 1))) {
                            result.unshift(k);
                            return result;
                        }
                    }
                }
            }
        }
        var result = recurse(this.attributes, 0);
        return result ? result.join('.') : null;
    };
}
<commit_msg>Use only dots as event separators in tbone models.<commit_after>/**
 * model/core/base.js
 */

/**
 * @type {RegExp}
 * @const
 */
var rgxEventSplitter = /[.]+/;

/**
 * Split name parameter into components (used in .on() and .trigger())
 *
 * For compatibility with backbone, we support using the colon as the
 * separator between "change" and the remainder of the terms, but only
 * dots after that.
 */
function splitName (name) {
    return name.replace(/^change:/, 'change.').split(rgxEventSplitter);
}

/**
 * baseModel
 * @constructor
 */
var baseModel = {
    isModel: true,
    make: function (opts) {
        var self = this;
        // Each TBone model/collection is an augmented copy of this TBoneModel function
        var instance = function TBoneModel (arg0, arg1, arg2) {
            if (typeof arg0 === 'function') {
                return autorun(arg0, arg1, arg2);
            } else if (typeof arg1 === 'function' && !isQueryable(arg1)) {
                return instance['query'](arg0, boundModel.extend({ 'state': arg1 }).make());
            } else {
                return (arguments.length === 0 ? instance['query']() :
                        arguments.length === 1 ? instance['query'](arg0) :
                        arguments.length === 2 ? instance['query'](arg0, arg1) :
                                                 instance['query'](arg0, arg1, arg2));
            }
        };
        _.extend(instance, self, isFunction(opts) ? { 'state': opts } : opts || {});

        // Initialize the model instance
        delete instance['tboneid'];
        delete instance['attributes'];
        instance._events = {};
        instance._removeCallbacks = {};
        uniqueId(instance);
        instance['initialize']();

        return instance;
    },
    'extend': function (subclass) {
        return _.extend({}, this, subclass);
    },
    'initialize': noop,
    'on': function (name, callback, context) {
        var parts = splitName(name);
        var events = this._events;
        var arg;

        while ((arg = parts.shift()) != null) {
            if (arg === '') {
                continue;
            }
            if (!events[arg]) {
                events[arg] = {};
            }
            events = events[arg];
        }
        var callbacks = events[''];
        if (!callbacks) {
            callbacks = events[''] = [];
        }
        callbacks.push({ callback: callback, context: context });

        /**
         * Wake up and reset this and other models that may be sleeping because
         * they did not need to be updated.
         */
        this.wake({});
    },
    'off': function (name, callback, context) {
        // XXX name & callback not supported.
        // XXX doesn't clean up when callbacks list goes to zero length
        var stack = [ this._events ];
        var next, callbacks, k;

        while (!!(next = stack.pop())) {
            for (k in next) {
                if (k === '') {
                    var newCallbacks = [];
                    callbacks = next[''];
                    for (var i = 0; i < next[k].length; i++) {
                        if (callbacks[i].context !== context) {
                            newCallbacks.push(callbacks[i]);
                        }
                    }
                    next[''] = newCallbacks;
                } else {
                    stack.push(next[k]);
                }
            }
        }
    },
    'trigger': function (name) {
        var self = this;
        var events = self._events;
        var parts = splitName(name);
        var arg;
        while ((arg = parts.shift()) != null) {
            if (arg === '') {
                continue;
            }
            if (!events[arg]) {
                events[arg] = {};
            }
            events = events[arg];
        }
        var callbacks = events[QUERY_SELF] || [];
        for (var i = 0; i < callbacks.length; i++) {
            callbacks[i].callback.call(callbacks[i].context);
        }
    },

    'query': query,

    'queryModel': function (prop) {
        return this['query'](DONT_GET_DATA, prop);
    },

    'idAttribute': 'id',

    'queryId': function () {
        return this['query'](this['idAttribute']);
    },

    'toggle': function (prop) {
        this['query'](QUERY_TOGGLE, prop);
    },

    'push': function (prop, value) {
        if (arguments.length === 1) {
            value = prop;
            prop = '';
        }
        this['query'](QUERY_PUSH, prop, value);
    },

    'unshift': function (prop, value) {
        if (arguments.length === 1) {
            value = prop;
            prop = '';
        }
        this['query'](QUERY_UNSHIFT, prop, value);
    },

    'removeFirst': function (prop) {
        this['query'](QUERY_REMOVE_FIRST, prop);
    },

    'removeLast': function (prop) {
        this['query'](QUERY_REMOVE_LAST, prop);
    },

    'unset': function (prop) {
        this['query'](QUERY_UNSET, prop);
    },

    'increment': function (prop, value) {
        this['query'](QUERY_INCREMENT, prop, value != null ? value : 1);
    },

    'clear': function () {
        this['query']('', undefined);
    },

    'toJSON': function () {
        return this.attributes;
    },

    wake: noop,

    'queryText': queryText, // deprecated
    'text': queryText, // deprecated
    'lookup': query, // deprecated
    'lookupText': queryText, // deprecated
    'set': query, // deprecated
    'get': query // deprecated
};

if (TBONE_DEBUG) {
    baseModel['find'] = function (obj) {
        function recurse(o, depth) {
            if (depth > 10) {
                return [];
            }
            if (o === obj) {
                return [];
            }
            if (isQueryable(o)) {
                if (!!(result = recurse(o.attributes, depth + 1))) {
                    return result;
                }
            } else if (o !== null && typeof o === 'object') {
                var result;
                if (o.push) {
                    for (var i = 0; i < o.length; i++) {
                        if (!!(result = recurse(o[i], depth + 1))) {
                            result.unshift(k);
                            return result;
                        }
                    }
                } else {
                    for (var k in o) {
                        if (!!(result = recurse(o[k], depth + 1))) {
                            result.unshift(k);
                            return result;
                        }
                    }
                }
            }
        }
        var result = recurse(this.attributes, 0);
        return result ? result.join('.') : null;
    };
}
<|endoftext|>


<commit_before>// Get the version of a specific CLI
const getVersion = async (rule, context) => {
  const { system } = context

  let versionOutput
  // They specified how to check version
  if (rule.version) {
    versionOutput = await system.run(`${rule.binary} ${rule.version}`)
  } else {
    // We try the following in this order
    // -v, --version, -version
    try { versionOutput = await system.run(`${rule.binary} -v`) } catch(_e) {
      try { versionOutput = await system.run(`${rule.binary} --version`) } catch(_e) {
        try { versionOutput = await system.run(`${rule.binary} -version`) } catch(_e) {
          throw 'No version identifier flag for this binary was found'
        }
      }
    }

  }

  // Now parse
  const correctLine = getVersionLine(rule, versionOutput)
  // clean version to only consist of numbers (better than semver.clean)
  return correctLine.replace(/[^\d.]/g, '')
}

// find semver based on rule and output
const getVersionLine = (rule, versionOutput) => {
  let result
  if (typeof rule.line === 'number') {
    result = versionOutput.split('\n')[rule.line - 1]
  } else if (typeof rule.line === 'string') {
    const findString = `.*${rule.line}.*`
    const findRegex = RegExp(findString, 'g')
    const foundLines = versionOutput.match(findRegex)
    try {
      // Always first instance
      result = foundLines[0]
    } catch (_e) {
      throw `rule.line string '${rule.line}' was not found`
    }
  } else {
    // Parse output for something that looks like a version
    const foundVersions = versionOutput.match(/(\d+\.)?(\d+\.)?(\d+)/g)
    try {
      // Always first match (for now...)
      result = foundVersions[0]
    } catch (_e) {
      throw `No version was detected from the output of the binary '${rule.binary}'`
    }
  }

  return result
}

module.exports = async (rule, context) => {
  const { system, semver } = context

  // First check for binary
  try {
    system.which(rule.binary)
  } catch (_e) {
    return `Binary '${rule.binary}' not found`
  }

  // Is there a semver rule?
  if (rule.semver) {
    // ensure we have valid rule input
    if (!semver.validRange(rule.semver)) return `Invalid semver rule ${rule.semver}`

    const binaryVersion = await getVersion(rule, context)
    // I can't get no satisfaction
    if (!semver.satisfies(binaryVersion, rule.semver)) {
      return `This system has an improper version for ${rule.binary}:
        Rule='${rule.semver}'
        Actual='${binaryVersion}'`
    }
  }
}
<commit_msg>Issue #20: Enhanced regex that was used to find a version in a line. Use regex always instead of only when rules don't provide a line<commit_after>// Get the version of a specific CLI
const getVersion = async (rule, context) => {
  const { system } = context

  let versionOutput
  // They specified how to check version
  if (rule.version) {
    versionOutput = await system.run(`${rule.binary} ${rule.version}`)
  } else {
    // We try the following in this order
    // -v, --version, -version
    try { versionOutput = await system.run(`${rule.binary} -v`) } catch(_e) {
      try { versionOutput = await system.run(`${rule.binary} --version`) } catch(_e) {
        try { versionOutput = await system.run(`${rule.binary} -version`) } catch(_e) {
          throw 'No version identifier flag for this binary was found'
        }
      }
    }

  }

  // Now parse
  const correctLine = getLineWithVersion(rule, versionOutput)
  const version = removeNonVersionCharacters(correctLine)
  return version
}

const getLineWithVersion = (rule, versionOutput) => {
  let result
  if (typeof rule.line === 'number') {
    result = versionOutput.split('\n')[rule.line - 1]
  } else if (typeof rule.line === 'string') {
    const findString = `.*${rule.line}.*`
    const findRegex = RegExp(findString, 'g')
    const foundLines = versionOutput.match(findRegex)
    try {
      // Always first instance
      result = foundLines[0]
    } catch (_e) {
      throw `rule.line string '${rule.line}' was not found`
    }
  } else {
    //pass it through if rules don't provide a line
    result = versionOutput
  }
  return result
}

const removeNonVersionCharacters = (line) => {
  const foundVersions = line.match(/(\d+\.)?(\d+\.)?(\d+)([^\sa-zA-Z0-9]+\w+)?/g)
  // Return longest match, because it is most likely to be correct
  let result = foundVersions[0]
  try {
    for (let i = 1; i < foundVersions.length; i++) {
      if (foundVersions[i].length >= result.length) {
        result = foundVersions[i]
      }
    }
  } catch (_e) {
    throw `No version was detected from the output of the binary '${rule.binary}'`
  }
  return result
}

module.exports = async (rule, context) => {
  const { system, semver } = context

  // First check for binary
  try {
    system.which(rule.binary)
  } catch (_e) {
    return `Binary '${rule.binary}' not found`
  }

  // Is there a semver rule?
  if (rule.semver) {
    // ensure we have valid rule input
    if (!semver.validRange(rule.semver)) return `Invalid semver rule ${rule.semver}`

    const binaryVersion = await getVersion(rule, context)
    // I can't get no satisfaction
    if (!semver.satisfies(binaryVersion, rule.semver)) {
      return `This system has an improper version for ${rule.binary}:
        Rule='${rule.semver}'
        Actual='${binaryVersion}'`
    }
  }
}
<|endoftext|>


<commit_before>/*
    A small plugin made for especially for UORPG chat server
*/

var core = undefined;

var UORPG_Server = "177730395352072192";

var Chan_RUS = "203294045689217024";
var Chan_ENG = "199908461549584384";
var Chan_LAT = "369616743200456715";

function isRussian(chan)
{
    return (chan.id == Chan_RUS);
}

function getChaos(guild)
{
    return guild.roles.find('name', 'Chaos');
}

function getOrder(guild)
{
    return guild.roles.find('name', 'Order');
}

var joinOrder = function(bot, message, args)
{
    var chaos = getChaos(message.guild);
    var order = getOrder(message.guild);
    var member = message.guild.members.get(message.author.id);
    member.removeRole(chaos);
    member.addRole(order);
    message.reply("Welcome to Order!", core.msgSendError);
}

var joinChaos = function(bot, message, args)
{
    var chaos = getChaos(message.guild);
    var order = getOrder(message.guild);
    var member = message.guild.members.get(message.author.id);
    member.removeRole(order);
    member.addRole(chaos);
    message.reply("Welcome to Chaos!", core.msgSendError);
}

var crystalPhase = function(bot, message, args)
{
    var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
    var firstDate = new Date(2017,11,1);//Точка отсчёта чётности
    var secondDate = new Date();

    var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));

    var rus = bot.channels.get(Chan_RUS);
    var lat = bot.channels.get(Chan_LAT);
    //var eng = bot.channels.get(Chan_ENG);

    var crystal_peace;
    var crystal_war;

    if(message.channel.id == rus.id)
    {
        crystal_peace = "# Кристал в мирной проекции мира.";
        crystal_war = "# Кристал в боевой проекции мира.";
    }
    else if(message.channel.id == lat.id)
    {
        crystal_peace = "# Kristāls ir pasaules mierā projekcijā.";
        crystal_war = "# Kristāls ir pasaules karā projekcijā.";
    }
    else
    {
        crystal_peace = "# The Crystal is in the peace projection of the world.";
        crystal_war = "# The Crystal is in the war projection of the world.";
    }

    if((diffDays % 2) == 0)
        message.channel.send(crystal_peace).catch(core.msgSendError);
    else
        message.channel.send(crystal_war).catch(core.msgSendError);
}

function registerCommands(foxyCore)
{
    core = foxyCore;
    core.addCMD(["order",      joinOrder,           "Join The Order Alliance - Holy Empire and Insurgents!!!", [], true, [UORPG_Server] ]);
    core.addCMD(["chaos",      joinChaos,           "Join The Chaos Alliance - Army of Darkness and The Shadows!!!", [], true, [UORPG_Server] ]);
    core.addCMD(["crystal",    crystalPhase,        "Show projection where crystal is located", [], true, [UORPG_Server] ]);
}

function guildMemberAdd(bot, guildMember)
{
    // console.log("Кто-то новенький! " + guildMember.user.id +
    // " на серваке " + guildMember.guild.id + " == " + UORPG_Server);
    if(guildMember.guild.id == UORPG_Server)
    {
        var ru = bot.channels.get(Chan_RUS);
        var en = bot.channels.get(Chan_ENG);

        var message_ru =
            "<@" + guildMember.user.id +">, Приветствуем вас на сервере Ultima Online - UORPG.net!\n\n" +
            "Выберите вашу фракцию:\n" +
            "Альянс Порядок - Священная Империя и Повстанцы\n" +
            "Альянс Хаос - Армия Тьмы и Тени\n\n" +
            "Для того, чтобы выбрать вашу сторону в войне напишите в чате: /foxy order или /foxy chaos";
        var message_en =
            "<@" + guildMember.user.id +">, Hi, welcome to Ultima Online server - UORPG.net!\n\n" +
            "Assign your faction please:\n" +
            "The Order Alliance - Holy Empire and Insurgents\n" +
            "The Chaos Alliance - Army of Darkness and The Shadows\n\n"+
            "In order to confirm your war force, type: /foxy order ;  /foxy chaos";

        ru.send(message_ru).catch(core.msgSendError);
        en.send(message_en).catch(core.msgSendError);
    }
}

module.exports =
{
    registerCommands:   registerCommands,
    guildMemberAdd:     guildMemberAdd
};
<commit_msg>UORPG: Change referebce date of a crystal projection phase Made by Born2Bake's request<commit_after>/*
    A small plugin made for especially for UORPG chat server
*/

var core = undefined;

var UORPG_Server = "177730395352072192";

var Chan_RUS = "203294045689217024";
var Chan_ENG = "199908461549584384";
var Chan_LAT = "369616743200456715";

function isRussian(chan)
{
    return (chan.id == Chan_RUS);
}

function getChaos(guild)
{
    return guild.roles.find('name', 'Chaos');
}

function getOrder(guild)
{
    return guild.roles.find('name', 'Order');
}

var joinOrder = function(bot, message, args)
{
    var chaos = getChaos(message.guild);
    var order = getOrder(message.guild);
    var member = message.guild.members.get(message.author.id);
    member.removeRole(chaos);
    member.addRole(order);
    message.reply("Welcome to Order!", core.msgSendError);
}

var joinChaos = function(bot, message, args)
{
    var chaos = getChaos(message.guild);
    var order = getOrder(message.guild);
    var member = message.guild.members.get(message.author.id);
    member.removeRole(order);
    member.addRole(chaos);
    message.reply("Welcome to Chaos!", core.msgSendError);
}

var crystalPhase = function(bot, message, args)
{
    var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
    var firstDate = new Date(2017,11,2);//Точка отсчёта чётности
    var secondDate = new Date();

    var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));

    var rus = bot.channels.get(Chan_RUS);
    var lat = bot.channels.get(Chan_LAT);
    //var eng = bot.channels.get(Chan_ENG);

    var crystal_peace;
    var crystal_war;

    if(message.channel.id == rus.id)
    {
        crystal_peace = "# Кристал в мирной проекции мира.";
        crystal_war = "# Кристал в боевой проекции мира.";
    }
    else if(message.channel.id == lat.id)
    {
        crystal_peace = "# Kristāls ir pasaules mierā projekcijā.";
        crystal_war = "# Kristāls ir pasaules karā projekcijā.";
    }
    else
    {
        crystal_peace = "# The Crystal is in the peace projection of the world.";
        crystal_war = "# The Crystal is in the war projection of the world.";
    }

    if((diffDays % 2) == 0)
        message.channel.send(crystal_peace).catch(core.msgSendError);
    else
        message.channel.send(crystal_war).catch(core.msgSendError);
}

function registerCommands(foxyCore)
{
    core = foxyCore;
    core.addCMD(["order",      joinOrder,           "Join The Order Alliance - Holy Empire and Insurgents!!!", [], true, [UORPG_Server] ]);
    core.addCMD(["chaos",      joinChaos,           "Join The Chaos Alliance - Army of Darkness and The Shadows!!!", [], true, [UORPG_Server] ]);
    core.addCMD(["crystal",    crystalPhase,        "Show projection where crystal is located", [], true, [UORPG_Server] ]);
}

function guildMemberAdd(bot, guildMember)
{
    // console.log("Кто-то новенький! " + guildMember.user.id +
    // " на серваке " + guildMember.guild.id + " == " + UORPG_Server);
    if(guildMember.guild.id == UORPG_Server)
    {
        var ru = bot.channels.get(Chan_RUS);
        var en = bot.channels.get(Chan_ENG);

        var message_ru =
            "<@" + guildMember.user.id +">, Приветствуем вас на сервере Ultima Online - UORPG.net!\n\n" +
            "Выберите вашу фракцию:\n" +
            "Альянс Порядок - Священная Империя и Повстанцы\n" +
            "Альянс Хаос - Армия Тьмы и Тени\n\n" +
            "Для того, чтобы выбрать вашу сторону в войне напишите в чате: /foxy order или /foxy chaos";
        var message_en =
            "<@" + guildMember.user.id +">, Hi, welcome to Ultima Online server - UORPG.net!\n\n" +
            "Assign your faction please:\n" +
            "The Order Alliance - Holy Empire and Insurgents\n" +
            "The Chaos Alliance - Army of Darkness and The Shadows\n\n"+
            "In order to confirm your war force, type: /foxy order ;  /foxy chaos";

        ru.send(message_ru).catch(core.msgSendError);
        en.send(message_en).catch(core.msgSendError);
    }
}

module.exports =
{
    registerCommands:   registerCommands,
    guildMemberAdd:     guildMemberAdd
};
<|endoftext|>


<commit_before>// wmts preview module
ckan.module('wmtspreview', function (jQuery, _) {
  return {
    initialize: function () {
      var self = this;

      self.el.empty();
      self.el.append($('

').attr('id', 'map'));
      self.map = ckan.commonLeafletMap('map', this.options.map_config, {center: [0, 0], zoom: 3});

      $.ajaxSetup({
        beforeSend: function (xhr) {
          xhr.overrideMimeType('application/xml; charset=UTF-8');
        }
      });

      // use CORS, if supported by browser and server
      if (jQuery.support.cors && preload_resource['original_url'] !== undefined) {
        jQuery.get(preload_resource['original_url'])
        .done(
          function(data){
            self.showPreview(preload_resource['original_url'], data);
          })
        .fail(
          function(jqxhr, textStatus, error) {
            jQuery.get(preload_resource['url']).done(
              function(data){
                self.showPreview(preload_resource['original_url'], data);
              })
            .fail(
              function(jqXHR, textStatus, errorThrown) {
                self.showError(jqXHR, textStatus, errorThrown);
              }
            );
          }
        );
      } else {
        jQuery.get(preload_resource['url']).done(
          function(data){
            self.showPreview(preload_resource['original_url'], data);
          })
        .fail(
          function(jqXHR, textStatus, errorThrown) {
            self.showError(jqXHR, textStatus, errorThrown);
          }
        );
      }
    },

    showError: function (jqXHR, textStatus, errorThrown) {
      if (textStatus == 'error' && jqXHR.responseText.length) {
        this.el.html(jqXHR.responseText);
      } else {
        this.el.html(this.i18n('error', {text: textStatus, error: errorThrown}));
      }
    },

    showPreview: function (url, data) {
      var self = this;
      var EPSG4326 = proj4('EPSG:4326');
      var nameSpace = ($(data).find('Contents Layer > ows\\:Identifier').length != 0) ? 'ows\\:' : '';
      var xmlPathPrefix = 'Contents Layer > ' + nameSpace;
      var xmlMapIds = $(data).find(xmlPathPrefix + 'Identifier');
      var xmlMapTitles = $(data).find(xmlPathPrefix + 'Title');
      var bboxName = ($(data).find(xmlPathPrefix + 'WGS84BoundingBox').length != 0) ? 'WGS84BoundingBox' : 'BoundingBox';
      var xmlPathPrefix2 = 'Contents Layer ows\\:' + bboxName + ' > ' + nameSpace;
      var xmlMapLowerCorner = $(data).find(xmlPathPrefix2 + 'LowerCorner');
      var xmlMapUpperCorner = $(data).find(xmlPathPrefix2 + 'UpperCorner');
      var mapIds = [];
      var mapTitles = [];
      var maps = {};
      var mapLatLngBounds = {};
      var xmlMapCrs, overlay;

      function layerChange(e) {
	var url = e.layer._url;
	overlay = e.layer;
	self.map.fitBounds(mapLatLngBounds[url.substring(url.lastIndexOf('LAYER='), url.indexOf('&STYLE')).split('=')[1]]);
      }

      function loadEPSG(url, callback) {
        var script = document.createElement('script');
        script.src = url;
        script.onreadystatechange = callback;
        script.onload = callback;
        document.getElementsByTagName('head')[0].appendChild(script);
      }

      function transCoord(x, y, userCrs) {
        if (proj4) {
          var p = proj4(userCrs, EPSG4326, [parseFloat(x), parseFloat(y)]);
        }
        return [p[1], p[0]];
      }

      for (var i=0, max=xmlMapIds.length; i < max; i++) {
        mapIds.push(xmlMapIds[i].textContent);
        mapTitles.push(xmlMapTitles[i].textContent);
      }

      for (var i=0, max=mapIds.length; i < max; i++) {
        maps[mapTitles[i]] = L.tileLayer(url + '?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=' + mapIds[i] + '&STYLE=_null&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/png');
        mapLatLngBounds[mapIds[i]] = [xmlMapLowerCorner[i].textContent.split(' ').reverse(), xmlMapUpperCorner[i].textContent.split(' ').reverse()];
      }

      // If we only have BoundingBox info, load crs from epsg.io.
      if (bboxName == 'BoundingBox') {
        xmlMapCrs = $(data).find(xmlPathPrefix + bboxName).first().attr("crs");
        EPSG = xmlMapCrs.substring(xmlMapCrs.indexOf("EPSG::") + 6, xmlMapCrs.length);
        loadEPSG('http://epsg.io/' + EPSG + '.js', function() {
	  // Except for EPSG:3821 (which is incomplete)
          if (EPSG == 3821) {
            proj4.defs([
              ['EPSG:3821', '+proj=tmerc +ellps=GRS67 +towgs84=-752,-358,-179,-.0000011698,.0000018398,.0000009822,.00002329 +lat_0=0 +lon_0=121 +x_0=250000 +y_0=0 +k=0.9999 +units=m +no_defs']
            ]);
          }
          EPSGUser = proj4('EPSG:' + EPSG);
          for (var i=0, max=mapIds.length; i < max; i++) {
            lowercorner = mapLatLngBounds[mapIds[i]][0];
            uppercorner = mapLatLngBounds[mapIds[i]][1];
            mapLatLngBounds[mapIds[i]] = [transCoord(lowercorner[1], lowercorner[0], EPSGUser), transCoord(uppercorner[1], uppercorner[0], EPSGUser)];
          }
          self.map.fitBounds(mapLatLngBounds[mapIds[0]]);
        });
      }

      overlay = maps[mapTitles[0]];
      self.map.addLayer(maps[mapTitles[0]]);
      L.control.layers(maps, null).addTo(self.map);
      self.map.fitBounds(mapLatLngBounds[mapIds[0]]);
      self.map.on({baselayerchange: layerChange});

      // Layer control for mobile
      var container = document.getElementsByClassName('leaflet-control-layers')[0];
      L.DomEvent.disableClickPropagation(container);

      // Opacity control for desktop
      if (!L.Browser.touch) {
	var outer = $('
');
	var inner = $('
');
	var start = false;
	var startTop;
	$(outer).append(inner);
	$(outer).appendTo('body');
	var handle = document.getElementById('handle');
        document.onmousemove = function(e) {
          if (!start) return;
          handle.style.top = Math.max(-5, Math.min(195, startTop + parseInt(e.clientY, 10) - start)) + 'px';
          overlay.setOpacity(1 - (handle.offsetTop / 200));
        };
        handle.onmousedown = function(e) {
          start = parseInt(e.clientY, 10);
          startTop = handle.offsetTop - 5;
	  return false;
        };
        document.onmouseup = function(e) {
          start = null;
        };
      }
    }
  };
});
<commit_msg>Remove the CORS handling as in fb8b99af3f15bb1548793e095efa749271540c17.<commit_after>// wmts preview module
ckan.module('wmtspreview', function (jQuery, _) {
  return {
    initialize: function () {
      var self = this;

      self.el.empty();
      self.el.append($('

').attr('id', 'map'));
      self.map = ckan.commonLeafletMap('map', this.options.map_config, {center: [0, 0], zoom: 3});

      $.ajaxSetup({
        beforeSend: function (xhr) {
          xhr.overrideMimeType('application/xml; charset=UTF-8');
        }
      });

      jQuery.get(preload_resource['url']).done(
        function(data){
          self.showPreview(preload_resource['original_url'], data);
        })
      .fail(
        function(jqXHR, textStatus, errorThrown) {
          self.showError(jqXHR, textStatus, errorThrown);
        }
      );
    },

    showError: function (jqXHR, textStatus, errorThrown) {
      if (textStatus == 'error' && jqXHR.responseText.length) {
        this.el.html(jqXHR.responseText);
      } else {
        this.el.html(this.i18n('error', {text: textStatus, error: errorThrown}));
      }
    },

    showPreview: function (url, data) {
      var self = this;
      var EPSG4326 = proj4('EPSG:4326');
      var nameSpace = ($(data).find('Contents Layer > ows\\:Identifier').length != 0) ? 'ows\\:' : '';
      var xmlPathPrefix = 'Contents Layer > ' + nameSpace;
      var xmlMapIds = $(data).find(xmlPathPrefix + 'Identifier');
      var xmlMapTitles = $(data).find(xmlPathPrefix + 'Title');
      var bboxName = ($(data).find(xmlPathPrefix + 'WGS84BoundingBox').length != 0) ? 'WGS84BoundingBox' : 'BoundingBox';
      var xmlPathPrefix2 = 'Contents Layer ows\\:' + bboxName + ' > ' + nameSpace;
      var xmlMapLowerCorner = $(data).find(xmlPathPrefix2 + 'LowerCorner');
      var xmlMapUpperCorner = $(data).find(xmlPathPrefix2 + 'UpperCorner');
      var mapIds = [];
      var mapTitles = [];
      var maps = {};
      var mapLatLngBounds = {};
      var xmlMapCrs, overlay;

      function layerChange(e) {
	var url = e.layer._url;
	overlay = e.layer;
	self.map.fitBounds(mapLatLngBounds[url.substring(url.lastIndexOf('LAYER='), url.indexOf('&STYLE')).split('=')[1]]);
      }

      function loadEPSG(url, callback) {
        var script = document.createElement('script');
        script.src = url;
        script.onreadystatechange = callback;
        script.onload = callback;
        document.getElementsByTagName('head')[0].appendChild(script);
      }

      function transCoord(x, y, userCrs) {
        if (proj4) {
          var p = proj4(userCrs, EPSG4326, [parseFloat(x), parseFloat(y)]);
        }
        return [p[1], p[0]];
      }

      for (var i=0, max=xmlMapIds.length; i < max; i++) {
        mapIds.push(xmlMapIds[i].textContent);
        mapTitles.push(xmlMapTitles[i].textContent);
      }

      for (var i=0, max=mapIds.length; i < max; i++) {
        maps[mapTitles[i]] = L.tileLayer(url + '?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=' + mapIds[i] + '&STYLE=_null&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/png');
        mapLatLngBounds[mapIds[i]] = [xmlMapLowerCorner[i].textContent.split(' ').reverse(), xmlMapUpperCorner[i].textContent.split(' ').reverse()];
      }

      // If we only have BoundingBox info, load crs from epsg.io.
      if (bboxName == 'BoundingBox') {
        xmlMapCrs = $(data).find(xmlPathPrefix + bboxName).first().attr("crs");
        EPSG = xmlMapCrs.substring(xmlMapCrs.indexOf("EPSG::") + 6, xmlMapCrs.length);
        loadEPSG('http://epsg.io/' + EPSG + '.js', function() {
	  // Except for EPSG:3821 (which is incomplete)
          if (EPSG == 3821) {
            proj4.defs([
              ['EPSG:3821', '+proj=tmerc +ellps=GRS67 +towgs84=-752,-358,-179,-.0000011698,.0000018398,.0000009822,.00002329 +lat_0=0 +lon_0=121 +x_0=250000 +y_0=0 +k=0.9999 +units=m +no_defs']
            ]);
          }
          EPSGUser = proj4('EPSG:' + EPSG);
          for (var i=0, max=mapIds.length; i < max; i++) {
            lowercorner = mapLatLngBounds[mapIds[i]][0];
            uppercorner = mapLatLngBounds[mapIds[i]][1];
            mapLatLngBounds[mapIds[i]] = [transCoord(lowercorner[1], lowercorner[0], EPSGUser), transCoord(uppercorner[1], uppercorner[0], EPSGUser)];
          }
          self.map.fitBounds(mapLatLngBounds[mapIds[0]]);
        });
      }

      overlay = maps[mapTitles[0]];
      self.map.addLayer(maps[mapTitles[0]]);
      L.control.layers(maps, null).addTo(self.map);
      self.map.fitBounds(mapLatLngBounds[mapIds[0]]);
      self.map.on({baselayerchange: layerChange});

      // Layer control for mobile
      var container = document.getElementsByClassName('leaflet-control-layers')[0];
      L.DomEvent.disableClickPropagation(container);

      // Opacity control for desktop
      if (!L.Browser.touch) {
	var outer = $('
');
	var inner = $('
');
	var start = false;
	var startTop;
	$(outer).append(inner);
	$(outer).appendTo('body');
	var handle = document.getElementById('handle');
        document.onmousemove = function(e) {
          if (!start) return;
          handle.style.top = Math.max(-5, Math.min(195, startTop + parseInt(e.clientY, 10) - start)) + 'px';
          overlay.setOpacity(1 - (handle.offsetTop / 200));
        };
        handle.onmousedown = function(e) {
          start = parseInt(e.clientY, 10);
          startTop = handle.offsetTop - 5;
	  return false;
        };
        document.onmouseup = function(e) {
          start = null;
        };
      }
    }
  };
});
<|endoftext|>


<commit_before>// Description:
//   Buy soda or list balance
//
// Configuration:
//   SODA_TOKEN,
//   SODA_URL,
//   MEMBERS_URL
//
// Commands
//   hubot kjøp <produkt_navn> - Purchase a product from Brus
//   hubot brus produkter - Get a list of products from brus.abakus.no
//   hubot saldo brus - Get your balance brus.abakus.no

const _ = require('lodash');
const fetch = require('node-fetch');
const members = require('../lib/members');
const logger = require('../lib/log');

const { SODA_TOKEN, SODA_URL } = process.env;

const sodaMappings = {
  ':dahls:': 'beer_dahls_bottle',
  ':dahls-jul:': 'beer_dahls_jul_bottle'
};

function brus(path, options = {}) {
  return fetch(
    `${SODA_URL}/api/liste${path}`,
    Object.assign(
      {
        method: 'GET',
        headers: {
          Authorization: `Token ${SODA_TOKEN}`,
          'Content-Type': 'application/json'
        }
      },
      options
    )
  );
}

function getSodaName(slackName) {
  return members(`?slack=${slackName}`).then(body => {
    const user = body[0];

    if (!user || !user.brus) {
      throw new Error(`Fant ikke ${slackName} på brus.`);
    }

    return user.brus;
  });
}
function getProducts() {
  return brus(`/products/`, {
    method: 'GET'
  })
    .then(response => {
      if (!response.ok) {
        throw new Error(`Jeg klarte ikke hente produktene fra brus`);
      }
      return response.json();
    })
    .then(body => {
      return body
        .map(product => `- \`${product.key}\`: ${product.current_price} kr`)
        .join('\n');
    });
}

function purchaseSoda(slackName, sodaType, count = 1) {
  return getSodaName(slackName).then(name => {
    return brus(`/purchase/`, {
      method: 'POST',
      body: JSON.stringify({
        name,
        shopping_cart: [
          {
            product_name: sodaMappings[sodaType] || sodaType,
            count
          }
        ]
      })
    }).then(response => {
      if (!response.ok) {
        if (response.status === 404) {
          throw new Error(
            `Jeg klarte ikke å kjøpe brusen: fant ikke noe produkt med navnet \`${sodaType}\`\nSkriv \`hubot brus produkter\` for å se listen`
          );
        } else {
          throw new Error(`Jeg klarte ikke å kjøpe brusen: ${response.status}`);
        }
      }

      return response.json();
    });
  });
}

module.exports = robot => {
  Object.keys(sodaMappings).map(sodaKey => {
    robot.hear(new RegExp(`(-|)(${sodaKey})`), msg => {
      if (msg.message.room === '#brus' || msg.message.room === 'brus') {
        logger.log(msg);
        const send = msg.send.bind(msg);
        const isMinus = msg.match[1].trim() === '-';
        purchaseSoda(msg.message.user.name, sodaKey, isMinus ? -1 : 1).catch(
          error => send(error.message)
        );
      }
    });
  });

  robot.respond(/kjøp (.*)?/i, msg => {
    logger.log(msg);
    const send = msg.send.bind(msg);
    const productName = msg.match[1].trim();
    purchaseSoda(msg.message.user.name, productName).catch(error =>
      send(error.message)
    );
  });

  robot.respond(/brus produkter/i, msg => {
    logger.log(msg);
    const send = msg.send.bind(msg);
    getProducts()
      .then(send)
      .catch(error => send(error.message));
  });

  robot.respond(/saldo brus( .*)?/i, msg => {
    logger.log(msg);
    const send = msg.send.bind(msg);
    const slackName = msg.match[1]
      ? msg.match[1].trim()
      : msg.message.user.name;

    getSodaName(slackName)
      .then(name => {
        return brus(`/${name}/`)
          .then(response => {
            if (response.status !== 200) {
              throw new Error(
                `Jeg klarte ikke hente info fra brus (${response.status}).`
              );
            }

            return response.json();
          })
          .then(
            // TODO: list products
            body =>
              `${body.name} sin saldo er ${
                body.balance
              } spenn. (TODO: produktliste, @noen fix)`
          );
      })
      .then(send)
      .catch(error => send(error.message));
  });
};
<commit_msg>Testing more stuff<commit_after>// Description:
//   Buy soda or list balance
//
// Configuration:
//   SODA_TOKEN,
//   SODA_URL,
//   MEMBERS_URL
//
// Commands
//   hubot kjøp <produkt_navn> - Purchase a product from Brus
//   hubot brus produkter - Get a list of products from brus.abakus.no
//   hubot saldo brus - Get your balance brus.abakus.no

const _ = require('lodash');
const fetch = require('node-fetch');
const members = require('../lib/members');
const logger = require('../lib/log');

const { SODA_TOKEN, SODA_URL } = process.env;

const sodaMappings = {
  ':dahls:': 'beer_dahls_bottle',
  ':dahls-jul:': 'beer_dahls_jul_bottle'
};

function brus(path, options = {}) {
  return fetch(
    `${SODA_URL}/api/liste${path}`,
    Object.assign(
      {
        method: 'GET',
        headers: {
          Authorization: `Token ${SODA_TOKEN}`,
          'Content-Type': 'application/json'
        }
      },
      options
    )
  );
}

function getSodaName(slackName) {
  return members(`?slack=${slackName}`).then(body => {
    const user = body[0];

    if (!user || !user.brus) {
      throw new Error(`Fant ikke ${slackName} på brus.`);
    }

    return user.brus;
  });
}
function getProducts() {
  return brus(`/products/`, {
    method: 'GET'
  })
    .then(response => {
      if (!response.ok) {
        throw new Error(`Jeg klarte ikke hente produktene fra brus`);
      }
      return response.json();
    })
    .then(body => {
      return body
        .map(product => `- \`${product.key}\`: ${product.current_price} kr`)
        .join('\n');
    });
}

function purchaseSoda(slackName, sodaType, count = 1) {
  return getSodaName(slackName).then(name => {
    return brus(`/purchase/`, {
      method: 'POST',
      body: JSON.stringify({
        name,
        shopping_cart: [
          {
            product_name: sodaMappings[sodaType] || sodaType,
            count
          }
        ]
      })
    }).then(response => {
      if (!response.ok) {
        if (response.status === 404) {
          throw new Error(
            `Jeg klarte ikke å kjøpe brusen: fant ikke noe produkt med navnet \`${sodaType}\`\nSkriv \`hubot brus produkter\` for å se listen`
          );
        } else {
          throw new Error(`Jeg klarte ikke å kjøpe brusen: ${response.status}`);
        }
      }

      return response.json();
    });
  });
}

module.exports = robot => {
  Object.keys(sodaMappings).map(sodaKey => {
    console.log('Mapping thing:', sodaKey, new RegExp(`(-|)(${sodaKey})`));

    robot.hear(new RegExp(`(-|)(${sodaKey})`), msg => {
      console.log('Found match', msg);
      if (msg.message.room === '#brus' || msg.message.room === 'brus') {
        logger.log(msg);
        const send = msg.send.bind(msg);
        const isMinus = msg.match[1].trim() === '-';
        purchaseSoda(msg.message.user.name, sodaKey, isMinus ? -1 : 1).catch(
          error => send(error.message)
        );
      }
    });
  });
  robot.hear(/:dahls:/, msg => {
    console.log('Found match', msg);
    if (msg.message.room === '#brus' || msg.message.room === 'brus') {
      logger.log(msg);
      const send = msg.send.bind(msg);
      const isMinus = false;
      purchaseSoda(msg.message.user.name, sodaKey, isMinus ? -1 : 1).catch(
        error => send(error.message)
      );
    }
  });

  robot.respond(/kjøp (.*)?/i, msg => {
    logger.log(msg);
    const send = msg.send.bind(msg);
    const productName = msg.match[1].trim();
    purchaseSoda(msg.message.user.name, productName).catch(error =>
      send(error.message)
    );
  });

  robot.respond(/brus produkter/i, msg => {
    logger.log(msg);
    const send = msg.send.bind(msg);
    getProducts()
      .then(send)
      .catch(error => send(error.message));
  });

  robot.respond(/saldo brus( .*)?/i, msg => {
    logger.log(msg);
    const send = msg.send.bind(msg);
    const slackName = msg.match[1]
      ? msg.match[1].trim()
      : msg.message.user.name;

    getSodaName(slackName)
      .then(name => {
        return brus(`/${name}/`)
          .then(response => {
            if (response.status !== 200) {
              throw new Error(
                `Jeg klarte ikke hente info fra brus (${response.status}).`
              );
            }

            return response.json();
          })
          .then(
            // TODO: list products
            body =>
              `${body.name} sin saldo er ${
                body.balance
              } spenn. (TODO: produktliste, @noen fix)`
          );
      })
      .then(send)
      .catch(error => send(error.message));
  });
};
<|endoftext|>