<commit_before>{
  class Bonsai {
    constructor(e, o) {
      // e:dom element, o:options={children:function(id,callback){...}, click:function(path){...}}
      const bt = this; // bonsai tree
      bt.rebuild = bt.rebuild.bind(bt);
      bt.render = bt.render.bind(bt);
      bt.refresh = bt.refresh.bind(bt);
      bt.childrenCb = o.children;
      bt.valueTipCb = o.valueTip;
      bt.dom = e;
      bt.rebuild();

      const toggleNode = (tgt) => {
        if (bt.newNodes) return;
        const a = tgt;
        const node = bt.nodes[a.parentNode.dataset.id];
        if (!node || !node.expandable) return;
        node.expanded = 1 - !!node.expanded; a.textContent = '+-'[+!!node.expanded];
        if (node.expanded) {
          bt.childrenCb(node.id, (children) => {
            node.children = children;
            children.forEach((c) => { bt.nodes[c.id] = c; });
              //bt.valueTipCb(c.id, path(c), (valueTip) => {
              //  c.value = valueTip;
              //});
            //});
            const selected = a.nextSibling.classList.contains('selected');
            a.parentNode.outerHTML = bt.render(node, selected);
            if (selected) e.getElementsByClassName('selected')[0].focus();
          });
        }
        a.parentNode.className = node.expanded ? '' : 'bt_collapsed';
      };

      const selectNode = (tgt, trg) => { // tgt=target,trg=trigger=1or0
        if (tgt.matches('.bt_text')) {
          const [sel] = e.getElementsByClassName('selected');
          sel && sel.classList.remove('selected');
          tgt.classList.add('selected');
          tgt.focus();
          if (o.click && trg) {
            const path = [];
            let div = tgt.parentNode;
            while (div && div !== e) {
              path.unshift(bt.nodes[div.dataset.id]);
              div = div.parentNode;
            }
            div && o.click(path);
          }
        }
      };

      let clickTimer = 0;
      e.onclick = (event) => {
        clearTimeout(clickTimer);
        if (event.target.matches('.bt_node_expand')) { toggleNode(event.target); }
        clickTimer = setTimeout(() => {
          selectNode(event.target, 1);
        }, 500);
        return !1;
      };

      e.ondblclick = (event) => {
        clearTimeout(clickTimer);
        const ps = event.target.previousSibling;
        if (ps && ps.matches('.bt_node_expand')) {
          toggleNode(ps);
          selectNode(event.target, 0);
        } else { selectNode(event.target, 1); }
        return !1;
      };

      e.onkeydown = (event) => {
        switch (event.which) {
          case 13:// case 37:case 38:case 39:case 40://Enter,Left,Up,Right,Down
            selectNode(event.target, 1);
            break;
          case 40:
          case 38: {
            const sp = [...e.getElementsByTagName('span')].filter(x => !!x.offsetWidth);
            for (let i = 0; i < sp.length; i += 1) {
              if (sp[i].classList.contains('selected')) {
                selectNode(sp[Math.max(0, Math.min(sp.length - 1, (i + event.which) - 39))]); break;
              }
            }
            return !1;
          }
          case 37: case 39: {
            const sel = e.getElementsByClassName('selected')[0];
            const left = event.which === 37;
            if (!!bt.nodes[sel.dataset.id].expanded === left) toggleNode(sel.previousSibling);
            else if (left) { selectNode(sel.parentNode.parentNode.getElementsByClassName('bt_text')[0]); }
            return !1;
          }
          case 116:// F5
            bt.refresh();
            break;
          default: break;
        }
        return !1;
      };
    }

    focus() {
      const [sel] = this.dom.getElementsByClassName('selected');
      sel && sel.focus();
    }

    render(node, selected) {
      const bt = this;
      let children = '';
      let expandable = '';
      if (node.expanded) children = node.children.map(x => bt.render(x)).join('');
      if (node.expandable) expandable = `<a class=bt_node_expand>${'+-'[+!!node.expanded]}</a>`;

      return `<table data-id="${node.id}"><tr>` +
        `${expandable}<span tabIndex=-1 data-id=${node.id}` +
        ` class="bt_icon_${node.icon} bt_text ${node.selected || selected ? 'selected' : ''}">` +
        `${node.text}</span></tr>${children}</table>`;
    }

    rebuild() {
      const bt = this;
      bt.nodes = {
        0: {
          id: 0,
          text: '',
          expanded: 1,
        }
      };
      bt.refresh();
    }

    refreshNode(node) {
      const bt = this;
      const oldNode = bt.nodes[node.id];
      bt.newNodes[node.id] = node;
      if (oldNode && oldNode.text === node.text && oldNode.expanded && node.expandable) {
        bt.pendingCalls += 1;
        bt.childrenCb(node.id, (children) => {
          node.expanded = 1;
          node.children = children;
          children.forEach(bt.refreshNode.bind(bt));
          bt.pendingCalls -= 1;
          !bt.pendingCalls && bt.replaceTree();
        });
      }
    }

    refresh() {
      const bt = this;
      if (bt.newNodes) return;
      bt.newNodes = {};
      bt.pendingCalls = 0;
      bt.refreshNode({
        id: 0,
        text: '',
        expandable: 1,
        icon: '',
      });
    }

    replaceTree() {
      const bt = this;
      if (!bt.newNodes) return;
      const [sel] = bt.dom.getElementsByClassName('selected');
      const hasFocus = !!$(bt.dom).find(':focus').length > 0;
      if (sel) {
        const n = bt.newNodes[sel.dataset.id];
        n && (n.selected = 1);
      }
      bt.dom.innerHTML = bt.newNodes[0].children.map(x => bt.render(x)).join('');
      bt.nodes = bt.newNodes;
      hasFocus && bt.focus();
      delete bt.newNodes;
    }
  }
  D.Bonsai = Bonsai;
}
<commit_msg>nodes in wse are now rendered with corresponding valueTip<commit_after>{
  class Bonsai {
    constructor(e, o) {
      // e:dom element, o:options={children:function(id,callback){...}, click:function(path){...}}
      const bt = this; // bonsai tree
      bt.rebuild = bt.rebuild.bind(bt);
      bt.render = bt.render.bind(bt);
      bt.refresh = bt.refresh.bind(bt);
      bt.childrenCb = o.children;
      bt.valueTipCb = o.valueTip;
      bt.dom = e;
      bt.rebuild();

      const toggleNode = (tgt) => {
        if (bt.newNodes) return;
        const a = tgt;
        const nodeElement = a.parentNode.parentNode;
        const node = bt.nodes[nodeElement.dataset.id];
        if (!node || !node.expandable) return;
        node.expanded = 1 - !!node.expanded; a.textContent = '+-'[+!!node.expanded];
        nodeElement.className = node.expanded ? '' : 'bt_collapsed';
        if (node.expanded) {
          bt.childrenCb(node.id, (children) => {
            const selected = a.nextSibling.classList.contains('selected');
            node.children = children;
            children.forEach((c) => {
              bt.nodes[c.id] = c;
              c.depth = node.depth + 1;
              c.path = node.path ? `${node.path}.${c.text}` : c.text;
              bt.valueTipCb(c, (vt) => {
                c.value = vt.tip[0];
                const elem = bt.dom.querySelector(`tr[data-id='${c.id}'] td.value_tip`);
                elem.innerText = vt.tip[0];
                elem.title = vt.tip.join('\n');
              });
            });
            nodeElement.outerHTML = bt.render(node, selected);
            if (selected) e.getElementsByClassName('selected')[0].focus();
          });
        } else {
          bt.refresh();
        }
      };

      const selectNode = (tgt, trg) => { // tgt=target,trg=trigger=1or0
        if (tgt.matches('.bt_text')) {
          const [sel] = e.getElementsByClassName('selected');
          sel && sel.classList.remove('selected');
          tgt.classList.add('selected');
          tgt.focus();
          if (o.click && trg) {
            o.click(tgt.dataset.path);
          }
        }
      };

      let clickTimer = 0;
      e.onclick = (event) => {
        clearTimeout(clickTimer);
        if (event.target.matches('.bt_node_expand')) { toggleNode(event.target); }
        clickTimer = setTimeout(() => {
          selectNode(event.target, 1);
        }, 500);
        return !1;
      };

      e.ondblclick = (event) => {
        clearTimeout(clickTimer);
        const ps = event.target.previousSibling;
        if (ps && ps.matches('.bt_node_expand')) {
          toggleNode(ps);
          selectNode(event.target, 0);
        } else { selectNode(event.target, 1); }
        return !1;
      };

      e.onkeydown = (event) => {
        switch (event.which) {
          case 13:// case 37:case 38:case 39:case 40://Enter,Left,Up,Right,Down
            selectNode(event.target, 1);
            break;
          case 40:
          case 38: {
            const sp = [...e.getElementsByTagName('span')].filter(x => !!x.offsetWidth);
            for (let i = 0; i < sp.length; i += 1) {
              if (sp[i].classList.contains('selected')) {
                selectNode(sp[Math.max(0, Math.min(sp.length - 1, (i + event.which) - 39))]); break;
              }
            }
            return !1;
          }
          case 37: case 39: {
            const sel = e.getElementsByClassName('selected')[0];
            const left = event.which === 37;
            if (!!bt.nodes[sel.dataset.id].expanded === left) toggleNode(sel.previousSibling);
            else if (left) { selectNode(sel.parentNode.parentNode.getElementsByClassName('bt_text')[0]); }
            return !1;
          }
          case 116:// F5
            bt.refresh();
            break;
          default: break;
        }
        return !1;
      };
    }

    focus() {
      const [sel] = this.dom.getElementsByClassName('selected');
      sel && sel.focus();
    }

    render(node, selected) {
      const bt = this;
      let children = '';
      let expandable = '';
      if (node.expanded) children = node.children.map(x => bt.render(x)).join('');
      if (node.expandable) expandable = `<a class=bt_node_expand>${'+-'[+!!node.expanded]}</a>`;

      return `<tr data-id="${node.id}">` +
        `<td style="padding-left:${node.depth}em;">${expandable}<span tabIndex=-1 data-id=${node.id} data-path=${node.path}` +
        ` class="bt_icon_${node.icon} bt_text ${node.selected || selected ? 'selected' : ''}">` +
        `${node.text}</span></td><td class="value_tip">${node.value}</td></tr>${children}`;
    }

    rebuild() {
      const bt = this;
      bt.nodes = {
        0: {
          id: 0,
          depth: 0,
          path: '',
          text: '',
          value: '',
          expanded: 1,
        }
      };
      bt.refresh();
    }

    refreshNode(node, path, depth) {
      const bt = this;
      const oldNode = bt.nodes[node.id];
      bt.newNodes[node.id] = node;
      node.depth = depth;
      node.path = path ? `${path}.${node.text}` : node.text;
      bt.valueTipCb(node, (vt) => {
        node.value = vt.tip[0];
        const elem = bt.dom.querySelector(`tr[data-id='${node.id}'] td.value_tip`);
        elem.innerText = vt.tip[0];
        elem.title = vt.tip.join('\n');
      });
      if (oldNode && oldNode.text === node.text && oldNode.expanded && node.expandable) {
        bt.pendingCalls += 1;
        bt.childrenCb(node.id, (children) => {
          node.expanded = 1;
          node.children = children;
          children.forEach(c => bt.refreshNode(c, node.path, node.depth + 1));
          bt.pendingCalls -= 1;
          !bt.pendingCalls && bt.replaceTree();
        });
      }
    }

    refresh() {
      const bt = this;
      if (bt.newNodes) return;
      bt.newNodes = {};
      bt.pendingCalls = 0;
      bt.refreshNode({
        id: 0,
        text: '',
        value: '',
        expandable: 1,
        icon: '',
      }, '', 0);
    }

    replaceTree() {
      const bt = this;
      if (!bt.newNodes) return;
      const [sel] = bt.dom.getElementsByClassName('selected');
      const hasFocus = !!$(bt.dom).find(':focus').length > 0;
      if (sel) {
        const n = bt.newNodes[sel.dataset.id];
        n && (n.selected = 1);
      }
      bt.dom.innerHTML = `<table><tbody>${bt.newNodes[0].children.map(x => bt.render(x)).join('')}</tbody></table>`;
      bt.nodes = bt.newNodes;
      hasFocus && bt.focus();
      delete bt.newNodes;
    }
  }
  D.Bonsai = Bonsai;
}
<|endoftext|>


<commit_before>import formatDistance from './_lib/formatDistance/index.js'
import formatLong from './_lib/formatLong/index.js'
import formatRelative from './_lib/formatRelative/index.js'
import localize from './_lib/localize/index.js'
import match from './_lib/match/index.js'

/**
 * @type {Locale}
 * @category Locales
 * @summary Norwegian Bokmål locale.
 * @language Norwegian Bokmål
 * @iso-639-2 nob
 * @author Hans-Kristian Koren [@Hanse]{@link https://github.com/Hanse}
 * @author Mikolaj Grzyb [@mikolajgrzyb]{@link https://github.com/mikolajgrzyb}
 */
var locale = {
  formatDistance: formatDistance,
  formatLong: formatLong,
  formatRelative: formatRelative,
  localize: localize,
  match: match,
  options: {
    weekStartsOn: 1 /* Monday */,
    firstWeekContainsDate: 4
  }
}

export default locale
<commit_msg>Add missing author tag to nb locale<commit_after>import formatDistance from './_lib/formatDistance/index.js'
import formatLong from './_lib/formatLong/index.js'
import formatRelative from './_lib/formatRelative/index.js'
import localize from './_lib/localize/index.js'
import match from './_lib/match/index.js'

/**
 * @type {Locale}
 * @category Locales
 * @summary Norwegian Bokmål locale.
 * @language Norwegian Bokmål
 * @iso-639-2 nob
 * @author Hans-Kristian Koren [@Hanse]{@link https://github.com/Hanse}
 * @author Mikolaj Grzyb [@mikolajgrzyb]{@link https://github.com/mikolajgrzyb}
 * @author Dag Stuan [@dagstuan]{@link https://github.com/dagstuan}
 */
var locale = {
  formatDistance: formatDistance,
  formatLong: formatLong,
  formatRelative: formatRelative,
  localize: localize,
  match: match,
  options: {
    weekStartsOn: 1 /* Monday */,
    firstWeekContainsDate: 4
  }
}

export default locale
<|endoftext|>


<commit_before>'use strict';

const SsdpClient = require('node-ssdp').Client;
const Request = require('request');
const URL = require('url');
const parseString = require('xml2js').parseString;

const ServiceProtocol = require('./service-protocol');

const SSDP_SERVICE_TYPE = 'urn:schemas-sony-com:service:IRCC:1';
const SERVICE_PROTOCOLS = [
  'accessControl',
  'appControl',
  'audio',
  'avContent',
  'browser',
  'cec',
  'encryption',
  'guide',
  'recording',
  'system',
  'videoScreen'
];
const DEFAULT_TIME_BETWEEN_COMMANDS = 350;

class Bravia {
  constructor(host, port = 80, psk = '0000', timeout = 5000) {
    this.host = host;
    this.port = port;
    this.psk = psk;
    this.timeout = timeout;
    this.protocols = SERVICE_PROTOCOLS;
    this.delay = DEFAULT_TIME_BETWEEN_COMMANDS;

    for (let key in this.protocols) {
      let protocol = this.protocols[key];
      this[protocol] = new ServiceProtocol(this, protocol);
    }

    this._url = `http://${this.host}:${this.port}/sony`;
    this._codes = [];
  }

  static discover(timeout = 3000) {
    return new Promise((resolve, reject) => {
      let ssdp = new SsdpClient();
      let discovered = [];

      ssdp.on('response', (headers, statusCode, data) => {
        if (statusCode === 200) {
          Request.get(headers.LOCATION, (error, response, body) => {
            if (!error && response.statusCode === 200) {
              parseString(body, (err, result) => {
                if (!err) {
                  try {
                    let device = result.root.device[0];
                    let service = device.serviceList[0].service
                      .find(service => service.serviceType[0] === SSDP_SERVICE_TYPE);

                    let api = URL.parse(service.controlURL[0]);
                    discovered.push({
                      host: api.host,
                      port: (api.port || 80),
                      friendlyName: device.friendlyName[0],
                      manufacturer: device.manufacturer[0],
                      manufacturerURL: device.manufacturerURL[0],
                      modelName: device.modelName[0],
                      UDN: device.UDN[0]
                    });
                  } catch(e) {
                    failed(new Error(`Unexpected or malformed discovery response: ${result}.`));
                  }
                } else {
                  failed(new Error(`Failed to parse the discovery response: ${body}.`));
                }
              });
            } else {
              failed(new Error(`Error retrieving the description metadata for device ${data.address}.`));
            }
          });
        }
      });

      ssdp.search(SSDP_SERVICE_TYPE);

      let failed = error => {
        ssdp.stop();
        clearTimeout(timer);
        reject(error);
      };

      let timer = setTimeout(() => {
        ssdp.stop();
        resolve(discovered);
      }, timeout);
    });
  }

  getIRCCCodes() {
    return new Promise((resolve, reject) => {
      if (this._codes.length > 0) {
        resolve(this._codes);
        return;
      }

      this.system
          .invoke('getRemoteControllerInfo')
          .then(codes => {
            this._codes = codes;
            resolve(this._codes);
          }, reject);
    });
  }

  send(codes) {
    return new Promise((resolve, reject) => {
      if (typeof codes === 'string') {
        codes = [codes];
      }

      let index = 0;
      let next = () => {
        if (index < codes.length) {
          let code = codes[index++];
          this.getIRCCCodes()
              .then(response => {
                let ircc = response.find(ircc => ircc.name === code || ircc.value === code);
                if (!ircc) {
                  reject(new Error(`Unknown IRCC code ${code}.`));
                  return;
                }

                let body = `<?xml version="1.0"?>
                  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
                      <s:Body>
                          <u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1">
                              <IRCCCode>${ircc}</IRCCCode>
                          </u:X_SendIRCC>
                      </s:Body>
                  </s:Envelope>`;

                this._request({
                  path: '/IRCC',
                  body: body
                }).then(() => setTimeout(() => next(), this.delay), reject);
              }, reject);
          } else {
            resolve();
          }
      };

      next();
    });
  }

  _request(options) {
    return new Promise((resolve, reject) => {
      options.timeout = this.timeout;
      options.url = this._url + options.path;
      options.headers = {
        'Content-Type': 'text/xml; charset=UTF-8',
        'SOAPACTION': '"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"',
        'X-Auth-PSK': this.psk
      };

      Request.post(options, (error, response, body) => {
        if (!error && response.statusCode === 200) {
          resolve(body);
        } else {
          if (error) {
            reject(error);
          } else if (body.error) {
            reject(new Error(body.error[1]));
          } else {
            parseString(body, (err, result) => {
              if (!err) {
                try {
                  reject(new Error(result['s:Envelope']['s:Body'][0]['s:Fault'][0]['detail'][0]['UPnPError'][0]['errorDescription'][0]));
                } catch (e) {
                  reject(new Error(`Unexpected or malformed error response: ${result}.`));
                }
              } else {
                reject(new Error(`Failed to parse the error response: ${body}.`));
              }
            });
          }
        }
      });
    });
  }
}

module.exports = Bravia;
<commit_msg>Re-wrote send() method to also accept raw IRCC codes<commit_after>'use strict';

const SsdpClient = require('node-ssdp').Client;
const Request = require('request');
const URL = require('url');
const parseString = require('xml2js').parseString;

const ServiceProtocol = require('./service-protocol');

const SSDP_SERVICE_TYPE = 'urn:schemas-sony-com:service:IRCC:1';
const SERVICE_PROTOCOLS = [
  'accessControl',
  'appControl',
  'audio',
  'avContent',
  'browser',
  'cec',
  'encryption',
  'guide',
  'recording',
  'system',
  'videoScreen'
];
const DEFAULT_TIME_BETWEEN_COMMANDS = 350;

class Bravia {
  constructor(host, port = 80, psk = '0000', timeout = 5000) {
    this.host = host;
    this.port = port;
    this.psk = psk;
    this.timeout = timeout;
    this.protocols = SERVICE_PROTOCOLS;
    this.delay = DEFAULT_TIME_BETWEEN_COMMANDS;

    for (let key in this.protocols) {
      let protocol = this.protocols[key];
      this[protocol] = new ServiceProtocol(this, protocol);
    }

    this._url = `http://${this.host}:${this.port}/sony`;
    this._codes = [];
  }

  static discover(timeout = 3000) {
    return new Promise((resolve, reject) => {
      let ssdp = new SsdpClient();
      let discovered = [];

      ssdp.on('response', (headers, statusCode, data) => {
        if (statusCode === 200) {
          Request.get(headers.LOCATION, (error, response, body) => {
            if (!error && response.statusCode === 200) {
              parseString(body, (err, result) => {
                if (!err) {
                  try {
                    let device = result.root.device[0];
                    let service = device.serviceList[0].service
                      .find(service => service.serviceType[0] === SSDP_SERVICE_TYPE);

                    let api = URL.parse(service.controlURL[0]);
                    discovered.push({
                      host: api.host,
                      port: (api.port || 80),
                      friendlyName: device.friendlyName[0],
                      manufacturer: device.manufacturer[0],
                      manufacturerURL: device.manufacturerURL[0],
                      modelName: device.modelName[0],
                      UDN: device.UDN[0]
                    });
                  } catch(e) {
                    failed(new Error(`Unexpected or malformed discovery response: ${result}.`));
                  }
                } else {
                  failed(new Error(`Failed to parse the discovery response: ${body}.`));
                }
              });
            } else {
              failed(new Error(`Error retrieving the description metadata for device ${data.address}.`));
            }
          });
        }
      });

      ssdp.search(SSDP_SERVICE_TYPE);

      let failed = error => {
        ssdp.stop();
        clearTimeout(timer);
        reject(error);
      };

      let timer = setTimeout(() => {
        ssdp.stop();
        resolve(discovered);
      }, timeout);
    });
  }

  getIRCCCodes() {
    return new Promise((resolve, reject) => {
      if (this._codes.length > 0) {
        resolve(this._codes);
        return;
      }

      this.system
          .invoke('getRemoteControllerInfo')
          .then(codes => {
            this._codes = codes;
            resolve(this._codes);
          }, reject);
    });
  }

  send(codes) {
    return new Promise((resolve, reject) => {
      if (typeof codes === 'string') {
        codes = [codes];
      }

      let index = 0;
      let next = () => {
        if (index < codes.length) {
          let code = codes[index++];
          if (/^[A]{5}[a-zA-Z0-9]{13}[\=]{2}$/.test(code)) {
            send(code);
          } else {
            this.getIRCCCodes()
                .then(response => {
                  let ircc = response.find(ircc => ircc.name === code);
                  if (!ircc) {
                    reject(new Error(`Unknown IRCC code ${code}.`));
                    return;
                  }

                  send(ircc.value);
                }, reject);
          }
        } else {
          resolve();
        }
      };

      let send = code => {
        let body = `<?xml version="1.0"?>
          <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
              <s:Body>
                  <u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1">
                      <IRCCCode>${code}</IRCCCode>
                  </u:X_SendIRCC>
              </s:Body>
          </s:Envelope>`;

        this._request({
          path: '/IRCC',
          body: body
        }).then(() => setTimeout(() => next(), this.delay), reject);
      };

      next();
    });
  }

  _request(options) {
    return new Promise((resolve, reject) => {
      options.timeout = this.timeout;
      options.url = this._url + options.path;
      options.headers = {
        'Content-Type': 'text/xml; charset=UTF-8',
        'SOAPACTION': '"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"',
        'X-Auth-PSK': this.psk
      };

      Request.post(options, (error, response, body) => {
        if (!error && response.statusCode === 200) {
          resolve(body);
        } else {
          if (error) {
            reject(error);
          } else if (body.error) {
            reject(new Error(body.error[1]));
          } else {
            parseString(body, (err, result) => {
              if (!err) {
                try {
                  reject(new Error(result['s:Envelope']['s:Body'][0]['s:Fault'][0]['detail'][0]['UPnPError'][0]['errorDescription'][0]));
                } catch (e) {
                  reject(new Error(`Unexpected or malformed error response: ${result}.`));
                }
              } else {
                reject(new Error(`Failed to parse the error response: ${body}.`));
              }
            });
          }
        }
      });
    });
  }
}

module.exports = Bravia;
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  routing: Ember.inject.service('-routing'),
  feedModel: null,
  userModel: null,
  parseFetchInfoResponse: function(response) {
    var store = this.get('store');
    var existing = response.warnings.map(function(i) {return i.onestop_id});
    // Feeds
    // Note: store.normalize operates in-place!
    var feed_data = store.normalize('feed', response.feed);
    var feedModel = existing.contains(feed_data.id) ? store.push('feed', feed_data) : store.createRecord('feed', feed_data);
    // Operators
    store.unloadAll('operator');
    (response.operators || []).forEach(function(operator) {
      var operator_data = store.normalize('operator', operator);
      operator_data.feeds = [feedModel];
      var operatorModel = existing.contains(operator_data.id) ? store.push('operator', operator_data) : store.createRecord('operator', operator_data);
    });
    // Reset the feedModel reference;
    this.set('feedModel', feedModel);
    return feedModel;
  },
  parseFetchInfoErrors: function(response){
    var feedModel = this.get('feedModel');
    response.errors.forEach(function(error){
      feedModel.get('errors').add('url', error.message);
    });
  },
  createFeedAndUserModels: function() {
    var newFeedModel = this.get('store').createRecord('feed', {});
		var newUserModel = this.get('store').createRecord('user', {});
    this.set('feedModel', newFeedModel);
    this.set('userModel', newUserModel);
    return {
      feed: newFeedModel,
      user: newUserModel
    };
  },
  getFeedOrTransitionToStart: function() {
    if (this.feedModel === null) {
      return this.get('routing').transitionTo('feeds.new');
    } else {
      return this.feedModel;
    }
  },
  toChangeset: function() {
    var feedModel = this.get('feedModel');
    var changes = [];
    feedModel
      .get('operators')
      .filterBy('hasDirtyAttributes', true)
      .filterBy('include_in_changeset', true)
      .map(function(operator) {
        changes.push({
          action: 'createUpdate',
          operator: operator.toChange()
        });
      });
    changes.push({
      action: 'createUpdate',
      feed: feedModel.toChange()
    });
    var changeset = this.get('store').createRecord('changeset', {
      notes: `Changed submitted from Feed Registry for feed at ${feedModel.get('url')}`,
      payload: {
        changes: changes
      }
    });
		changeset.set('user', this.get('userModel'));
    return changeset;
  }
});
<commit_msg>Logging<commit_after>import Ember from 'ember';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  routing: Ember.inject.service('-routing'),
  feedModel: null,
  userModel: null,
  parseFetchInfoResponse: function(response) {
    var store = this.get('store');
    var existing = response.warnings.map(function(i) {return i.onestop_id});
    // Feeds
    // Note: store.normalize operates in-place!
    var feed_data = store.normalize('feed', response.feed);
    var feedModel = existing.contains(feed_data.id) ? store.push('feed', feed_data) : store.createRecord('feed', feed_data);
    // Operators
    store.unloadAll('operator');
    (response.operators || []).forEach(function(operator) {
      var operator_data = store.normalize('operator', operator);
      operator_data.feeds = [feedModel];
      var operatorModel = existing.contains(operator_data.id) ? store.push('operator', operator_data) : store.createRecord('operator', operator_data);
    });
    // Reset the feedModel reference;
    this.set('feedModel', feedModel);
    return feedModel;
  },
  parseFetchInfoErrors: function(response){
    var feedModel = this.get('feedModel');
    response.errors.forEach(function(error){
      feedModel.get('errors').add('url', error.message);
    });
  },
  createFeedAndUserModels: function() {
    var newFeedModel = this.get('store').createRecord('feed', {});
		var newUserModel = this.get('store').createRecord('user', {});
    this.set('feedModel', newFeedModel);
    this.set('userModel', newUserModel);
    return {
      feed: newFeedModel,
      user: newUserModel
    };
  },
  getFeedOrTransitionToStart: function() {
    if (this.feedModel === null) {
      return this.get('routing').transitionTo('feeds.new');
    } else {
      return this.feedModel;
    }
  },
  toChangeset: function() {
    var feedModel = this.get('feedModel');
    var changes = [];
    feedModel
      .get('operators')
      .filterBy('hasDirtyAttributes', true)
      .filterBy('include_in_changeset', true)
      .map(function(operator) {
        changes.push({
          action: 'createUpdate',
          operator: operator.toChange()
        });
      });
    changes.push({
      action: 'createUpdate',
      feed: feedModel.toChange()
    });
    console.log("Change payload:");
    console.log(changes);
    var changeset = this.get('store').createRecord('changeset', {
      notes: `Changed submitted from Feed Registry for feed at ${feedModel.get('url')}`,
      payload: {
        changes: changes
      }
    });
		changeset.set('user', this.get('userModel'));
    return changeset;
  }
});
<|endoftext|>


<commit_before>var cli = require('aurelia-cli');

cli.command('bundle', {
  js: {
    "dist/app-bundle": {
      modules: [
        '*',
        'aurelia-bootstrapper',
        'aurelia-fetch-client',
        'aurelia-router',
        'aurelia-animator-css',
        'github:aurelia/templating-binding',
        'github:aurelia/templating-resources',
        'github:aurelia/templating-router',
        'github:aurelia/loader-default',
        'github:aurelia/history-browser'
      ],
      options: {
        inject: true
      }
    }
  },
  template: {
    "dist/app-bundle": {
      pattern: 'dist/*.html',
      options: {
        inject: true
      }
    }
  }
});
<commit_msg>feat(bundle config): package path<commit_after>var cli = require('aurelia-cli');

var config = {
  js: {
    "dist/app-bundle": {
      modules: [
        '*',
        'aurelia-bootstrapper',
        'aurelia-fetch-client',
        'aurelia-router',
        'aurelia-animator-css',
        'github:aurelia/templating-binding',
        'github:aurelia/templating-resources',
        'github:aurelia/templating-router',
        'github:aurelia/loader-default',
        'github:aurelia/history-browser'
      ],
      options: {
        inject: true
      }
    }
  },
  template: {
    "dist/app-bundle": {
      pattern: 'dist/*.html',
      options: {
        inject: {
          indexFile: 'index.html',
          destFile: 'dest_index.html'
        }
      }
    }
  }
};

cli.command('bundle', config);
cli.command('unbundle', config);

<|endoftext|>


<commit_before>define(["avalon"], function(avalon) {
    var DOC = document
    var root = DOC.documentElement
    var IEEventMap = {
        "change": "click",
        "focus": "focusin",
        "blur": "focusout"
    }
    function getVal(elem) {
        var type = elem.type
        if (type === "select-multiple") {
            if (elem.selectedIndex > -1) {
                var ret = []
                for (var i = 0, el; el = elem.options[i++]; ) {
                    ret.push(el.selected)
                }
                return ret.join("-")
            } else {
                return ""
            }

        } else if (elem.nodeName.toLowerCase() === "select") {
            return  elem.selectedIndex;
        }

        return  elem.value
    }

    function testChange(e) {
        var callbacks = liveMap["fixChangechange"]
        var target = e.target
        for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
            var elem = obj.elem
            if (root.contains(elem)) {
                if (elem === target) {
                    var curVal = getVal(elem)
                    if (obj.__change__ !== curVal) {
                        e.type = "change"
                        obj.fn.call(elem, e)
                        obj.__change__ = curVal
                    }
                }
            } else {
                dequeue(callbacks, obj, i)
            }
        }
    }
    function dequeue(callbacks, obj, i) {
        var parent = obj.elem.parentNode
        if (!parent || parent.nodeType == 11) {
            callbacks.splice(i, 1)
        }
    }
    var liveMap = avalon.bindingHandlers.live = function(data, vmodels) {
        var type = data.param
        var elem = data.element
        var live = "noFix"
        if (!DOC.createEvent) {
            if (/focus|blur/.test(type)) {
                live = "fixFocus"//旧式IE下使用focusin与focusout来模拟focus、blur，使用click来模拟复选框，单选框的change事件
            } else if (type == "change") {
                var elemType = elem.type
                if (elemType == "radio" || elemType === "checkbox") {
                    live = "fixFocus"
                    if (!("_just_changed" in elem)) {//确保只绑定一次
                        elem._just_changed = false
                        elem.attachEvent("onpropertychange", function(e) {
                            if (e.propertyName == "checked") {
                                elem._just_changed = true
                            }
                        })
                    }
                } else {
                    live = "fixChange"
                }
            } else if (/submit|reset|select/.test(type)) {
                live = false//对于一些模拟成本太大的事件直接使用普通的事件绑定
            }
        }

        if (live) {
            if (!liveMap[live + type]) {
                liveMap[live + type] = []
                if (live === "noFix") {
                    avalon.bind(DOC, type, function(e) {//W3C
                        var callbacks = liveMap[live + type]
                        var target = e.target
                        for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
                            if (root.contains(obj.elem)) {
                                if (obj.elem === target || obj.elem.contains(target)) {
                                    obj.fn.call(obj.elem, e)
                                }
                            } else {
                                dequeue(callbacks, obj, i)
                            }
                        }
                    }, true)
                }

                if (live === "fixFocus") {//旧式浏览器的focus，blur，单选框与复选枉的change
                    avalon.bind(DOC, IEEventMap[type], function(e) {
                        var callbacks = liveMap[live + type]
                        var target = e.target
                        for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
                            var elem = obj.elem
                            if (root.contains(elem)) {
                                if (elem === target || elem.contains(target)) {
                                    if (type === "change") {
                                        if (elem._just_changed === true) {
                                            e.type = "change"
                                            obj.fn.call(elem, e)
                                            elem._just_changed = false
                                        }
                                    } else {
                                        e.type = type
                                        obj.fn.call(elem, e)
                                    }
                                }
                            } else {
                                dequeue(callbacks, obj, i)
                            }
                        }
                    })

                }
                if (live === "fixChange") {
                    avalon.bind(DOC, "beforeactivate", testChange)
                    avalon.bind(DOC, "beforedeactivate", testChange)
                }
            }
            data.specialBind = function(elem, fn) {
                var obj = {
                    elem: elem,
                    fn: fn
                }
                if (/focus|blur/.test(type)) {
                    elem.tabIndex = elem.tabIndex || -1
                }
                if (live === "fixChange") {
                    obj.__change__ = getVal(elem)
                }
                var callbacks = liveMap[live + type]
                callbacks.unshift(obj)
                data.specialUnbind = function() {
                    avalon.Array.remove(callbacks, obj)
                    delete data.specialBind
                    delete data.specialUnbind
                }
            }
        }

        avalon.bindingHandlers.on(data, vmodels)
    }

})
//avalon的事件代理模块<commit_msg>fix avalon.live<commit_after>define(["avalon"], function(avalon) {
    var DOC = document
    var root = DOC.documentElement
    var IEEventMap = {
        "change": "click",
        "focus": "focusin",
        "blur": "focusout"
    }
    function getVal(elem) {
        var type = elem.type
        if (type === "select-multiple") {
            if (elem.selectedIndex > -1) {
                var ret = []
                for (var i = 0, el; el = elem.options[i++]; ) {
                    ret.push(el.selected)
                }
                return ret.join("-")
            } else {
                return ""
            }

        } else if (elem.nodeName.toLowerCase() === "select") {
            return  elem.selectedIndex;
        }

        return  elem.value
    }

    function testChange(e) {
        var callbacks = liveMap["fixChangechange"]
        var target = e.target
        for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
            var elem = obj.elem
            if (root.contains(elem)) {
                if (elem === target) {
                    var curVal = getVal(elem)
                    if (obj.__change__ !== curVal) {
                        e.type = "change"
                        obj.fn.call(elem, e)
                        obj.__change__ = curVal
                    }
                }
            } else {
                dequeue(callbacks, obj, i)
            }
        }
    }
    function dequeue(callbacks, obj, i) {
        var parent = obj.elem.parentNode
        if (!parent || parent.nodeType == 11) {
            callbacks.splice(i, 1)
        }
    }
    var liveMap = avalon.bindingHandlers.live = function(data, vmodels) {
        var type = data.param
        var elem = data.element
        data.type = "on"
        var live = "noFix"
        if (!DOC.createEvent) {
            if (/focus|blur/.test(type)) {
                live = "fixFocus"//旧式IE下使用focusin与focusout来模拟focus、blur，使用click来模拟复选框，单选框的change事件
            } else if (type == "change") {
                var elemType = elem.type
                if (elemType == "radio" || elemType === "checkbox") {
                    live = "fixFocus"
                    if (!("_just_changed" in elem)) {//确保只绑定一次
                        elem._just_changed = false
                        elem.attachEvent("onpropertychange", function(e) {
                            if (e.propertyName == "checked") {
                                elem._just_changed = true
                            }
                        })
                    }
                } else {
                    live = "fixChange"
                }
            } else if (/submit|reset|select/.test(type)) {
                live = false//对于一些模拟成本太大的事件直接使用普通的事件绑定
            }
        }

        if (live) {
            if (!liveMap[live + type]) {
                liveMap[live + type] = []
                if (live === "noFix") {
                    avalon.bind(DOC, type, function(e) {//W3C
                        var callbacks = liveMap[live + type]
                        var target = e.target
                        for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
                            if (root.contains(obj.elem)) {
                                if (obj.elem === target || obj.elem.contains(target)) {
                                    obj.fn.call(obj.elem, e)
                                }
                            } else {
                                dequeue(callbacks, obj, i)
                            }
                        }
                    }, true)
                }

                if (live === "fixFocus") {//旧式浏览器的focus，blur，单选框与复选枉的change
                    avalon.bind(DOC, IEEventMap[type], function(e) {
                        var callbacks = liveMap[live + type]
                        var target = e.target
                        for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
                            var elem = obj.elem
                            if (root.contains(elem)) {
                                if (elem === target || elem.contains(target)) {
                                    if (type === "change") {
                                        if (elem._just_changed === true) {
                                            e.type = "change"
                                            obj.fn.call(elem, e)
                                            elem._just_changed = false
                                        }
                                    } else {
                                        e.type = type
                                        obj.fn.call(elem, e)
                                    }
                                }
                            } else {
                                dequeue(callbacks, obj, i)
                            }
                        }
                    })

                }
                if (live === "fixChange") {
                    avalon.bind(DOC, "beforeactivate", testChange)
                    avalon.bind(DOC, "beforedeactivate", testChange)
                }
            }
            data.specialBind = function(elem, fn) {
                var obj = {
                    elem: elem,
                    fn: fn
                }
                if (/focus|blur/.test(type)) {
                    elem.tabIndex = elem.tabIndex || -1
                }
                if (live === "fixChange") {
                    obj.__change__ = getVal(elem)
                }
                var callbacks = liveMap[live + type]
                callbacks.unshift(obj)
                data.specialUnbind = function() {
                    avalon.Array.remove(callbacks, obj)
                    delete data.specialBind
                    delete data.specialUnbind
                }
            }
        }

        avalon.bindingHandlers.on(data, vmodels)
    }

})
//avalon的事件代理模块<|endoftext|>


<commit_before>var test = require("tap").test,
    request = require("supertest");

var mockEmail = "test@example.org",
    mockSession = require("./mock.session"),
    mockUser = require("./mock.user")(),
    mockFilter = require("./mock.filter"),
    mockSanitizer = require("./mock.sanitizer"),
    mockStore = require("./mock.store");

var express = require("express");
var app = express.createServer();

app.use(mockSession({
  email: mockEmail
}))
  .use(express.bodyParser());

require("../routes")(app, mockUser, mockFilter, mockSanitizer, mockStore);

test("whoami API valid", function(t) {
  request(app)
    .get("/api/whoami")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      t.deepEqual(res.body, {
        email: mockEmail,
        name: mockEmail,
        username: mockEmail
      }, "response should have 3 attributes");

      t.end();
    });
});

test("project data get with error", function(t) {
  mockUser.error = true;
  mockUser.doc = false;

  request(app)
    .get("/api/project/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("project data get not found", function(t) {
  mockUser.error = false;
  mockUser.doc = false;

  request(app)
    .get("/api/project/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 404, "status code is 404");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("project data get valid", function(t) {
  mockUser.error = false;
  mockUser.doc = true;

  request(app)
    .get("/api/project/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");

      // This is very obtuse...
      var mockData = mockUser.generateMockData(1234);
      mockData.data = JSON.parse(mockData.data);
      mockData.data.name = mockData.name;
      mockData.data.projectID = mockData.id;
      mockData.data.author = mockData.author;
      mockData = mockData.data;
      t.deepEqual(res.body, mockData, "saved data is equal");

      t.end();
    });
});

test("delete project not found", function(t) {
  mockUser.error = true;

  request(app)
    .post("/api/delete/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 404, "status code is 404");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("delete project found", function(t) {
  mockUser.error = false;

  request(app)
    .post("/api/delete/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      // wtf was I think when returning error is a good thing?
      t.equal(res.body.error, "okay", "json returns okay");

      t.end();
    });
});

/*******************
 * DANGER ZONE     *
 * HERE BE DRAGONS *
 *******************/

test("create project with error", function(t) {
  mockUser.error = true;

  var mockData = mockUser.generateMockData(1234);
  delete mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "mock error", "error message is correct");

      t.end();
    });
});

test("create project with no data", function(t) {
  mockUser.error = false;

  var mockData = mockUser.generateMockData(1234);
  delete mockData.id;
  delete mockData.data;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "not enough parameters to update", "error message is correct");

      t.end();
    });
});

test("create project valid", function(t) {
  mockUser.error = false;

  var mockData = mockUser.generateMockData(1234);
  mockData.data = JSON.parse(mockData.data);
  delete mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "okay");

      var id = res.body.project.id;
      t.ok(id, "id is present");
      delete res.body.project.id;

      mockData.data = JSON.stringify(mockData.data);
      t.deepEqual(res.body.project, mockData, "saved data is equal");

      t.end();
    });
});

test("update project with error", function(t) {
  mockUser.error = true;
  mockUser.doc = true;

  var mockData = mockUser.generateMockData(1234);
  mockData.data = JSON.parse(mockData.data);
  mockData.id = mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "mock error");

      t.end();
    });
});

test("update project with no matching id", function(t) {
  mockUser.error = false;
  mockUser.doc = false;

  var mockData = mockUser.generateMockData(1234);
  mockData.data = JSON.parse(mockData.data);
  mockData.id = mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "project id not found");

      t.end();
    });
});

test("update project valid", function(t) {
  mockUser.error = false;
  mockUser.doc = true;

  var mockData = mockUser.generateMockData(1234);
  mockData.data = JSON.parse(mockData.data);
  mockData.id = mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "okay", "status is okay");
      mockData.data = JSON.stringify(mockData.data);
      t.deepEqual(res.body.project, mockData, "saved data is equal");

      t.end();
    });
});

test("remix project with error", function(t) {
  mockUser.error = true;
  mockUser.doc = false;

  request(app)
    .get("/api/remix/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("remix project with no doc", function(t) {
  mockUser.error = false;
  mockUser.doc = false;

  request(app)
    .get("/api/remix/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 404, "status code is 404");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("remix project valid", function(t) {
  mockUser.error = false;
  mockUser.doc = true;

  request(app)
    .get("/api/remix/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");

      // This is very obtuse...
      var mockData = mockUser.generateMockData(1234);
      mockData.data = JSON.parse(mockData.data);
      mockData.data.name = "Remix of " + mockData.name;
      mockData = mockData.data;
      t.deepEqual(res.body, mockData, "saved data is equal");

      t.end();
    });
});

test("clean up server connections", function(t) {
  app.close();
  t.end();
});
<commit_msg>Bug 2478 - Fix test regression from Bug 2344<commit_after>var test = require("tap").test,
    request = require("supertest");

var mockEmail = "test@example.org",
    mockSession = require("./mock.session"),
    mockUser = require("./mock.user")(),
    mockFilter = require("./mock.filter"),
    mockSanitizer = require("./mock.sanitizer"),
    mockStore = require("./mock.store");

var express = require("express");
var app = express.createServer();

app.use(mockSession({
  email: mockEmail
}))
  .use(express.bodyParser());

require("../routes")(app, mockUser, mockFilter, mockSanitizer, mockStore);

test("whoami API valid", function(t) {
  request(app)
    .get("/api/whoami")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      t.deepEqual(res.body, {
        email: mockEmail,
        name: mockEmail,
        username: mockEmail
      }, "response should have 3 attributes");

      t.end();
    });
});

test("project data get with error", function(t) {
  mockUser.error = true;
  mockUser.doc = false;

  request(app)
    .get("/api/project/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("project data get not found", function(t) {
  mockUser.error = false;
  mockUser.doc = false;

  request(app)
    .get("/api/project/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 404, "status code is 404");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("project data get valid", function(t) {
  mockUser.error = false;
  mockUser.doc = true;

  request(app)
    .get("/api/project/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");

      // This is very obtuse...
      var mockData = mockUser.generateMockData(1234);
      mockData.data = JSON.parse(mockData.data);
      mockData.data.name = mockData.name;
      mockData.data.projectID = mockData.id;
      mockData.data.author = mockData.author;
      mockData = mockData.data;
      t.deepEqual(res.body, mockData, "saved data is equal");

      t.end();
    });
});

test("delete project not found", function(t) {
  mockUser.error = true;

  request(app)
    .post("/api/delete/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 404, "status code is 404");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("delete project found", function(t) {
  mockUser.error = false;

  request(app)
    .post("/api/delete/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      // wtf was I think when returning error is a good thing?
      t.equal(res.body.error, "okay", "json returns okay");

      t.end();
    });
});

/*******************
 * DANGER ZONE     *
 * HERE BE DRAGONS *
 *******************/

test("create project with error", function(t) {
  mockUser.error = true;

  var mockData = mockUser.generateMockData(1234);
  delete mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "mock error", "error message is correct");

      t.end();
    });
});

test("create project with no data", function(t) {
  mockUser.error = false;

  var mockData = mockUser.generateMockData(1234);
  delete mockData.id;
  delete mockData.data;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "not enough parameters to update", "error message is correct");

      t.end();
    });
});

test("create project valid", function(t) {
  mockUser.error = false;

  var mockData = mockUser.generateMockData();
  mockData.data = JSON.parse(mockData.data);
  delete mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "okay", "status is okay");
      t.ok(res.body.projectId, "id is present");

      t.end();
    });
});

test("update project with error", function(t) {
  mockUser.error = true;
  mockUser.doc = true;

  var mockData = mockUser.generateMockData(1234);
  mockData.data = JSON.parse(mockData.data);
  mockData.id = mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "mock error");

      t.end();
    });
});

test("update project with no matching id", function(t) {
  mockUser.error = false;
  mockUser.doc = false;

  var mockData = mockUser.generateMockData(1234);
  mockData.data = JSON.parse(mockData.data);
  mockData.id = mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "project id not found");

      t.end();
    });
});

test("update project valid", function(t) {
  mockUser.error = false;
  mockUser.doc = true;

  var mockData = mockUser.generateMockData(1234);
  mockData.data = JSON.parse(mockData.data);
  mockData.id = mockData.id;

  request(app)
    .post("/api/project/1234")
    .send(mockData)
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");
      t.equal(res.body.error, "okay", "status is okay");
      mockData.data = JSON.stringify(mockData.data);
      t.deepEqual(res.body.project, mockData, "saved data is equal");

      t.end();
    });
});

test("remix project with error", function(t) {
  mockUser.error = true;
  mockUser.doc = false;

  request(app)
    .get("/api/remix/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 500, "status code is 500");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("remix project with no doc", function(t) {
  mockUser.error = false;
  mockUser.doc = false;

  request(app)
    .get("/api/remix/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 404, "status code is 404");
      t.equal(res.type, "application/json", "response type is json");
      t.ok(res.body.error, "json contains an error");

      t.end();
    });
});

test("remix project valid", function(t) {
  mockUser.error = false;
  mockUser.doc = true;

  request(app)
    .get("/api/remix/1234")
    .end(function(err, res) {
      t.equal(res.statusCode, 200, "status code is 200");
      t.equal(res.type, "application/json", "response type is json");

      // This is very obtuse...
      var mockData = mockUser.generateMockData(1234);
      mockData.data = JSON.parse(mockData.data);
      mockData.data.name = "Remix of " + mockData.name;
      mockData = mockData.data;
      t.deepEqual(res.body, mockData, "saved data is equal");

      t.end();
    });
});

test("clean up server connections", function(t) {
  app.close();
  t.end();
});
<|endoftext|>


<commit_before>'use strict';

var mocks, baseUrl;

beforeEach(function() {
  baseUrl = 'http://localhost:3000/';
  mocks = {
    configUrl: baseUrl + 'configs',
    configResults: {
      configs: [{
        images: {
          base_url: 'http://image.tmdb.org/t/p/', // jshint ignore:line
          secure_base_url: 'https://image.tmdb.org/t/p/', // jshint ignore:line
          backdrop_sizes: ['w300', 'w780', 'w1280', 'original'], // jshint ignore:line
          logo_sizes: ['w45', 'w92', 'w154', 'w185', 'w300', 'w500', 'original'], // jshint ignore:line
          poster_sizes: ['w92', 'w154', 'w185', 'w342', 'w500', 'w780', 'original'], // jshint ignore:line
          profile_sizes: ['w45', 'w185', 'h632', 'original'], // jshint ignore:line
          still_sizes: ['w92', 'w185', 'w300', 'original'] // jshint ignore:line
        }
      }]
    },
    allMoviesUrl: baseUrl + 'movies',
    allMoviesResults: {
      movies: [{
        title: 'Fight Club',
        themoviedbid: 550,
        id: 1,
        createdAt: '2015-02-13T05:44:34.000Z',
        updatedAt: '2015-02-13T05:44:34.000Z'
      }, {
        title: 'Guardians of the Galaxy',
        themoviedbid: 118340,
        id: 2,
        createdAt: '2015-02-13T06:19:29.000Z',
        updatedAt: '2015-02-13T06:19:29.000Z'
      }]
    },
    createMovieUrl: baseUrl + 'movies',
    createMovieResults: {
      movie: {
        title: 'The Matrix',
        themoviedbid: 603,
        id: 3,
        createdAt: '2015-02-13T05:44:34.000Z',
        updatedAt: '2015-02-13T05:44:34.000Z'
      }
    },
    searchUrl: baseUrl + 'movies/search/SDF',
    searchResults: {
      page: 1,
      results: [{
        adult: false,
        backdrop_path: '/qLxJlnfZ9b2BMzvhzvnJMBi7EGH.jpg', // jshint ignore:line
        id: 14114,
        original_title: 'You Got Served', // jshint ignore:line
        release_date: '2004-01-30', // jshint ignore:line
        poster_path: '/3ESy6TiBPSYIbEES1zNspdYtMtw.jpg', // jshint ignore:line
        popularity: 0.33499858390984,
        title: 'You Got Served',
        video: false,
        vote_average: 6.3, // jshint ignore:line
        vote_count: 9 // jshint ignore:line
      }],
      total_pages: 1, // jshint ignore:line
      total_results: 1 // jshint ignore:line
    },
    infoUrl: baseUrl + 'movies/info/550',
    infoResults: {
      adult: false,
      backdrop_path: '/8uO0gUM8aNqYLs1OsTBQiXu0fEv.jpg', // jshint ignore:line
      belongs_to_collection: null, // jshint ignore:line
      budget: 63000000,
      genres: [{
        id: 18,
        name: 'Drama'
      }],
      homepage: '',
      id: 550,
      imdb_id: 'tt0137523', // jshint ignore:line
      original_language: 'en', // jshint ignore:line
      original_title: 'Fight Club', // jshint ignore:line
      overview: 'A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground " fight clubs " forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.',
      popularity: 3.16634464772838,
      poster_path: '/2lECpi35Hnbpa4y46JX0aY3AWTy.jpg', // jshint ignore:line
      production_companies: [{ // jshint ignore:line
        name: '20th Century Fox',
        id: 25
      }, {
        name: 'Fox 2000 Pictures',
        id: 711
      }, {
        name: 'Regency Enterprises',
        id: 508
      }],
      production_countries: [{ // jshint ignore:line
        iso_3166_1: 'DE', // jshint ignore:line
        name: 'Germany'
      }, {
        iso_3166_1: 'US', // jshint ignore:line
        name: 'United States of America'
      }],
      release_date: '1999-10-14', // jshint ignore:line
      revenue: 100853753,
      runtime: 139,
      spoken_languages: [{ // jshint ignore:line
        iso_639_1: 'en', // jshint ignore:line
        name: 'English'
      }],
      status: 'Released',
      tagline: 'How much can you know about yourself if you\'ve never been in a fight?',
      title: 'Fight Club',
      video: false,
      vote_average: 7.8, // jshint ignore:line
      vote_count: 3286 // jshint ignore:line
    },
    deleteUrl: baseUrl + 'movies/550',
    deleteResults: {}
  };
});<commit_msg>Update mocks<commit_after>'use strict';

var mocks, baseUrl;

beforeEach(function() {
  baseUrl = 'http://localhost:3000/';
  mocks = {
    configUrl: baseUrl + 'configs',
    configResults: {
      configs: [{
        images: {
          base_url: 'http://image.tmdb.org/t/p/', // jshint ignore:line
          secure_base_url: 'https://image.tmdb.org/t/p/', // jshint ignore:line
          backdrop_sizes: ['w300', 'w780', 'w1280', 'original'], // jshint ignore:line
          logo_sizes: ['w45', 'w92', 'w154', 'w185', 'w300', 'w500', 'original'], // jshint ignore:line
          poster_sizes: ['w92', 'w154', 'w185', 'w342', 'w500', 'w780', 'original'], // jshint ignore:line
          profile_sizes: ['w45', 'w185', 'h632', 'original'], // jshint ignore:line
          still_sizes: ['w92', 'w185', 'w300', 'original'] // jshint ignore:line
        }
      }]
    },
    allMoviesUrl: baseUrl + 'movies',
    allMoviesResults: {
      movies: [{
        title: 'Fight Club',
        themoviedbid: 550,
        id: 1,
        createdAt: '2015-02-13T05:44:34.000Z',
        updatedAt: '2015-02-13T05:44:34.000Z'
      }, {
        title: 'Guardians of the Galaxy',
        themoviedbid: 118340,
        id: 2,
        createdAt: '2015-02-13T06:19:29.000Z',
        updatedAt: '2015-02-13T06:19:29.000Z'
      }]
    },
    createMovieUrl: baseUrl + 'movies',
    createMovieResults: {
      movie: {
        title: 'The Matrix',
        themoviedbid: 603,
        id: 3,
        createdAt: '2015-02-13T05:44:34.000Z',
        updatedAt: '2015-02-13T05:44:34.000Z'
      }
    },
    searchUrl: baseUrl + 'movies/search/SDF',
    searchResults: {
      page: 1,
      results: [{
        adult: false,
        backdrop_path: '/qLxJlnfZ9b2BMzvhzvnJMBi7EGH.jpg', // jshint ignore:line
        id: 14114,
        original_title: 'You Got Served', // jshint ignore:line
        release_date: '2004-01-30', // jshint ignore:line
        poster_path: '/3ESy6TiBPSYIbEES1zNspdYtMtw.jpg', // jshint ignore:line
        popularity: 0.33499858390984,
        title: 'You Got Served',
        video: false,
        vote_average: 6.3, // jshint ignore:line
        vote_count: 9 // jshint ignore:line
      }],
      total_pages: 1, // jshint ignore:line
      total_results: 1 // jshint ignore:line
    },
    infoUrl: baseUrl + 'movies/info/550',
    infoResults: {
      adult: false,
      backdrop_path: '/8uO0gUM8aNqYLs1OsTBQiXu0fEv.jpg', // jshint ignore:line
      belongs_to_collection: null, // jshint ignore:line
      budget: 63000000,
      genres: [{
        id: 18,
        name: 'Drama'
      }],
      homepage: '',
      id: 550,
      imdb_id: 'tt0137523', // jshint ignore:line
      original_language: 'en', // jshint ignore:line
      original_title: 'Fight Club', // jshint ignore:line
      overview: 'A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground " fight clubs " forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.',
      popularity: 3.16634464772838,
      poster_path: '/2lECpi35Hnbpa4y46JX0aY3AWTy.jpg', // jshint ignore:line
      production_companies: [{ // jshint ignore:line
        name: '20th Century Fox',
        id: 25
      }, {
        name: 'Fox 2000 Pictures',
        id: 711
      }, {
        name: 'Regency Enterprises',
        id: 508
      }],
      production_countries: [{ // jshint ignore:line
        iso_3166_1: 'DE', // jshint ignore:line
        name: 'Germany'
      }, {
        iso_3166_1: 'US', // jshint ignore:line
        name: 'United States of America'
      }],
      release_date: '1999-10-14', // jshint ignore:line
      revenue: 100853753,
      runtime: 139,
      spoken_languages: [{ // jshint ignore:line
        iso_639_1: 'en', // jshint ignore:line
        name: 'English'
      }],
      status: 'Released',
      tagline: 'How much can you know about yourself if you\'ve never been in a fight?',
      title: 'Fight Club',
      video: false,
      vote_average: 7.8, // jshint ignore:line
      vote_count: 3286 // jshint ignore:line
    },
    deleteUrl: baseUrl + 'movies/2',
    deleteResults: {}
  };
});<|endoftext|>


<commit_before>module.exports = {
  fileFilterFn: path => !path.includes('test/importing/') && !path.includes('documentation'),
  decaffeinateArgs: ['--keep-commonjs', '--prefer-const', '--enable-babel-constructor-workaround'],
};
<commit_msg>Add transform for top-level `this` to CoffeeScript (#33)<commit_after>module.exports = {
  fileFilterFn: path => !path.includes('test/importing/') && !path.includes('documentation'),
  jscodeshiftScripts: [
    'top-level-this-to-exports.js',
  ],
  decaffeinateArgs: ['--keep-commonjs', '--prefer-const', '--enable-babel-constructor-workaround'],
};
<|endoftext|>


<commit_before>'use strict';

var Marionette = require('backbone.marionette'),
    emojione = require('./../../../../node_modules/emojione/lib/js/emojione').emojione;

// Turns on :) emojis
emojione.ascii = true;

module.exports = Marionette.ItemView.extend({
  /**
   * @type {String}
   */
  className: 'message',

  /**
   * @type {String}
   */
  template: require('./../templates/message.hbs'),

  /**
   * Replaces URL with  link to URL
   * @param  {String} string
   * @return {String}
   */
  toLink: function (string) {
    var urlRegex = /((http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?)/;
    return string.replace(urlRegex, '$1');
  },

  /**
   * Adds the type as a class and pulls message
   * upwards if from same previous user
   */
  onRender: function () {
    this.$el.addClass(this.model.getType());
    this.$el.toggleClass('pull-up', this.model.samePreviousUser());
    this.$('p').html(emojione.toImage(this.toLink(this.model.get('message'))));
  }
});
<commit_msg>Fixed emojione build problem<commit_after>'use strict';

var Marionette = require('backbone.marionette'),
    emojione = require('./../../../../node_modules/emojione/lib/js/emojione');

// Turns on :) emojis
emojione.ascii = true;

module.exports = Marionette.ItemView.extend({
  /**
   * @type {String}
   */
  className: 'message',

  /**
   * @type {String}
   */
  template: require('./../templates/message.hbs'),

  /**
   * Replaces URL with  link to URL
   * @param  {String} string
   * @return {String}
   */
  toLink: function (string) {
    var urlRegex = /((http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?)/;
    return string.replace(urlRegex, '$1');
  },

  /**
   * Adds the type as a class and pulls message
   * upwards if from same previous user
   */
  onRender: function () {
    this.$el.addClass(this.model.getType());
    this.$el.toggleClass('pull-up', this.model.samePreviousUser());
    this.$('p').html(emojione.toImage(this.toLink(this.model.get('message'))));
  }
});
<|endoftext|>


<commit_before>$(document).ready(function () {
    // https://datatables.net/plug-ins/sorting/date-euro
    $.extend(jQuery.fn.dataTableExt.oSort, {
        "date-euro-pre": function (a) {
            var x;

            if ($.trim(a) !== '') {
                var frDatea = $.trim(a).split(' ');
                var frTimea = (undefined != frDatea[1]) ? frDatea[1].split(':') : [00, 00, 00];
                var frDatea2 = frDatea[0].split('.');
                x = (frDatea2[2] + frDatea2[1] + frDatea2[0] + frTimea[0] + frTimea[1] + ((undefined != frTimea[2]) ? frTimea[2] : 0)) * 1;
            } else {
                x = Infinity;
            }
            return x;
        },
        "date-euro-asc": function (a, b) {
            return a - b;
        },
        "date-euro-desc": function (a, b) {
            return b - a;
        }
    });

    // Current rentals with euro date sorting
    $('#rentals').DataTable({columnDefs: [{type: 'date-euro', targets: [3]}]});
    // Rental history with euro date sorting
    $('#rentals_history').DataTable({columnDefs: [{type: 'date-euro', targets: [3, 4]}]});
    $('#usrs').DataTable(); // Users table
    $('#devs').DataTable(); // Device table

// Manage symbol "-". Each barcode of the tablet is length of 5
    $('#devices').bind('input propertychange', function (event) {
        // Remove "-" from input
        var text = event.target.value.replace(new RegExp("-", "g"), "");
        // Set input to ""
        $(event.target).val("");

        // Re-add "-"
        var finalText = "";
        var i = 0;
        for (var token in text) {
            if (i !== 0 && i % 5 === 0) {
                finalText += "-";
            }
            finalText += text[token];
            i++;
        }
        // Set text to input
        $(event.target).val(finalText.toUpperCase());
        // Update tablet counter
        $('#charNum').text(event.target.value.split("-").length);
    });

    // Async check that user exists.
    $("#personInformation").bind("input propertychange", function () {
        $.ajax({
            url: window.location.href + "exists",
            type: "POST",
            //data: {pin: $("#personInformation").val(), _csrf: $('meta[name="_csrf"]').attr('content')},
            data: {pin: $("#personInformation").val()},
            success: function (data) {
                if (typeof(data) === "string") {
                    $("#usr").text(data !== "" ? "Tere, " + data + "! ✔" : "Sisesta printeri kood ✘")
                        .removeClass("valid invalid").addClass(data !== "" ? "valid" : "invalid");
                }
            }
        });
    });

    // Add autofocus on modal elements
    $('.modal').on('shown.bs.modal', function () {
        $(this).find('[autofocus]').focus();
    });

    // Load the Visualization API and the corechart package.
    google.charts.load('current', {'packages': ['corechart']});

    var tabletHistory = [];

    function callDeviceUsagePieChart() {
        $.ajax({
            url: window.location.origin + "/history_chart_device",
            type: 'GET',
            cache: false,
            success: function (data) {
                data.forEach(function (entry) {
                    tabletHistory.push([entry[0], parseInt(entry[1])]);
                });
                google.charts.setOnLoadCallback(pieChartDeviceUsage);
            }
        });
    }

    function pieChartDeviceUsage() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Seade');
        data.addColumn('number', 'Kasutusi');
        data.addRows(tabletHistory);
        var options = {
            title: "Seadme kasutuste arv",
            width: 500,
            height: 500,
            vAxis: {viewWindowMode: "explicit", viewWindow: {min: 0}}
        };
        new google.visualization.PieChart(document.getElementById("piechart_device")).draw(data, options);
    }

    if ($("#piechart_device").length) {
        // Set a callback to run when the Google Visualization API is loaded.
        google.charts.setOnLoadCallback(callDeviceUsagePieChart);
    }

    var userHistory = [];

    function callUserUsagePieChart() {
        $.ajax({
            url: window.location.origin + "/history_chart_user",
            type: 'GET',
            cache: false,
            success: function (data) {
                data.forEach(function (entry) {
                    userHistory.push([entry[0], parseInt(entry[1])]);
                });
                google.charts.setOnLoadCallback(pieChartUserUsage);
            }
        });
    }

    function pieChartUserUsage() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'PIN');
        data.addColumn('number', 'Kasutusi');
        data.addRows(userHistory);
        var options = {
            title: "Kasutaja aktiivsus",
            width: 500,
            height: 500,
            vAxis: {viewWindowMode: "explicit", viewWindow: {min: 0}}
        };
        new google.visualization.PieChart(document.getElementById("piechart_user")).draw(data, options);
    }

    if ($("#piechart_user").length) {
        // Set a callback to run when the Google Visualization API is loaded.
        google.charts.setOnLoadCallback(callUserUsagePieChart);
    }
});<commit_msg>Bug fix<commit_after>$(document).ready(function () {
    // https://datatables.net/plug-ins/sorting/date-euro
    $.extend(jQuery.fn.dataTableExt.oSort, {
        "date-euro-pre": function (a) {
            var x;

            if ($.trim(a) !== '') {
                var frDatea = $.trim(a).split(' ');
                var frTimea = (undefined != frDatea[1]) ? frDatea[1].split(':') : [00, 00, 00];
                var frDatea2 = frDatea[0].split('.');
                x = (frDatea2[2] + frDatea2[1] + frDatea2[0] + frTimea[0] + frTimea[1] + ((undefined != frTimea[2]) ? frTimea[2] : 0)) * 1;
            } else {
                x = Infinity;
            }
            return x;
        },
        "date-euro-asc": function (a, b) {
            return a - b;
        },
        "date-euro-desc": function (a, b) {
            return b - a;
        }
    });

    // Current rentals with euro date sorting
    $('#rentals').DataTable({columnDefs: [{type: 'date-euro', targets: [3]}]});
    // Rental history with euro date sorting
    $('#rentals_history').DataTable({columnDefs: [{type: 'date-euro', targets: [3, 4]}]});
    $('#usrs').DataTable(); // Users table
    $('#devs').DataTable(); // Device table

// Manage symbol "-". Each barcode of the tablet is length of 5
    $('#devices').bind('input propertychange', function (event) {
        // Remove "-" from input
        var text = event.target.value.replace(new RegExp("-", "g"), "");
        // Set input to ""
        $(event.target).val("");

        // Re-add "-"
        var finalText = "";
        var i = 0;
        for (var token in text) {
            if (i !== 0 && i % 5 === 0) {
                finalText += "-";
            }
            finalText += text[token];
            i++;
        }
        // Set text to input
        $(event.target).val(finalText.toUpperCase());
        // Update tablet counter
        $('#charNum').text(event.target.value.split("-").length);
    });

    // Async check that user exists.
    $("#personInformation").bind("input propertychange", function () {
        $.ajax({
            url: window.location.href + "exists",
            type: "POST",
            //data: {pin: $("#personInformation").val(), _csrf: $('meta[name="_csrf"]').attr('content')},
            data: {pin: $("#personInformation").val()},
            success: function (data) {
                if (typeof(data) === "string") {
                    $("#usr").text(data !== "" ? "Tere, " + data + "! ✔" : "Sisesta printeri kood ✘")
                        .removeClass("valid invalid").addClass(data !== "" ? "valid" : "invalid");
                }
            }
        });
    });

    // Add autofocus on modal elements
    $('.modal').on('shown.bs.modal', function () {
        $(this).find('[autofocus]').focus();
    });

    // Load the Visualization API and the corechart package.
    google.charts.load('current', {'packages': ['corechart']});

    var tabletHistory = [];

    function callDeviceUsagePieChart() {
        $.ajax({
            url: window.location.href + "_chart_device",
            type: 'GET',
            cache: false,
            success: function (data) {
                data.forEach(function (entry) {
                    tabletHistory.push([entry[0], parseInt(entry[1])]);
                });
                google.charts.setOnLoadCallback(pieChartDeviceUsage);
            }
        });
    }

    function pieChartDeviceUsage() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Seade');
        data.addColumn('number', 'Kasutusi');
        data.addRows(tabletHistory);
        var options = {
            title: "Seadme kasutuste arv",
            width: 500,
            height: 500,
            vAxis: {viewWindowMode: "explicit", viewWindow: {min: 0}}
        };
        new google.visualization.PieChart(document.getElementById("piechart_device")).draw(data, options);
    }

    if ($("#piechart_device").length) {
        // Set a callback to run when the Google Visualization API is loaded.
        google.charts.setOnLoadCallback(callDeviceUsagePieChart);
    }

    var userHistory = [];

    function callUserUsagePieChart() {
        $.ajax({
            url: window.location.href + "_chart_user",
            type: 'GET',
            cache: false,
            success: function (data) {
                data.forEach(function (entry) {
                    userHistory.push([entry[0], parseInt(entry[1])]);
                });
                google.charts.setOnLoadCallback(pieChartUserUsage);
            }
        });
    }

    function pieChartUserUsage() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'PIN');
        data.addColumn('number', 'Kasutusi');
        data.addRows(userHistory);
        var options = {
            title: "Kasutaja aktiivsus",
            width: 500,
            height: 500,
            vAxis: {viewWindowMode: "explicit", viewWindow: {min: 0}}
        };
        new google.visualization.PieChart(document.getElementById("piechart_user")).draw(data, options);
    }

    if ($("#piechart_user").length) {
        // Set a callback to run when the Google Visualization API is loaded.
        google.charts.setOnLoadCallback(callUserUsagePieChart);
    }
});<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { GridListTileBar } from 'material-ui/GridList'

import styles from './Project.scss'

class Project extends Component {
  constructor (props) {
    super(props)

    this.handleClick = this.handleClick.bind(this)
    this.renderProjectApplicationResult = this.renderProjectApplicationResult.bind(this)
    this.getAppliedStatus = this.getAppliedStatus.bind(this)
  }

  handleClick () {
    const { authenticated, project, user } = this.props
    const applied = this.getAppliedStatus()

    if (!applied && authenticated && user.usertype === 'volunteer') {
      return this.props.applyForProject(project, user)
    }
  }

  renderProjectApplicationResult (project) {
    const applied = this.getAppliedStatus()
    const isContact = this.isUserTypeContact()
    if (applied && !isContact) {
      return (
        ✔
      )
    } else if (!isContact) {
      return (
        ✗
      )
    }
  }

  getAppliedStatus () {
    return (
      this.props.user.projectsAppliedFor &&
      this.props.user.projectsAppliedFor.includes(this.props.project.id)
    )
  }

  isUserTypeContact () {
    return this.props.user.usertype === 'contact'
  }

  render () {
    const { currentPage, project } = this.props

    const applied = this.getAppliedStatus()
    const isContact = this.isUserTypeContact()
    const isProfile = currentPage.includes('profile')

    let projectClasses = styles.project
    if (this.props.authenticated && !applied && !isContact) {
      projectClasses = styles.projectAuthenticated
    } else if (this.props.authenticated && !applied) {
      projectClasses = styles.projectAuthenticatedContact
    }

    return (

        <GridListTileBar title={project.name}
          subtitle={isContact && isProfile ? null : project.organization.name || 'Organization Name'}
          actionIcon={this.renderProjectApplicationResult(project)}>
        </GridListTileBar>

    )
  }
}

function mapStateToProps (state) {
  return {
    currentPage: state.routing.location.pathname,
    user: state.user
  }
}

Project.propTypes = {
  applyForProject: PropTypes.func.isRequired,
  authenticated: PropTypes.bool.isRequired,
  currentPage: PropTypes.string.isRequired,
  project: PropTypes.object.isRequired,
  user: PropTypes.object
}

export default connect(mapStateToProps, null)(Project)
<commit_msg>fix #153534540 (#189)<commit_after>import React, { Component } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { GridListTileBar } from 'material-ui/GridList'

import styles from './Project.scss'

class Project extends Component {
  constructor (props) {
    super(props)

    this.handleClick = this.handleClick.bind(this)
    this.renderProjectApplicationResult = this.renderProjectApplicationResult.bind(this)
    this.getAppliedStatus = this.getAppliedStatus.bind(this)
  }

  handleClick () {
    const { authenticated, project, user } = this.props
    const applied = this.getAppliedStatus()

    if (!applied && authenticated && user.usertype === 'volunteer') {
      return this.props.applyForProject(project, user)
    }
  }

  renderProjectApplicationResult (project) {
    const applied = this.getAppliedStatus()
    const isContact = this.isUserTypeContact()
    if (this.props.authenticated && !isContact) {
      return applied ? ✔
        : ✗
    }
    return
  }

  getAppliedStatus () {
    return (
      this.props.user.projectsAppliedFor &&
      this.props.user.projectsAppliedFor.includes(this.props.project.id)
    )
  }

  isUserTypeContact () {
    return this.props.user.usertype === 'contact'
  }

  render () {
    const { currentPage, project } = this.props

    const applied = this.getAppliedStatus()
    const isContact = this.isUserTypeContact()
    const isProfile = currentPage.includes('profile')

    let projectClasses = styles.project
    if (this.props.authenticated && !applied && !isContact) {
      projectClasses = styles.projectAuthenticated
    } else if (this.props.authenticated && !applied) {
      projectClasses = styles.projectAuthenticatedContact
    }

    return (

        <GridListTileBar title={project.name}
          subtitle={isContact && isProfile ? null : project.organization.name || 'Organization Name'}
          actionIcon={this.renderProjectApplicationResult(project)}>
        </GridListTileBar>

    )
  }
}

function mapStateToProps (state) {
  return {
    currentPage: state.routing.location.pathname,
    user: state.user
  }
}

Project.propTypes = {
  applyForProject: PropTypes.func.isRequired,
  authenticated: PropTypes.bool.isRequired,
  currentPage: PropTypes.string.isRequired,
  project: PropTypes.object.isRequired,
  user: PropTypes.object
}

export default connect(mapStateToProps, null)(Project)
<|endoftext|>


<commit_before>'use strict';

var ords = angular.module('ords',['ngRoute', 'ngResource', 'angular-growl', 'ngMessages', 'angularUtils.directives.dirPagination', 'gettext'])

	//
	// Setup the gettext() function
	//
	.run(function (gettextCatalog) {
	    gettextCatalog.setCurrentLanguage('en');
		//gettextCatalog.debug = true;
		//gettextCatalog.showTranslatedMarkers = true;
	})

	//
	// Project REST Resources
	//
	.factory('Project', function( $resource ) {
		return $resource(
			'/project-api/project/:id/',
			null,
			{'update': { method:'PUT' }}
		)
	})

	.factory('Statistics', function( $resource ) {
		return $resource('/api/1.0/statistics')
	})

	.factory('Audit', function( $resource ) {
		return $resource('/api/1.0/audit/project/:id')
	})

	.factory('User', function( $resource ) {
		return $resource(
			'/api/1.0/user/',
			null,
			{'lookup': { method: 'GET'}}
		);
	})

	.factory('Member', function( $resource, User ) {

		var Member =  $resource('/project-api/project/:id/role/:roleid', null, {'update': { method:'PUT' }});

		Member.prototype.name = "";

		//
		// The "name" property of a Member is held by the User resource
		// so we have to load that asynchronously from the REST API
		//
		Member.prototype.getName = function () {

			if (this.name !== "") return this.name;
			var that = this;
			User.lookup( {name: this.principalName}, function(user){
				that.name = user.name;
			}
			);
			this.name = "loading ...";
		};

		return Member;
	})

	//
	// A "really?" handler to confirm actions
	// Usage: Add attributes: ng-really-message="Are you sure"? ng-really-click="takeAction()" function
	// See: https://gist.github.com/asafge/7430497
	//
	.directive('ngReallyClick', [function() {
	    return {
	        restrict: 'A',
	        link: function(scope, element, attrs) {
	            element.bind('click', function() {
	                var message = attrs.ngReallyMessage;
	                if (message && confirm(message)) {
	                    scope.$apply(attrs.ngReallyClick);
	                }
	            });
	        }
	    }
	}])

	//
	// Service that checks if user is currently authenticated
	//
	.factory('AuthService', function ($rootScope, $location, User, Project){
		var svc = {};
		svc.check = function(){
			if ($rootScope.loggedIn !== "yes"){
				$rootScope.user = User.get(
					 function successCallback() {
						$rootScope.loggedIn="yes"
						 if ($location.path() === "/"){

			 	 			//
			 	 			// Load initial projects
			 	 			//
			 	 			Project.query({}, function(data){
			 	 				$rootScope.projects = data;
			 	 			});
			 				$location.path("/projects");
						 }
					 },
					 function errorCallback(response) {

						 //
						 // If we have a 401, we aren't logged in...
						 //
						 if (response.status === 401){
							 $rootScope.loggedIn="no"
							 $location.path("/");
						 }

						 //
						 // If we have a 404, we're logged in, but haven't registered yet
						 //
						 if (response.status === 404){
							 $rootScope.loggedIn="no"
							 $location.path("/register");
						 }
					 }
				);
			}
		};
		return svc;
	})

	//
	// Configure alerts
	//
	.config(['growlProvider', function(growlProvider) {
	  growlProvider.globalTimeToLive(10000);
	  growlProvider.globalDisableCountDown(true);
	}])

	//
	// configure  routes
	//
	.config(function($routeProvider) {
	        $routeProvider

	            // Home page
	            .when('/projects', {
	                templateUrl : 'project/views/home.html',
	                controller  : 'projectsController'
	            })

	            // Search results
	            .when('/search', {
	                templateUrl : 'views/searchresults.html',
	                controller  : 'searchController'
	            })

	            // Home page for login
	            .when('/', {
	                templateUrl : 'views/home.html',
	                controller  : 'mainController'
	            })

	            // Project Details
	            .when('/project/:id', {
	                templateUrl : 'project/views/project.html',
	                controller  : 'projectController'
	            })

				// New Project Form
				.when('/newproject', {
	                templateUrl : 'project/views/newproject.html',
	                controller  : 'newProjectController'
				})

	            // Edit Project Details
	            .when('/project/:id/edit', {
	                templateUrl : 'project/views/editproject.html',
	                controller  : 'editProjectController'
	            })

	            // Project Audit
	            .when('/project/:id/audit', {
	                templateUrl : 'project/views/audit.html',
	                controller  : 'auditController'
	            })

				// Edit Member Form
				.when('/project/:projectId/member/:memberId', {
	                templateUrl : 'project/views/editmember.html',
	                controller  : 'editMemberController'
				})

				// New Member Form
				.when('/project/:id/newmember', {
	                templateUrl : 'project/views/newmember.html',
	                controller  : 'newMemberController'
				})

				// New User Registration Form
				.when('/register', {
	                templateUrl : 'views/register.html',
	                controller  : 'registerController'
				})

				// Email verification
				.when('/verify/:code', {
	                templateUrl : 'views/verify.html',
	                controller  : 'verifyController'
				})

				.otherwise({
					redirectTo: '/'
				})

				;
	    })

;

<commit_msg>Ensure we redirect calls to "/"<commit_after>'use strict';

var ords = angular.module('ords',['ngRoute', 'ngResource', 'angular-growl', 'ngMessages', 'angularUtils.directives.dirPagination', 'gettext'])

	//
	// Setup the gettext() function
	//
	.run(function (gettextCatalog) {
	    gettextCatalog.setCurrentLanguage('en');
		//gettextCatalog.debug = true;
		//gettextCatalog.showTranslatedMarkers = true;
	})

	//
	// Project REST Resources
	//
	.factory('Project', function( $resource ) {
		return $resource(
			'/project-api/project/:id/',
			null,
			{'update': { method:'PUT' }}
		)
	})

	.factory('Statistics', function( $resource ) {
		return $resource('/api/1.0/statistics')
	})

	.factory('Audit', function( $resource ) {
		return $resource('/api/1.0/audit/project/:id')
	})

	.factory('User', function( $resource ) {
		return $resource(
			'/api/1.0/user/',
			null,
			{'lookup': { method: 'GET'}}
		);
	})

	.factory('Member', function( $resource, User ) {

		var Member =  $resource('/project-api/project/:id/role/:roleid', null, {'update': { method:'PUT' }});

		Member.prototype.name = "";

		//
		// The "name" property of a Member is held by the User resource
		// so we have to load that asynchronously from the REST API
		//
		Member.prototype.getName = function () {

			if (this.name !== "") return this.name;
			var that = this;
			User.lookup( {name: this.principalName}, function(user){
				that.name = user.name;
			}
			);
			this.name = "loading ...";
		};

		return Member;
	})

	//
	// A "really?" handler to confirm actions
	// Usage: Add attributes: ng-really-message="Are you sure"? ng-really-click="takeAction()" function
	// See: https://gist.github.com/asafge/7430497
	//
	.directive('ngReallyClick', [function() {
	    return {
	        restrict: 'A',
	        link: function(scope, element, attrs) {
	            element.bind('click', function() {
	                var message = attrs.ngReallyMessage;
	                if (message && confirm(message)) {
	                    scope.$apply(attrs.ngReallyClick);
	                }
	            });
	        }
	    }
	}])

	//
	// Service that checks if user is currently authenticated
	//
	.factory('AuthService', function ($rootScope, $location, User, Project){
		var svc = {};
		svc.check = function(){
			if ($rootScope.loggedIn !== "yes"){
				$rootScope.user = User.get(
					 function successCallback() {
						$rootScope.loggedIn="yes"
						 if ($location.path() === "/"){

			 	 			//
			 	 			// Load initial projects
			 	 			//
			 	 			Project.query({}, function(data){
			 	 				$rootScope.projects = data;
			 	 			});
			 				$location.path("/projects");
						 }
					 },
					 function errorCallback(response) {

						 //
						 // If we have a 401, we aren't logged in...
						 //
						 if (response.status === 401){
							 $rootScope.loggedIn="no"
							 $location.path("/");
						 }

						 //
						 // If we have a 404, we're logged in, but haven't registered yet
						 //
						 if (response.status === 404){
							 $rootScope.loggedIn="no"
							 $location.path("/register");
						 }
					 }
				);
			} else {
				//
				// If we are already logged in, bypass the front page and
				// view the projects page
				//
				if ($location.path() === "/"){
					$location.path("/projects");
				}
			}
		};
		return svc;
	})

	//
	// Configure alerts
	//
	.config(['growlProvider', function(growlProvider) {
	  growlProvider.globalTimeToLive(10000);
	  growlProvider.globalDisableCountDown(true);
	}])

	//
	// configure  routes
	//
	.config(function($routeProvider) {
	        $routeProvider

	            // Home page
	            .when('/projects', {
	                templateUrl : 'project/views/home.html',
	                controller  : 'projectsController'
	            })

	            // Search results
	            .when('/search', {
	                templateUrl : 'views/searchresults.html',
	                controller  : 'searchController'
	            })

	            // Home page for login
	            .when('/', {
	                templateUrl : 'views/home.html',
	                controller  : 'mainController'
	            })

	            // Project Details
	            .when('/project/:id', {
	                templateUrl : 'project/views/project.html',
	                controller  : 'projectController'
	            })

				// New Project Form
				.when('/newproject', {
	                templateUrl : 'project/views/newproject.html',
	                controller  : 'newProjectController'
				})

	            // Edit Project Details
	            .when('/project/:id/edit', {
	                templateUrl : 'project/views/editproject.html',
	                controller  : 'editProjectController'
	            })

	            // Project Audit
	            .when('/project/:id/audit', {
	                templateUrl : 'project/views/audit.html',
	                controller  : 'auditController'
	            })

				// Edit Member Form
				.when('/project/:projectId/member/:memberId', {
	                templateUrl : 'project/views/editmember.html',
	                controller  : 'editMemberController'
				})

				// New Member Form
				.when('/project/:id/newmember', {
	                templateUrl : 'project/views/newmember.html',
	                controller  : 'newMemberController'
				})

				// New User Registration Form
				.when('/register', {
	                templateUrl : 'views/register.html',
	                controller  : 'registerController'
				})

				// Email verification
				.when('/verify/:code', {
	                templateUrl : 'views/verify.html',
	                controller  : 'verifyController'
				})

				.otherwise({
					redirectTo: '/'
				})

				;
	    })

;

<|endoftext|>