<commit_before>'use strict'
const props = require('../render/static').property
const getParent = require('../render/dom/parent')

exports.components = {
  group: {
    type: 'property',
    isGroup: true,
    define: {
      storeStatic (pnode) {
        const val = this.compute()
        const store = []
        props(this, pnode, store)
        return join(store, val)
      },
      storeState (state, type, stamp, subs, tree, id, pid) {
        const val = state && this.$ ? this.compute(state.val) : this.compute()
        const store = tree._[id] || (tree._[id] = [])
        const pnode = getParent(type, stamp, subs, tree, pid)
        const parsed = '_' + this.key + 'StaticParsed'
        if (!pnode[parsed]) {
          props(this, pnode, store)
          pnode[parsed] = true
        }
        return join(store, val)
      }
    },
    Child: {
      define: {
        getStore (tree, id) {
          if (this.$ !== true) {
            tree = tree._p
            while (!tree.$) { tree = tree._p }
          }
          const _ = tree._ || (tree._ = {})
          return _[id] || (_[id] = [])
        }
      }
    },
    defaultSubscription: 'done'
  }
}

function join (store, val) {
  const l = store.length
  var i = 1
  if (val && typeof val === 'string') {
    store[0] = val
  } else {
    while (i < l) {
      val = store[i++]
      if (val !== void 0) { break }
    }
  }
  while (i < l) {
    const append = store[i++]
    if (append !== void 0) { val = val + ' ' + append }
  }
  return val
}
<commit_msg>reverted last change<commit_after>'use strict'
const props = require('../render/static').property
const getParent = require('../render/dom/parent')

exports.components = {
  group: {
    type: 'property',
    isGroup: true,
    define: {
      storeStatic (pnode) {
        const val = this.compute()
        const store = []
        props(this, pnode, store)
        return join(store, val)
      },
      storeState (state, type, stamp, subs, tree, id, pid) {
        const val = state && this.$ ? this.compute(state.val) : this.compute()
        const store = tree._[id] || (tree._[id] = [])
        const pnode = getParent(type, stamp, subs, tree, pid)
        const parsed = '_' + this.key + 'StaticParsed'
        if (!pnode[parsed]) {
          props(this, pnode, store)
          pnode[parsed] = true
        }
        return join(store, val)
      }
    },
    Child: {
      define: {
        getStore (tree, id) {
          if (this.$ !== true) {
            tree = tree._p
            while (!tree.$) { tree = tree._p }
          }
          const _ = tree._ || (tree._ = {})
          return _[id] || (_[id] = [])
        }
      }
    },
    defaultSubscription: 'done'
  }
}

function join (store, val) {
  const l = store.length
  var i = 1
  if (val && typeof val === 'string') {
    store[0] = val
  } else {
    while (i < l) {
      val = store[i++]
      if (val) { break }
    }
  }
  while (i < l) {
    const append = store[i++]
    if (append) { val = val + ' ' + append }
  }
  return val
}
<|endoftext|>


<commit_before>let { type, rangeCheck, repeat } = require("../utility");

module.exports = class Matrix {

  constructor(columns, rows, data) {
    this.columns = columns;
    this.rows    = rows;
    this.data    = data;
  }

  static create(m) {
    let columns = null;
    let rows = 0;
    let data = [ ];
    for (let row of m) {
      let rowLength = 0;
      for (let element of row) {
        if (typeof element != "number")
          throw new Error(`Expected number, got '${ type(element) }'`)
        data.push(element);
        rowLength++;
      }
      if (columns == null) columns = rowLength;
      else if (rowLength != columns)
        throw new Error(`Row lengths don't match (${ rowLength } != ${ columns })`);
      rows++;
    }
    if ((rows == 0) || (columns == 0))
      throw new Error("Matrix must have at least one element");
    return new Matrix(columns, rows, data);
  }

  static zero(columns, rows = columns) {
    if ((columns <= 0) || (rows <= 0))
      throw new Error(`Invalid matrix dimensions (${ columns },${ rows })`);
    let data = new Array(columns * rows);
    return new Matrix(columns, rows, data);
  }

  static identity(size) {
    let matrix = Matrix.zero(size);
    for (let i = 0; i < size; i++)
      matrix.set(i, i, 1);
    return matrix;
  }

  static translation(...v) {
    let matrix = Matrix.identity(v.length - 1);
    for (let i = 0; i < v.length; i++)
      matrix.set(i, matrix.rows - 1, v[i]);
    return matrix;
  }

  static scale(...v) {
    let matrix = Matrix.identity(v.length - 1);
    for (let i = 0; i < v.length; i++)
      matrix.set(i, i, v[i]);
    return matrix;
  }

  static lookAt(eye, center, up) {
    let z = eye.subtract(center).toUnitVector();
    let x = up.cross(z).toUnitVector();
    let y = z.cross(x).toUnitVector();

    let m = Matrix.identity(4);
    m.setRow(0, ...repeat(x, 3));
    m.setRow(1, ...repeat(y, 3));
    m.setRow(2, ...repeat(z, 3));

    let t = Matrix.identity(4);
    t.setColumn(3, eye.negate());

    return m.multiply(t);
  }

  get size() { return [ this.columns, this.rows ]; }

  get elements() { return this.elements[Symbol.iterator]; }

  _index(i, j) { return (i + j * this.columns); }

  _indexWithCheck(i, j) {
    if (!rangeCheck(i, 0, this.rows - 1) ||
        !rangeCheck(j, 0, this.columns - 1))
      throw new Error(`[${ i },${ j }] is not a valid index in Matrix of size (${ this.size.join(",") })`);
    return this._index(i, j);
  }

  get(i, j) { return this.data[this._indexWithCheck(i, j)]; }

  set(i, j, v) { this.data[this._indexWithCheck(i, j)] = v; }

  * row(row) {
    if (!rangeCheck(row, 0, this.rows - 1))
      throw new Error(`Row ${ row } is not valid in Matrix of size (${ this.size.join(",") })`);
    for (let i = 0; i < this.columns; i++)
      yield this.data[this._index(i, row)];
  }

  * column(column) {
    if (!rangeCheck(column, 0, this.columns - 1))
      throw new Error(`Column ${ column } is not valid in Matrix of size (${ this.size.join(",") })`);
    for (let i = 0; i < this.rows; i++)
      yield this.data[this._index(column, i)];
  }

  setRow(row, ...v) {
    if (!rangeCheck(row, 0, this.rows - 1))
      throw new Error(`Row ${ row } is not valid in Matrix of size (${ this.size.join(",") })`);
    if (v.length > this.columns)
      throw new Error(`Can't put ${ v.length } values into a matrix with ${ this.columns } columns`);
    for (let i = 0; i < this.columns; i++)
      this.data[this._index(i, row)] = v[i];
  }

  setColumn(column, ...v) {
    if (!rangeCheck(column, 0, this.columns - 1))
      throw new Error(`Columns ${ column } is not valid in Matrix of size (${ this.size.join(",") })`);
    if (v.length > this.rows)
      throw new Error(`Can't put ${ v.length } values into a matrix with ${ this.rows } rows`);
    for (let i = 0; i < this.rows; i++)
      this.data[this._index(column, i)] = v[i];
  }

  clone() { return new Matrix(this.columns, this.rows, this.data.slice(0)); }

};
<commit_msg>Add Matrix.frustum, .perspective and .ortho<commit_after>let { type, rangeCheck, repeat } = require("../utility");

module.exports = class Matrix {

  constructor(columns, rows, data) {
    this.columns = columns;
    this.rows    = rows;
    this.data    = data;
  }

  static create(m) {
    let columns = null;
    let rows = 0;
    let data = [ ];
    for (let row of m) {
      let rowLength = 0;
      for (let element of row) {
        if (typeof element != "number")
          throw new Error(`Expected number, got '${ type(element) }'`)
        data.push(element);
        rowLength++;
      }
      if (columns == null) columns = rowLength;
      else if (rowLength != columns)
        throw new Error(`Row lengths don't match (${ rowLength } != ${ columns })`);
      rows++;
    }
    if ((rows == 0) || (columns == 0))
      throw new Error("Matrix must have at least one element");
    return new Matrix(columns, rows, data);
  }

  static zero(columns, rows = columns) {
    if ((columns <= 0) || (rows <= 0))
      throw new Error(`Invalid matrix dimensions (${ columns },${ rows })`);
    let data = new Array(columns * rows);
    return new Matrix(columns, rows, data);
  }

  static identity(size) {
    let matrix = Matrix.zero(size);
    for (let i = 0; i < size; i++)
      matrix.set(i, i, 1);
    return matrix;
  }

  static translation(...v) {
    let matrix = Matrix.identity(v.length - 1);
    for (let i = 0; i < v.length; i++)
      matrix.set(i, matrix.rows - 1, v[i]);
    return matrix;
  }

  static scale(...v) {
    let matrix = Matrix.identity(v.length - 1);
    for (let i = 0; i < v.length; i++)
      matrix.set(i, i, v[i]);
    return matrix;
  }

  static lookAt(eye, center, up) {
    let z = eye.subtract(center).toUnitVector();
    let x = up.cross(z).toUnitVector();
    let y = z.cross(x).toUnitVector();

    let m = Matrix.identity(4);
    m.setRow(0, ...repeat(x, 3));
    m.setRow(1, ...repeat(y, 3));
    m.setRow(2, ...repeat(z, 3));

    let t = Matrix.identity(4);
    t.setColumn(3, ...eye.negate());

    return m.multiply(t);
  }

  static frustum(left, right, bottom, top, znear, zfar) {
    let X = 2 * znear / (right - left);
    let Y = 2 * znear / (top - bottom);
    let A = (right + left) / (right - left);
    let B = (top + bottom) / (top - bottom);
    let C = -(zfar + znear) / (zfar - znear);
    let D = -2 * zfar * znear / (zfar - znear);

    return Matrix.create(
      [[ X, 0,  A, 0 ]
       [ 0, Y,  B, 0 ]
       [ 0, 0,  C, D ]
       [ 0, 0, -1, 0 ]]);
  }

  static perspective(fovy, aspect, znear, zfar) {
    let ymax = znear * Math.tan(fovy * Math.PI / 360.0);
    let ymin = -ymax;
    let xmin = ymin * aspect;
    let xmax = ymax * aspect;

    return Matrix.frustum(xmin, xmax, ymin, ymax, znear, zfar);
  };

  static ortho(left, right, bottom, top, znear, zfar) {
    let tx = -(right + left) / (right - left);
    let ty = -(top + bottom) / (top - bottom);
    let tz = -(zfar + znear) / (zfar - znear);

    return Matrix.create(
      [[ 2 / (right - left), 0, 0, 0 ]
      [ 0, 2 / (top - bottom), 0, 0 ]
      [ 0, 0, -2 / (zfar - znear), 0 ]
      [ tx, ty, tz, 1 ]]);
  };

  get size() { return [ this.columns, this.rows ]; }

  get elements() { return this.elements[Symbol.iterator]; }

  _index(i, j) { return (i + j * this.columns); }

  _indexWithCheck(i, j) {
    if (!rangeCheck(i, 0, this.rows - 1) ||
        !rangeCheck(j, 0, this.columns - 1))
      throw new Error(`[${ i },${ j }] is not a valid index in Matrix of size (${ this.size.join(",") })`);
    return this._index(i, j);
  }

  get(i, j) { return this.data[this._indexWithCheck(i, j)]; }

  set(i, j, v) { this.data[this._indexWithCheck(i, j)] = v; }

  * row(row) {
    if (!rangeCheck(row, 0, this.rows - 1))
      throw new Error(`Row ${ row } is not valid in Matrix of size (${ this.size.join(",") })`);
    for (let i = 0; i < this.columns; i++)
      yield this.data[this._index(i, row)];
  }

  * column(column) {
    if (!rangeCheck(column, 0, this.columns - 1))
      throw new Error(`Column ${ column } is not valid in Matrix of size (${ this.size.join(",") })`);
    for (let i = 0; i < this.rows; i++)
      yield this.data[this._index(column, i)];
  }

  setRow(row, ...v) {
    if (!rangeCheck(row, 0, this.rows - 1))
      throw new Error(`Row ${ row } is not valid in Matrix of size (${ this.size.join(",") })`);
    if (v.length > this.columns)
      throw new Error(`Can't put ${ v.length } values into a matrix with ${ this.columns } columns`);
    for (let i = 0; i < this.columns; i++)
      this.data[this._index(i, row)] = v[i];
  }

  setColumn(column, ...v) {
    if (!rangeCheck(column, 0, this.columns - 1))
      throw new Error(`Columns ${ column } is not valid in Matrix of size (${ this.size.join(",") })`);
    if (v.length > this.rows)
      throw new Error(`Can't put ${ v.length } values into a matrix with ${ this.rows } rows`);
    for (let i = 0; i < this.rows; i++)
      this.data[this._index(column, i)] = v[i];
  }

  clone() { return new Matrix(this.columns, this.rows, this.data.slice(0)); }

};
<|endoftext|>


<commit_before>var http = require('http');
var path = require('path');
var url = require('url');
var querystring = require('querystring');
var spdy = require('spdy');
var argo = require('argo');
var argoMultiparty = require('argo-multiparty');
var titan = require('titan');
var WebSocketServer = require('ws').Server;
var SpdyAgent = require('./spdy_agent');
var EventBroker = require('./event_broker');
var PeerSocket = require('./peer_socket');
var EventSocket = require('./event_socket');
var Siren = require('argo-formatter-siren');
var DevicesResource = require('./api_resources/devices');
var PeersManagementResource = require('./api_resources/peer_management');
var RootResource = require('./api_resources/root');
var ServersResource = require('./api_resources/servers');
var PubSubResource = require('./api_resources/pubsub_subscriptions');
var rels = require('./api_rels');

var ZettaHttpServer = module.exports = function(zettaInstance) {
  this.idCounter = 0;
  this.server = http.createServer();
  this.zetta = zettaInstance;
  this.peerRegistry = zettaInstance.peerRegistry;
  this.eventBroker = new EventBroker(zettaInstance);
  this.clients = {};
  this.agent = null;
  this.peers = [];
  this.agents = {};
  this.router = {};
  this._collectors = {};
  this.server = http.createServer();
  this.spdyServer = spdy.createServer({
    windowSize: 1024 * 1024,
    plain: true,
    ssl: false
  });

  this.cloud = argo()
    .use(titan)
   .format({ engines: [Siren], override: { 'application/json': Siren }, directory: path.join(__dirname, './api_formats') })
    .add(RootResource, zettaInstance)
    .add(PeersManagementResource, zettaInstance)
    .add(DevicesResource, zettaInstance)
    .add(ServersResource, zettaInstance)
    .add(PubSubResource, zettaInstance)
    .use(argoMultiparty)
    .allow({
      methods: ['DELETE', 'PUT', 'PATCH', 'POST'],
      origins: ['*'],
      headers: ['accept', 'content-type'],
      maxAge: '432000'
    })
    .use(function(handle) {
      handle('request', function(env, next) {
        if (env.request.headers['zetta-message-id']) {
          env.response.setHeader('zetta-message-id', env.request.headers['zetta-message-id']);
        }
        next(env);
      });
    })
    .use(function(handle) {
      handle('request', function(env, next) {
        if (env.request.method === 'OPTIONS') {
          env.argo._routed = true;
        }
        next(env);
      });
    });
};

ZettaHttpServer.prototype.init = function(cb) {
  var self = this;

  // handle http registration of device
  this.cloud = this.cloud.use(this.httpRegistration.bind(this));
  // handle proxying to peer
  //this.cloud = this.cloud.route('*', this.proxyToPeer.bind(this));
  // setup http servers request handler to argo routes
  this.cloud = this.cloud.build();

  this.server.on('request', this.cloud.run);
  this.spdyServer.on('request', this.cloud.run);

  this.wss = new WebSocketServer({ server: this.server });
  this.wss.on('connection', function(ws) {
    var match = /^\/peers\/(.+)$/.exec(ws.upgradeReq.url);
    if (match) {
      var peerId = match[1];
      var peer = new PeerSocket(ws, peerId);

      self.zetta.log.emit('log', 'http_server', 'Websocket connection for peer ' + peerId + ' established');

      var requestOpts = { method: 'GET', path: '/', agent: peer.agent };
      var peerRequest = http.request(requestOpts, function(res) {
        var buffer = [];
        var len = 0;

        res.on('readable', function() {
          var data;
          while (data = res.read()) {
            buffer.push(data);
            len += data.length;
          }
        });

        res.on('end', function() {
          self.zetta.log.emit('log', 'http_server', 'Peer http request finished ' + peerId + ' maped to ' + newPeer.id);
          var buf = Buffer.concat(buffer, len);
          var root = JSON.parse(buf.toString());

          var peerName = root.links.filter(function(link) {
            return link.rel.indexOf(rels.server) !== -1;
          })[0].title;

          var peerItem = {
            peerId: peerId,
            direction: 'acceptor',
            name: peerName,
            status: 'connected'
          };

          self.peerRegistry.add(peerItem, function(err, newPeer) {
            if (err) {
              console.error('HttpServer: Failed to save peeer information', err);
              ws.close();
              return;
            }

            self.zetta.log.emit('log', 'http_server', 'Peer connection established ' + peerId + ' maped to ' + newPeer.id);

            peer.serverId = newPeer.id; // set proxy peer id
            self.agents[newPeer.id] = peer.agent;
            self.agents[peerId] = peer.agent;
            self.router[newPeer.id] = peerId;
            self.peers.push(peer);
            self.eventBroker.peer(peer);

            ws.on('close', function() {
              self.zetta.log.emit('log', 'http_server', 'Peer connection closed for ' + peerId + ' maped to ' + newPeer.id);
              self._cleanupPeer(peer); // remove from zetta internals
              self.peerRegistry.get(newPeer.id, function(err, peer) {
                peer = JSON.parse(peer);
                if (peer) {
                  peer.status = 'disconnected';
                  self.peerRegistry.save(peer);
                }
              });
            });

            ws.on('error', function(err) {
              self.zetta.log.emit('log', 'http_server', 'Peer connection failed for ' + peerId + ' maped to ' + newPeer.id);
              self._cleanupPeer(peer); // remove from zetta internals
              self.peerRegistry.get(newPeer.id, function(err, peer) {
                peer = JSON.parse(peer);
                if (peer) {
                  peer.status = 'failed';
                  peer.error = err;
                  self.peerRegistry.save(peer);
                }
              });
            });
          });
        });
      });

      peerRequest.on('error', function(err) {
        console.error('Peer request failed', err);
        ws.close(); // close socket if request failed
      });

      setImmediate(peerRequest.end.bind(peerRequest));
    } else {
      self.setupEventSocket(ws);
    }
  });

  if (cb) {
    cb();
  }
};

ZettaHttpServer.prototype.listen = function() {
  this.server.listen.apply(this.server,arguments);
  return this;
};

ZettaHttpServer.prototype.collector = function(name, collector) {
  if(typeof name === 'function'){
    collector = name;
    name = '_logs';
  }

  if(!this._collectors[name]) {
    this._collectors[name] = [];
  }

  this._collectors[name].push(collector);
  return this;
};

ZettaHttpServer.prototype.setupEventSocket = function(ws) {
  var match = /^\/servers\/(.+)\/events/.exec(ws.upgradeReq.url);
  if(!match) {
    ws.close(1001); // go away status code
    return;
  }
  var query = querystring.parse(url.parse(ws.upgradeReq.url).query);
  query.serverId = match[1]; // set serverId on query
  var client = new EventSocket(ws, query);
  this.eventBroker.client(client);
};

ZettaHttpServer.prototype._cleanupPeer = function(peerSocket) {
  var peerId = this.router[peerSocket.serverId];
  delete this.agents[peerSocket.serverId];
  delete this.agents[peerId];
  delete this.router[peerSocket.serverId];
  var idx = this.peers.indexOf(peerSocket);
  if (idx !== -1) {
    this.peers.splice(idx, 1);
  }

  //  this.eventBroker.peer(peer);
};

ZettaHttpServer.prototype.httpRegistration = function(handle) {
  handle('request', function(env, next) {
    if (!(env.request.method === 'POST' && env.request.url === '/registration')) {
      return next(env);
    }

    env.request.getBody(function(err, body) {
      body = JSON.parse(body.toString());
      var agent = self.agents[body.target];

      if (!agent) {
        env.response.statusCode = 404;
        return next(env);
      }

      env.request.body = new Buffer(JSON.stringify(body.device));
      env.zettaAgent = agent;
      next(env);
    });
  });
};

//ZettaHttpServer.prototype.proxyToPeer = function(handle) {
ZettaHttpServer.prototype.proxyToPeer = function(env, next) {
  //handle('request', function(env, next) {
  var self = this;

    var req = env.request;
    var res = env.response;
    if (!self.peers.length) {
      res.statusCode = 404;
      res.end();
      return;
    }
    var messageId = ++self.idCounter;

    // change this to handle multiple fogs
    self.clients[messageId] = res;//req.socket; Will need socket for event broadcast.

    var appName = req.url.split('/')[2];

    req.headers['zetta-message-id'] = messageId;
    req.headers['zetta-forwarded-server'] = appName;

    var agent = env.zettaAgent || self.agents[appName];
    if (!agent){
      res.statusCode = 404;
      res.end();
      return;
    }

    var path = req.url.replace(appName, self.router[appName]);
    var opts = { method: req.method, headers: req.headers, path: path, agent: agent };
    var request = http.request(opts, function(response) {
      var id = response.headers['zetta-message-id'];
      var res = self.clients[id];

      if (!res) {
        response.statusCode = 404;
        return;
      }

      Object.keys(response.headers).forEach(function(header) {
        if (header !== 'zetta-message-id') {
          res.setHeader(header, response.headers[header]);
        }
      });

      response.pipe(res);

      response.on('finish', function() {
        delete self.clients[id];
        next(env);
      });

    });

    if (req.body) {
      request.end(req.body);
    } else {
      req.pipe(request);
    }
  //});
};
<commit_msg>fixed bug in ws connection<commit_after>var http = require('http');
var path = require('path');
var url = require('url');
var querystring = require('querystring');
var spdy = require('spdy');
var argo = require('argo');
var argoMultiparty = require('argo-multiparty');
var titan = require('titan');
var WebSocketServer = require('ws').Server;
var SpdyAgent = require('./spdy_agent');
var EventBroker = require('./event_broker');
var PeerSocket = require('./peer_socket');
var EventSocket = require('./event_socket');
var Siren = require('argo-formatter-siren');
var DevicesResource = require('./api_resources/devices');
var PeersManagementResource = require('./api_resources/peer_management');
var RootResource = require('./api_resources/root');
var ServersResource = require('./api_resources/servers');
var PubSubResource = require('./api_resources/pubsub_subscriptions');
var rels = require('./api_rels');

var ZettaHttpServer = module.exports = function(zettaInstance) {
  this.idCounter = 0;
  this.server = http.createServer();
  this.zetta = zettaInstance;
  this.peerRegistry = zettaInstance.peerRegistry;
  this.eventBroker = new EventBroker(zettaInstance);
  this.clients = {};
  this.agent = null;
  this.peers = [];
  this.agents = {};
  this.router = {};
  this._collectors = {};
  this.server = http.createServer();
  this.spdyServer = spdy.createServer({
    windowSize: 1024 * 1024,
    plain: true,
    ssl: false
  });

  this.cloud = argo()
    .use(titan)
   .format({ engines: [Siren], override: { 'application/json': Siren }, directory: path.join(__dirname, './api_formats') })
    .add(RootResource, zettaInstance)
    .add(PeersManagementResource, zettaInstance)
    .add(DevicesResource, zettaInstance)
    .add(ServersResource, zettaInstance)
    .add(PubSubResource, zettaInstance)
    .use(argoMultiparty)
    .allow({
      methods: ['DELETE', 'PUT', 'PATCH', 'POST'],
      origins: ['*'],
      headers: ['accept', 'content-type'],
      maxAge: '432000'
    })
    .use(function(handle) {
      handle('request', function(env, next) {
        if (env.request.headers['zetta-message-id']) {
          env.response.setHeader('zetta-message-id', env.request.headers['zetta-message-id']);
        }
        next(env);
      });
    })
    .use(function(handle) {
      handle('request', function(env, next) {
        if (env.request.method === 'OPTIONS') {
          env.argo._routed = true;
        }
        next(env);
      });
    });
};

ZettaHttpServer.prototype.init = function(cb) {
  var self = this;

  // handle http registration of device
  this.cloud = this.cloud.use(this.httpRegistration.bind(this));
  // handle proxying to peer
  //this.cloud = this.cloud.route('*', this.proxyToPeer.bind(this));
  // setup http servers request handler to argo routes
  this.cloud = this.cloud.build();

  this.server.on('request', this.cloud.run);
  this.spdyServer.on('request', this.cloud.run);

  this.wss = new WebSocketServer({ server: this.server });
  this.wss.on('connection', function(ws) {
    var match = /^\/peers\/(.+)$/.exec(ws.upgradeReq.url);
    if (match) {
      var peerId = match[1];
      var peer = new PeerSocket(ws, peerId);

      self.zetta.log.emit('log', 'http_server', 'Websocket connection for peer ' + peerId + ' established');

      var requestOpts = { method: 'GET', path: '/', agent: peer.agent };
      var peerRequest = http.request(requestOpts, function(res) {
        var buffer = [];
        var len = 0;

        res.on('readable', function() {
          var data;
          while (data = res.read()) {
            buffer.push(data);
            len += data.length;
          }
        });

        res.on('end', function() {
          self.zetta.log.emit('log', 'http_server', 'Peer http request finished ' + peerId);
          var buf = Buffer.concat(buffer, len);
          var root = JSON.parse(buf.toString());

          var peerName = root.links.filter(function(link) {
            return link.rel.indexOf(rels.server) !== -1;
          })[0].title;

          var peerItem = {
            peerId: peerId,
            direction: 'acceptor',
            name: peerName,
            status: 'connected'
          };

          self.peerRegistry.add(peerItem, function(err, newPeer) {
            if (err) {
              console.error('HttpServer: Failed to save peeer information', err);
              ws.close();
              return;
            }

            self.zetta.log.emit('log', 'http_server', 'Peer connection established ' + peerId + ' maped to ' + newPeer.id);

            peer.serverId = newPeer.id; // set proxy peer id
            self.agents[newPeer.id] = peer.agent;
            self.agents[peerId] = peer.agent;
            self.router[newPeer.id] = peerId;
            self.peers.push(peer);
            self.eventBroker.peer(peer);

            ws.on('close', function() {
              self.zetta.log.emit('log', 'http_server', 'Peer connection closed for ' + peerId + ' maped to ' + newPeer.id);
              self._cleanupPeer(peer); // remove from zetta internals
              self.peerRegistry.get(newPeer.id, function(err, peer) {
                peer = JSON.parse(peer);
                if (peer) {
                  peer.status = 'disconnected';
                  self.peerRegistry.save(peer);
                }
              });
            });

            ws.on('error', function(err) {
              self.zetta.log.emit('log', 'http_server', 'Peer connection failed for ' + peerId + ' maped to ' + newPeer.id);
              self._cleanupPeer(peer); // remove from zetta internals
              self.peerRegistry.get(newPeer.id, function(err, peer) {
                peer = JSON.parse(peer);
                if (peer) {
                  peer.status = 'failed';
                  peer.error = err;
                  self.peerRegistry.save(peer);
                }
              });
            });
          });
        });
      });

      peerRequest.on('error', function(err) {
        console.error('Peer request failed', err);
        ws.close(); // close socket if request failed
      });

      setImmediate(peerRequest.end.bind(peerRequest));
    } else {
      self.setupEventSocket(ws);
    }
  });

  if (cb) {
    cb();
  }
};

ZettaHttpServer.prototype.listen = function() {
  this.server.listen.apply(this.server,arguments);
  return this;
};

ZettaHttpServer.prototype.collector = function(name, collector) {
  if(typeof name === 'function'){
    collector = name;
    name = '_logs';
  }

  if(!this._collectors[name]) {
    this._collectors[name] = [];
  }

  this._collectors[name].push(collector);
  return this;
};

ZettaHttpServer.prototype.setupEventSocket = function(ws) {
  var match = /^\/servers\/(.+)\/events/.exec(ws.upgradeReq.url);
  if(!match) {
    ws.close(1001); // go away status code
    return;
  }
  var query = querystring.parse(url.parse(ws.upgradeReq.url).query);
  query.serverId = match[1]; // set serverId on query
  var client = new EventSocket(ws, query);
  this.eventBroker.client(client);
};

ZettaHttpServer.prototype._cleanupPeer = function(peerSocket) {
  var peerId = this.router[peerSocket.serverId];
  delete this.agents[peerSocket.serverId];
  delete this.agents[peerId];
  delete this.router[peerSocket.serverId];
  var idx = this.peers.indexOf(peerSocket);
  if (idx !== -1) {
    this.peers.splice(idx, 1);
  }

  //  this.eventBroker.peer(peer);
};

ZettaHttpServer.prototype.httpRegistration = function(handle) {
  handle('request', function(env, next) {
    if (!(env.request.method === 'POST' && env.request.url === '/registration')) {
      return next(env);
    }

    env.request.getBody(function(err, body) {
      body = JSON.parse(body.toString());
      var agent = self.agents[body.target];

      if (!agent) {
        env.response.statusCode = 404;
        return next(env);
      }

      env.request.body = new Buffer(JSON.stringify(body.device));
      env.zettaAgent = agent;
      next(env);
    });
  });
};

//ZettaHttpServer.prototype.proxyToPeer = function(handle) {
ZettaHttpServer.prototype.proxyToPeer = function(env, next) {
  //handle('request', function(env, next) {
  var self = this;

    var req = env.request;
    var res = env.response;
    if (!self.peers.length) {
      res.statusCode = 404;
      res.end();
      return;
    }
    var messageId = ++self.idCounter;

    // change this to handle multiple fogs
    self.clients[messageId] = res;//req.socket; Will need socket for event broadcast.

    var appName = req.url.split('/')[2];

    req.headers['zetta-message-id'] = messageId;
    req.headers['zetta-forwarded-server'] = appName;

    var agent = env.zettaAgent || self.agents[appName];
    if (!agent){
      res.statusCode = 404;
      res.end();
      return;
    }

    var path = req.url.replace(appName, self.router[appName]);
    var opts = { method: req.method, headers: req.headers, path: path, agent: agent };
    var request = http.request(opts, function(response) {
      var id = response.headers['zetta-message-id'];
      var res = self.clients[id];

      if (!res) {
        response.statusCode = 404;
        return;
      }

      Object.keys(response.headers).forEach(function(header) {
        if (header !== 'zetta-message-id') {
          res.setHeader(header, response.headers[header]);
        }
      });

      response.pipe(res);

      response.on('finish', function() {
        delete self.clients[id];
        next(env);
      });

    });

    if (req.body) {
      request.end(req.body);
    } else {
      req.pipe(request);
    }
  //});
};
<|endoftext|>


<commit_before>/* global Parse */
/* global console */
(function() {
'use strict';

// Load module dependencies
var _ = require('underscore');

// Use Parse.Cloud.define to define as many cloud functions as you want.
Parse.Cloud.define('slove', function(request, response) {
  response.success('You\'ve been sloved!');
});

/**
 * Twilio (phone confirmation)
 */
var twilioLiveMode = true;

var testSid = 'AC67aa36effde530903ec7d9a2b11b9498';
var testTok = '0b508f57260346c4b909d3f4e063c3b3';
var liveSid = 'AC7848a69b13ee905acf3aa3fc00a32270';
var liveTok = '30d9b2319348852525081e14ce693749';

var sandboxPin = '9863-5189';
var sandboxPhone = '+33644600124';
var livePhone = '+16466933339';

var twilio = require('twilio')(
  twilioLiveMode ? liveSid : testSid,
  twilioLiveMode ? liveTok : testTok
);

Parse.Cloud.define('sendPhoneCode', function(request, response) {
  var phoneNumber = request.params.phoneNumber;
  var query = new Parse.Query(Parse.User);

  query.equalTo('phoneNumber', phoneNumber);
  query.find().then(function(results) {
    if (results.length > 0) {
      response.error('error_phone_number_already_used');
    }
    else {
      var verificationCode = _.random(1000, 9999).toString();

      // Save the verificationCode for the user who requested the validation
      var user = Parse.User.current();
      user.set('phoneVerificationCode', verificationCode);
      user.save();

      var sms = 'Hi from Slove! Your verification code is: ' + verificationCode;
      twilio.sendSms({
        From: twilioLiveMode ? livePhone : sandboxPhone,
        To: phoneNumber,
        Body: twilioLiveMode ? sms : sandboxPin + ' ' + sms
      },
      function(errorData, responseData) {
        if (!errorData) {
          responseData.status = 'ok';
          response.success(responseData);
        }
        else {
          console.error(errorData);
          response.error('error_failed_to_send');
        }
      });
    }
  });
});

Parse.Cloud.define('confirmPhoneCode', function(request, response) {
  var user = Parse.User.current();
  var verificationCode = user.get('phoneVerificationCode');

  if (verificationCode === request.params.phoneVerificationCode) {
    user.set('phoneNumber', request.params.phoneNumber);
    user.save();
    response.success({ status: 'ok' });
  }
  else {
    response.error('error_codes_dont_match');
  }
});

/**
 * Contacts and Facebook friends
 */
Parse.Cloud.define('getRegisteredContacts', function(request, response) {
  var phoneNumbers = request.params.phoneNumbers;
  // Check if param was sent correctly
  if (phoneNumbers === undefined) {
    response.error('error_missing_param');
    return;
  }
  // Check if param is in the expected format
  if (!Array.isArray(phoneNumbers)) {
    response.error('error_param_is_not_an_array');
    return;
  }

  // Run the query with supplied param and send back formated results,
  // or send an error message if no match was found
  var registeredContacts = [];
  var userObject = {
    username: '',
    phoneNumber: '',
    pictureUrl: ''
  };
  var currentUser;
  var query = new Parse.Query(Parse.User);
  query.containedIn('phoneNumber', phoneNumbers);
  query.each(function(user) {
    currentUser = Object.create(userObject);
    currentUser.username = user.get('username') ? user.get('username') : '';
    currentUser.pictureUrl = user.get('pictureUrl') ? user.get('pictureUrl') : '';
    // We know this one is present because it matched
    currentUser.phoneNumber = user.get('phoneNumber');
    // Save it to the list that we will return
    registeredContacts.push(currentUser);
  })
  .then(function() {
    if (registeredContacts.length > 0) {
      response.success({ status: 'ok', registeredContacts: registeredContacts });
    }
    else {
      response.error('error_no_user_found');
    }
  });
});

Parse.Cloud.define('getRegisteredFriends', function(request, response) {
  var facebookIds = request.params.facebookIds;
  // Check if param was sent correctly
  if (facebookIds === undefined) {
    response.error('error_missing_param');
    return;
  }
  // Check if param is in the expected format
  if (!Array.isArray(facebookIds)) {
    response.error('error_param_is_not_an_array');
    return;
  }

  // Run the query with supplied param and send back formated results,
  // or send an error message if no match was found
  var registeredFriends = [];
  var userObject = {
    username: '',
    facebookId: '',
    pictureUrl: ''
  };
  var currentUser;
  var query = new Parse.Query(Parse.User);
  query.containedIn('facebookId', facebookIds);
  query.each(function(user) {
    currentUser = Object.create(userObject);
    currentUser.username = user.get('username') ? user.get('username') : '';
    currentUser.pictureUrl = user.get('pictureUrl') ? user.get('pictureUrl') : '';
    // We know this one is present because it matched
    currentUser.facebookId = user.get('facebookId');
    // Save it to the list that we will return
    registeredFriends.push(currentUser);
  })
  .then(function() {
    if (registeredFriends.length > 0) {
      response.success({ status: 'ok', registeredFriends: registeredFriends });
    }
    else {
      response.error('error_no_user_found');
    }
  });
});

/**
 * Serious business: send Slove and Push notifs!
 */
Parse.Cloud.define('sendSlove', function(request, response) {
  // Retrieve users
  var slover = Parse.User.current();
  var targetUsername = request.params.username;
  // Retrieve sloved user info
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', targetUsername);
  query.first({
    success: function(target) {
      if (!target) {
        response.error('error_username_doesnt_exist');
        return;
      }

      if (slover.get('sloveCounter') < 1) {
        response.error('error_not_enough_slove');
        return;
      }

      // Create Slove object that will be passed the data and saved
      var Slove = Parse.Object.extend('Slove');
      var slove = new Slove();

      // Create the Slove to be saved
      var sloveData = {
        slover: slover,
        sloved: target
      };

      // Saving Slove in database
      slove.save(sloveData, {
        success: function(savedSlove) {
          console.log({ savedSlove: savedSlove.id });

          /**
           * Slove saved successfully, trying to send Slove push
           * Update of the sloveCounter takes place in an afterSave hook
           */
          var pushData = {
            channels: [targetUsername],
            data: {
              alert: '♥ New Slove ♥',
              badge: 'Increment',
              sound: 'Assets/Sound/Congratsbuild2.wav',
              slover: {
                username: slover.get('username'),
                pictureUrl: slover.get('pictureUrl')
              }
            }
          };
          var pushOptions = {
            success: function() {
              // Push was sent successfully
              response.success({ status: 'ok', sloved: targetUsername });
            },
            error: function(error) {
              console.error({ pushError: error });
              response.error('error_push_couldnt_be_sent');
            }
          };
          Parse.Push.send(pushData, pushOptions);
        },
        error: function(slove, error) {
          // The save failed.
          // error is a Parse.Error with an error code and message.
          console.error({ sendSloveError: error });
          response.error('error_slove_couldnt_be_saved');
        }
      });
    },
    error: function() {
      response.error('error_user_request_failed');
    }
  });
});

/**
 * 1) Updating sloveCounter for the slover
 * 2) Setting permissions on the Slove object
 */
Parse.Cloud.afterSave('Slove', function(request) {
  Parse.Cloud.useMasterKey();

  // Check if the object was just created
  if (request.object.existed() === false) {
    // 1)
    // Slover counter update
    request.object.get('slover').fetch().then(function(slover) {
      var sloverCounter = slover.get('sloveCounter');
      slover.set('sloveCounter', sloverCounter - 1);
      slover.save();
    });

    // 2)
    // No public read nor write
    var acl = new Parse.ACL();
    acl.setPublicReadAccess(false);
    acl.setPublicWriteAccess(false);
    // Apply ACL to the object and save
    request.object.setACL(acl);
    request.object.save();
  }
});

/**
 * Background job meant to be executed every day to give users their daily amount of Sloves
 */
Parse.Cloud.job('dailySloveDistribution', function(request, status) {
  // Set up to modify user data
  Parse.Cloud.useMasterKey();
  // Counter of updated users
  var counter = 0;
  // Query for all users (@todo: add timezone management later)
  var query = new Parse.Query(Parse.User);
  query.each(function(user) {
    counter++;
    // Reinit sloveNumber(-Counter, to rename?) based on sloveCredit value
    user.set('sloveCounter', user.get('sloveCredit'));
    return user.save();
  })
  .then(
    function() {
      // Set the job's success status
      status.message(counter + ' users processed');
      status.success('Job finished successfully');
    },
    function(error) {
      // Set the job's error status
      console.error(error);
      status.error('Job encountered an error');
    }
  );
});

/**
 * User
 */
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
  // Check if the object was just created
  if (request.object.existed() === false) {
    // Set arbitrary default number. Could be set differently...
    request.object.set('sloveCounter', 5);
    request.object.set('sloveCredit', 5);
  }
  response.success();
});

/**
 * Follows
 */
Parse.Cloud.define('addFollow', function(request, response) {
  // Retrieve users
  var currentUser = Parse.User.current();
  var newFollowUsername = request.params.username;
  // Retrieve newRelation user info
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', newFollowUsername);
  query.first({
    success: function(newFollow) {
      if (!newFollow) {
        response.error('error_username_doesnt_exist');
        return;
      }

      // Create Relation object that will be passed the data and saved
      var Follow = Parse.Object.extend('Follow');
      var follow = new Follow();

      // Create the Relation to be saved
      var followData = {
        from: currentUser,
        to: newFollow
      };

      // Saving Relation in database
      follow.save(followData, {
        success: function(savedFollow) {
          response.success({ status: 'ok', newFollow: savedFollow.id });
        },
        error: function(follow, error) {
          // The save failed.
          // error is a Parse.Error with an error code and message.
          console.error({ newFollowError: error });
          response.error('error_follow_couldnt_be_saved');
        }
      });
    },
    error: function() {
      response.error('error_request_failed');
    }
  });
});

Parse.Cloud.define('getFollows', function(request, response) {
  var query = new Parse.Query('Follow');

  // Tells the query to retrieve the user objects, not just the reference to them
  query.include('to');

  // Add query condition to get only current user's follows
  query.equalTo('from', Parse.User.current());

  // Prepare data
  var follows = [];
  var userObject = {
    username: '',
    pictureUrl: ''
  };
  var currentUser;
  var followedUser;

  // Execute query and loop through results
  query.each(function(follow) {
    followedUser = follow.get('to');
    currentUser = Object.create(userObject);
    currentUser.username = followedUser.get('username') ? followedUser.get('username') : '';
    currentUser.pictureUrl = followedUser.get('pictureUrl') ? followedUser.get('pictureUrl') : '';
    // Save it to the list that we will return
    follows.push(currentUser);
  })
  .then(function() {
    if (follows.length > 0) {
      response.success({ status: 'ok', follows: follows });
    }
    else {
      response.error('error_no_user_found');
    }
  });
});

})();
<commit_msg>Add getActivities<commit_after>/* global Parse */
/* global console */
(function() {
'use strict';

// Load module dependencies
var _ = require('underscore');

// Use Parse.Cloud.define to define as many cloud functions as you want.
Parse.Cloud.define('slove', function(request, response) {
  response.success('You\'ve been sloved!');
});

/**
 * Twilio (phone confirmation)
 */
var twilioLiveMode = true;

var testSid = 'AC67aa36effde530903ec7d9a2b11b9498';
var testTok = '0b508f57260346c4b909d3f4e063c3b3';
var liveSid = 'AC7848a69b13ee905acf3aa3fc00a32270';
var liveTok = '30d9b2319348852525081e14ce693749';

var sandboxPin = '9863-5189';
var sandboxPhone = '+33644600124';
var livePhone = '+16466933339';

var twilio = require('twilio')(
  twilioLiveMode ? liveSid : testSid,
  twilioLiveMode ? liveTok : testTok
);

Parse.Cloud.define('sendPhoneCode', function(request, response) {
  var phoneNumber = request.params.phoneNumber;
  var query = new Parse.Query(Parse.User);

  query.equalTo('phoneNumber', phoneNumber);
  query.find().then(function(results) {
    if (results.length > 0) {
      response.error('error_phone_number_already_used');
    }
    else {
      var verificationCode = _.random(1000, 9999).toString();

      // Save the verificationCode for the user who requested the validation
      var user = Parse.User.current();
      user.set('phoneVerificationCode', verificationCode);
      user.save();

      var sms = 'Hi from Slove! Your verification code is: ' + verificationCode;
      twilio.sendSms({
        From: twilioLiveMode ? livePhone : sandboxPhone,
        To: phoneNumber,
        Body: twilioLiveMode ? sms : sandboxPin + ' ' + sms
      },
      function(errorData, responseData) {
        if (!errorData) {
          responseData.status = 'ok';
          response.success(responseData);
        }
        else {
          console.error(errorData);
          response.error('error_failed_to_send');
        }
      });
    }
  });
});

Parse.Cloud.define('confirmPhoneCode', function(request, response) {
  var user = Parse.User.current();
  var verificationCode = user.get('phoneVerificationCode');

  if (verificationCode === request.params.phoneVerificationCode) {
    user.set('phoneNumber', request.params.phoneNumber);
    user.save();
    response.success({ status: 'ok' });
  }
  else {
    response.error('error_codes_dont_match');
  }
});

/**
 * Contacts and Facebook friends
 */
Parse.Cloud.define('getRegisteredContacts', function(request, response) {
  var phoneNumbers = request.params.phoneNumbers;
  // Check if param was sent correctly
  if (phoneNumbers === undefined) {
    response.error('error_missing_param');
    return;
  }
  // Check if param is in the expected format
  if (!Array.isArray(phoneNumbers)) {
    response.error('error_param_is_not_an_array');
    return;
  }

  // Run the query with supplied param and send back formated results,
  // or send an error message if no match was found
  var registeredContacts = [];
  var userObject = {
    username: '',
    phoneNumber: '',
    pictureUrl: ''
  };
  var currentUser;
  var query = new Parse.Query(Parse.User);
  query.containedIn('phoneNumber', phoneNumbers);
  query.each(function(user) {
    currentUser = Object.create(userObject);
    currentUser.username = user.get('username') ? user.get('username') : '';
    currentUser.pictureUrl = user.get('pictureUrl') ? user.get('pictureUrl') : '';
    // We know this one is present because it matched
    currentUser.phoneNumber = user.get('phoneNumber');
    // Save it to the list that we will return
    registeredContacts.push(currentUser);
  })
  .then(function() {
    if (registeredContacts.length > 0) {
      response.success({ status: 'ok', registeredContacts: registeredContacts });
    }
    else {
      response.error('error_no_user_found');
    }
  });
});

Parse.Cloud.define('getRegisteredFriends', function(request, response) {
  var facebookIds = request.params.facebookIds;
  // Check if param was sent correctly
  if (facebookIds === undefined) {
    response.error('error_missing_param');
    return;
  }
  // Check if param is in the expected format
  if (!Array.isArray(facebookIds)) {
    response.error('error_param_is_not_an_array');
    return;
  }

  // Run the query with supplied param and send back formated results,
  // or send an error message if no match was found
  var registeredFriends = [];
  var userObject = {
    username: '',
    facebookId: '',
    pictureUrl: ''
  };
  var currentUser;
  var query = new Parse.Query(Parse.User);
  query.containedIn('facebookId', facebookIds);
  query.each(function(user) {
    currentUser = Object.create(userObject);
    currentUser.username = user.get('username') ? user.get('username') : '';
    currentUser.pictureUrl = user.get('pictureUrl') ? user.get('pictureUrl') : '';
    // We know this one is present because it matched
    currentUser.facebookId = user.get('facebookId');
    // Save it to the list that we will return
    registeredFriends.push(currentUser);
  })
  .then(function() {
    if (registeredFriends.length > 0) {
      response.success({ status: 'ok', registeredFriends: registeredFriends });
    }
    else {
      response.error('error_no_user_found');
    }
  });
});

/**
 * Serious business: send Slove and Push notifs!
 */
Parse.Cloud.define('sendSlove', function(request, response) {
  // Retrieve users
  var slover = Parse.User.current();
  var targetUsername = request.params.username;
  // Retrieve sloved user info
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', targetUsername);
  query.first({
    success: function(target) {
      if (!target) {
        response.error('error_username_doesnt_exist');
        return;
      }

      if (slover.get('sloveCounter') < 1) {
        response.error('error_not_enough_slove');
        return;
      }

      // Create Slove object that will be passed the data and saved
      var Slove = Parse.Object.extend('Slove');
      var slove = new Slove();

      // Create the Slove to be saved
      var sloveData = {
        slover: slover,
        sloved: target
      };

      // Saving Slove in database
      slove.save(sloveData, {
        success: function(savedSlove) {
          console.log({ savedSlove: savedSlove.id });

          /**
           * Slove saved successfully, trying to send Slove push
           * Update of the sloveCounter takes place in an afterSave hook
           */
          var pushData = {
            channels: [targetUsername],
            data: {
              alert: '♥ New Slove from ' + slover.get('username') + ' ♥',
              badge: 'Increment',
              sound: 'Assets/Sound/Congratsbuild2.wav',
              slover: {
                username: slover.get('username'),
                pictureUrl: slover.get('pictureUrl')
              }
            }
          };
          var pushOptions = {
            success: function() {
              // Push was sent successfully
              response.success({ status: 'ok', sloved: targetUsername });
            },
            error: function(error) {
              console.error({ pushError: error });
              response.error('error_push_couldnt_be_sent');
            }
          };
          Parse.Push.send(pushData, pushOptions);
        },
        error: function(slove, error) {
          // The save failed.
          // error is a Parse.Error with an error code and message.
          console.error({ sendSloveError: error });
          response.error('error_slove_couldnt_be_saved');
        }
      });
    },
    error: function() {
      response.error('error_user_request_failed');
    }
  });
});

/**
 * 1) Updating sloveCounter for the slover
 * 2) Setting permissions on the Slove object
 */
Parse.Cloud.afterSave('Slove', function(request) {
  Parse.Cloud.useMasterKey();

  // Check if the object was just created
  if (request.object.existed() === false) {
    // 1)
    // Slover counter update
    request.object.get('slover').fetch().then(function(slover) {
      var sloverCounter = slover.get('sloveCounter');
      slover.set('sloveCounter', sloverCounter - 1);
      slover.save();
    });

    // 2)
    // No public read nor write
    var acl = new Parse.ACL();
    acl.setPublicReadAccess(false);
    acl.setPublicWriteAccess(false);
    // Apply ACL to the object and save
    request.object.setACL(acl);
    request.object.save();
  }
});

/**
 * Background job meant to be executed every day to give users their daily amount of Sloves
 */
Parse.Cloud.job('dailySloveDistribution', function(request, status) {
  // Set up to modify user data
  Parse.Cloud.useMasterKey();
  // Counter of updated users
  var counter = 0;
  // Query for all users (@todo: add timezone management later)
  var query = new Parse.Query(Parse.User);
  query.each(function(user) {
    counter++;
    // Reinit sloveNumber(-Counter, to rename?) based on sloveCredit value
    user.set('sloveCounter', user.get('sloveCredit'));
    return user.save();
  })
  .then(
    function() {
      // Set the job's success status
      status.message(counter + ' users processed');
      status.success('Job finished successfully');
    },
    function(error) {
      // Set the job's error status
      console.error(error);
      status.error('Job encountered an error');
    }
  );
});

/**
 * User
 */
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
  // Check if the object was just created
  if (request.object.existed() === false) {
    // Set arbitrary default number. Could be set differently...
    request.object.set('sloveCounter', 5);
    request.object.set('sloveCredit', 5);
  }
  response.success();
});

/**
 * Follows
 */
Parse.Cloud.define('addFollow', function(request, response) {
  // Retrieve users
  var currentUser = Parse.User.current();
  var newFollowUsername = request.params.username;
  // Retrieve newRelation user info
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', newFollowUsername);
  query.first({
    success: function(newFollow) {
      if (!newFollow) {
        response.error('error_username_doesnt_exist');
        return;
      }

      // Create Relation object that will be passed the data and saved
      var Follow = Parse.Object.extend('Follow');
      var follow = new Follow();

      // Create the Relation to be saved
      var followData = {
        from: currentUser,
        to: newFollow
      };

      // Saving Relation in database
      follow.save(followData, {
        success: function(savedFollow) {
          response.success({ status: 'ok', newFollow: savedFollow.id });
        },
        error: function(follow, error) {
          // The save failed.
          // error is a Parse.Error with an error code and message.
          console.error({ newFollowError: error });
          response.error('error_follow_couldnt_be_saved');
        }
      });
    },
    error: function() {
      response.error('error_request_failed');
    }
  });
});

Parse.Cloud.define('getFollows', function(request, response) {
  var query = new Parse.Query('Follow');

  // Tells the query to retrieve the user objects, not just the reference to them
  query.include('to');

  // Add query condition to get only current user's follows
  query.equalTo('from', Parse.User.current());

  // Prepare data
  var follows = [];
  var userObject = {
    username: '',
    pictureUrl: ''
  };
  var currentUser;
  var followedUser;

  // Execute query and loop through results
  query.each(function(follow) {
    followedUser = follow.get('to');
    currentUser = Object.create(userObject);
    currentUser.username = followedUser.get('username') ? followedUser.get('username') : '';
    currentUser.pictureUrl = followedUser.get('pictureUrl') ? followedUser.get('pictureUrl') : '';
    // Save it to the list that we will return
    follows.push(currentUser);
  })
  .then(
    function() {
      response.success({ status: 'ok', follows: follows });
    },
    function() {
      response.error('error_request_failed');
    }
  );
});

/**
 * Activity
 */
Parse.Cloud.define('getActivities', function(request, response) {
  var query = new Parse.Query('Activity');

  // Limit number of activities returned, and order them by date
  query.limit(20);
  query.descending('createdAt');

  // Tells the query to retrieve the relatedUser objects, not just the reference to them
  query.include('relatedUser');

  // Add query condition to get only current user's activity
  query.equalTo('user', Parse.User.current());

  // Prepare data
  var activities = [];
  var activityObject = {
    isNew: false,
    activityType: '',
    activityValue: 0,
    relatedUser: ''
  };
  var currentActivity;
  var relatedUser;

  // Execute query and create result list
  query.find({
    success: function(results) {
      _.each(results, function(activity) {
        // Create and populate a sample activity object
        relatedUser = activity.get('relatedUser') ? activity.get('relatedUser') : null;

        currentActivity = Object.create(activityObject);
        currentActivity.activityType = activity.get('activityType') ? activity.get('activityType') : '';
        currentActivity.activityValue = activity.get('activityValue') ? activity.get('activityValue') : 0;
        currentActivity.relatedUser = relatedUser ? relatedUser.get('username') : '';

        // Save it to the list that we will return
        activities.push(currentActivity);
      });

      // Send data back
      response.success({ status: 'ok', activities: activities });
    },
    error: function(error) {
      console.error('getActivities failed: ' + error.message + ' (code: ' + error.code + ')');
      response.error('error_request_failed');
    }
  });
});

})();
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import DaysViewHeading from './DaysViewHeading';
import DaysOfWeek from './DaysOfWeek';
import MonthSelector from './MonthSelector';
import Day from './Day';
import { getDaysOfMonth } from '../utils/moment-helper';
import moment from 'moment-jalaali';
import onClickOutside from 'react-onclickoutside';
import { defaultStyles } from './DefaultStyles';

export class Calendar extends Component {
  static propTypes = {
    min: PropTypes.object,
    max: PropTypes.object,
    styles: PropTypes.object,
    selectedDay: PropTypes.object,
    defaultMonth: PropTypes.object,
    onSelect: PropTypes.func,
    onClickOutside: PropTypes.func,
    containerProps: PropTypes.object,
    isGregorian: PropTypes.bool
  };

  static childContextTypes = {
    nextMonth: PropTypes.func.isRequired,
    prevMonth: PropTypes.func.isRequired,
    setCalendarMode: PropTypes.func.isRequired,
    setMonth: PropTypes.func.isRequired,
    setType: PropTypes.func.isRequired
  };

  static defaultProps = {
    styles: defaultStyles,
    containerProps: {},
    isGregorian:false
  };

  state = {
    month: this.props.defaultMonth || this.props.selectedDay || moment(this.props.min),
    selectedDay: this.props.selectedDay || null,
    mode: 'days',
    isGregorian: this.props.isGregorian
  };

  getChildContext() {
    return {
      nextMonth: this.nextMonth.bind(this),
      prevMonth: this.prevMonth.bind(this),
      setCalendarMode: this.setMode.bind(this),
      setMonth: this.setMonth.bind(this),
      setType: this.setMonth.bind(this)
    };
  }

  componentWillReceiveProps({ selectedDay, defaultMonth, min }) {
    if (this.props.selectedDay !== selectedDay) {
      this.selectDay(selectedDay);
    } else if (defaultMonth && this.props.defaultMonth !== defaultMonth && this.state.month === this.props.defaultMonth) {
      this.setMonth(defaultMonth);
    } else if (min && this.props.min !== min && this.state.month.isSame(this.props.min)) {
      this.setMonth(min.clone());
    }
  }

  setMode(mode) {
    this.setState({ mode });
  }

  setMonth(month) {
    this.setState({ month });
  }

  setType(type) {
    this.setState({ type });
  }

  nextMonth() {
    const { isGregorian } = this.state;
    const monthFormat = isGregorian ? 'Month' : 'jMonth';

    this.setState({
      month: this.state.month.clone().add(1, monthFormat)
    });
  }

  prevMonth() {
    const { isGregorian } = this.state;
    const monthFormat = isGregorian ? 'Month' : 'jMonth';

    this.setState({
      month: this.state.month.clone().subtract(1, monthFormat)
    });
  }

  selectDay(selectedDay) {
    const { month, isGregorian } = this.state;
    const yearMonthFormat = isGregorian ? 'YYYYMM' : 'jYYYYjMM';

    // Because there's no `m1.isSame(m2, 'jMonth')`
    if (selectedDay.format(yearMonthFormat) !== month.format(yearMonthFormat)) {
      this.setState({ month: selectedDay });
    }

    this.setState({ selectedDay });
  }

  handleClickOnDay = selectedDay => {
    const { onSelect } = this.props;
    this.selectDay(selectedDay);
    if (onSelect) {
      onSelect(selectedDay);
    }
  };

  handleClickOutside(event) {
    if (this.props.onClickOutside) {
      this.props.onClickOutside(event);
    }
  }

  days = null;
  lastRenderedMonth = null;

  renderMonthSelector() {
    const { month, isGregorian } = this.state;
    const { styles } = this.props;
    return (<MonthSelector styles={styles} isGregorian={isGregorian} selectedMonth={month} />);
  }

  renderDays() {
    const { month, selectedDay, isGregorian } = this.state;
    const { children, min, max, styles, outsideClickIgnoreClass } = this.props;

    let days;

    if (this.lastRenderedMonth === month) {
      days = this.days;
    } else {
      days = getDaysOfMonth(month, isGregorian);
      this.days = days;
      this.lastRenderedMonth = month;
    }

    const monthFormat = isGregorian ? 'MM' : 'jMM';
    const dateFormat = isGregorian ? 'YYYYMMDD' : 'jYYYYjMMjDD';

    return (

        {children}
        <DaysViewHeading isGregorian={isGregorian} styles={styles} month={month} />
        <DaysOfWeek styles={styles} isGregorian={isGregorian} />

          {
            days.map(day => {
              const isCurrentMonth = day.format(monthFormat) === month.format(monthFormat);
              const disabled = (min ? day.isBefore(min) : false) || (max ? day.isAfter(max) : false);
              const selected = selectedDay ? selectedDay.isSame(day, 'day') : false;

              return (
                <Day
                  isGregorian={isGregorian}
                  key={day.format(dateFormat)}
                  onClick={this.handleClickOnDay}
                  day={day}
                  disabled={disabled}
                  selected={selected}
                  isCurrentMonth={isCurrentMonth}
                  styles={styles}
                />
              );
            })
          }

    );
  }

  render() {
    const {
      selectedDay,
      min,
      max,
      onClickOutside,
      outsideClickIgnoreClass,
      styles,
      className
    } = this.props;
    const { mode, isGregorian } = this.state;

    const jalaaliClassName = isGregorian ? '' : 'jalaali ';

    return (

        {mode === 'monthSelector' ? this.renderMonthSelector() : this.renderDays()}

    );
  }
}

export default onClickOutside(Calendar);
<commit_msg>change calendar isGregorian default<commit_after>import React, { Component, PropTypes } from 'react';
import DaysViewHeading from './DaysViewHeading';
import DaysOfWeek from './DaysOfWeek';
import MonthSelector from './MonthSelector';
import Day from './Day';
import { getDaysOfMonth } from '../utils/moment-helper';
import moment from 'moment-jalaali';
import onClickOutside from 'react-onclickoutside';
import { defaultStyles } from './DefaultStyles';

export class Calendar extends Component {
  static propTypes = {
    min: PropTypes.object,
    max: PropTypes.object,
    styles: PropTypes.object,
    selectedDay: PropTypes.object,
    defaultMonth: PropTypes.object,
    onSelect: PropTypes.func,
    onClickOutside: PropTypes.func,
    containerProps: PropTypes.object,
    isGregorian: PropTypes.bool
  };

  static childContextTypes = {
    nextMonth: PropTypes.func.isRequired,
    prevMonth: PropTypes.func.isRequired,
    setCalendarMode: PropTypes.func.isRequired,
    setMonth: PropTypes.func.isRequired,
    setType: PropTypes.func.isRequired
  };

  static defaultProps = {
    styles: defaultStyles,
    containerProps: {},
    isGregorian: true
  };

  state = {
    month: this.props.defaultMonth || this.props.selectedDay || moment(this.props.min),
    selectedDay: this.props.selectedDay || null,
    mode: 'days',
    isGregorian: this.props.isGregorian
  };

  getChildContext() {
    return {
      nextMonth: this.nextMonth.bind(this),
      prevMonth: this.prevMonth.bind(this),
      setCalendarMode: this.setMode.bind(this),
      setMonth: this.setMonth.bind(this),
      setType: this.setMonth.bind(this)
    };
  }

  componentWillReceiveProps({ selectedDay, defaultMonth, min }) {
    if (this.props.selectedDay !== selectedDay) {
      this.selectDay(selectedDay);
    } else if (defaultMonth && this.props.defaultMonth !== defaultMonth && this.state.month === this.props.defaultMonth) {
      this.setMonth(defaultMonth);
    } else if (min && this.props.min !== min && this.state.month.isSame(this.props.min)) {
      this.setMonth(min.clone());
    }
  }

  setMode(mode) {
    this.setState({ mode });
  }

  setMonth(month) {
    this.setState({ month });
  }

  setType(type) {
    this.setState({ type });
  }

  nextMonth() {
    const { isGregorian } = this.state;
    const monthFormat = isGregorian ? 'Month' : 'jMonth';

    this.setState({
      month: this.state.month.clone().add(1, monthFormat)
    });
  }

  prevMonth() {
    const { isGregorian } = this.state;
    const monthFormat = isGregorian ? 'Month' : 'jMonth';

    this.setState({
      month: this.state.month.clone().subtract(1, monthFormat)
    });
  }

  selectDay(selectedDay) {
    const { month, isGregorian } = this.state;
    const yearMonthFormat = isGregorian ? 'YYYYMM' : 'jYYYYjMM';

    // Because there's no `m1.isSame(m2, 'jMonth')`
    if (selectedDay.format(yearMonthFormat) !== month.format(yearMonthFormat)) {
      this.setState({ month: selectedDay });
    }

    this.setState({ selectedDay });
  }

  handleClickOnDay = selectedDay => {
    const { onSelect } = this.props;
    this.selectDay(selectedDay);
    if (onSelect) {
      onSelect(selectedDay);
    }
  };

  handleClickOutside(event) {
    if (this.props.onClickOutside) {
      this.props.onClickOutside(event);
    }
  }

  days = null;
  lastRenderedMonth = null;

  renderMonthSelector() {
    const { month, isGregorian } = this.state;
    const { styles } = this.props;
    return (<MonthSelector styles={styles} isGregorian={isGregorian} selectedMonth={month} />);
  }

  renderDays() {
    const { month, selectedDay, isGregorian } = this.state;
    const { children, min, max, styles, outsideClickIgnoreClass } = this.props;

    let days;

    if (this.lastRenderedMonth === month) {
      days = this.days;
    } else {
      days = getDaysOfMonth(month, isGregorian);
      this.days = days;
      this.lastRenderedMonth = month;
    }

    const monthFormat = isGregorian ? 'MM' : 'jMM';
    const dateFormat = isGregorian ? 'YYYYMMDD' : 'jYYYYjMMjDD';

    return (

        {children}
        <DaysViewHeading isGregorian={isGregorian} styles={styles} month={month} />
        <DaysOfWeek styles={styles} isGregorian={isGregorian} />

          {
            days.map(day => {
              const isCurrentMonth = day.format(monthFormat) === month.format(monthFormat);
              const disabled = (min ? day.isBefore(min) : false) || (max ? day.isAfter(max) : false);
              const selected = selectedDay ? selectedDay.isSame(day, 'day') : false;

              return (
                <Day
                  isGregorian={isGregorian}
                  key={day.format(dateFormat)}
                  onClick={this.handleClickOnDay}
                  day={day}
                  disabled={disabled}
                  selected={selected}
                  isCurrentMonth={isCurrentMonth}
                  styles={styles}
                />
              );
            })
          }

    );
  }

  render() {
    const {
      selectedDay,
      min,
      max,
      onClickOutside,
      outsideClickIgnoreClass,
      styles,
      className
    } = this.props;
    const { mode, isGregorian } = this.state;

    const jalaaliClassName = isGregorian ? '' : 'jalaali ';

    return (

        {mode === 'monthSelector' ? this.renderMonthSelector() : this.renderDays()}

    );
  }
}

export default onClickOutside(Calendar);
<|endoftext|>


<commit_before>/**
 * entry_GLOBALS.js
 *
 * Module for loading styles and scripts related to the entire site
 *
 */

var $ = require( "jquery" ), // require jQuery
    q = require( "Q" ); // require the Q Promise library

/*
 * START MOBILE NAVIGATION CODE
 * ====================================================================
 *
 * On mobile, both the nav "hamburger" menu and search button elements
 * share the same functionality in terms of, respectively,
 * hiding/showing the site nav and search box. To make this
 * functionality reusable, create separate objects for each element
 * which contains unique element parameters, then pass the object as a
 * parameter to the "animateNavElement()" method at the bottom.
 *
 * TODO:
 * =====
 * Can the removeClassCheck() method be more dynamic?
 */

// Data object for the nav "hamburger" menu
var nav = {
  bodyClass: "show-mobile-menu",
  targetEl: "#site-navigation",
  hideClass: "hide-menu",
  showClass: "show-menu",
  removeClassCheck: function() {
    if ( $( "body" ).hasClass( "show-mobile-search" ) ) {
      $( "body" ).removeClass( "show-mobile-search" );
      $( "#searchform" ).addClass( "hide-searchbox" ).removeClass( "show-searchbox" );
    }
  },
  singleRemoveClass: function() {
    $( "#searchform" ).removeClass( "hide-searchbox" );
  }
};

// Data object for the nav "seachbox" menu
var search = {
  bodyClass: "show-mobile-search",
  targetEl: "#searchform",
  hideClass: "hide-searchbox",
  showClass: "show-searchbox",
  removeClassCheck: function() {
    if ( $( "body" ).hasClass( "show-mobile-menu" ) ) {
      $( "body" ).removeClass( "show-mobile-menu" );
      $( "#site-navigation" ).addClass( "hide-menu" ).removeClass( "show-menu" );
    }
  },
  singleRemoveClass: function() {
    $( "#site-navigation" ).removeClass( "hide-menu" );
  }
};

/*
 * CLICK METHODS FOR THE MENU & SEARCH BUTTONS
 * ====================================================================
 *
 * When clicked, each button:
 *
 * 1. runs testBranding() which toggles the #branding elements z-index
 * 2. returns a Promise
 * 3. runs animateNavElement() & the parameter is one of two vars above
 *
 */

// Menu button
$( "#mobile-menu-button" ).click( function(){

  q.fcall( function(){

    var thisTest = testBranding( "z-index: auto;", "z-index: 2;" );
    thisTest();

  }).then( function() {
    animateNavElement( nav );
  });
});

// Search button
$( "#mobile-search-button" ).click( function() {

  q.fcall( function(){

    var thisTest = testBranding( "z-index: 2;", "z-index: auto;");
    thisTest();

  }).then( function() {
    animateNavElement( search );
  });

});

/*
 * I had to write a crazy hack that toggled the z-index of the
 * "#branding" element so the main nav could stack properly and the
 * search box could be focused :-\ To redeem myself for writing a
 * crazy hack, I wrote cool code that executes the hack with a
 * closure. It runs in the "animateNavElement()" element. and the
 * "currentStyle" and "newStyle" parameters are the z-index styles
 * that get toggled.
 */
function testBranding( currentStyle, newStyle ) {

  // Store the toggled states in variables
  var isBrandingClass = $( "#branding" ).attr( "style", currentStyle ),
      isNotBrandingClass = $( "#branding" ).attr( "style", newStyle );

  // An inner function toggles the states with a ternary function check
  function getBrandingClass() {
    isBrandingClass ? isNotBrandingClass : isBrandingClass;
  }

  // Return the inner function so it's accessible when called
  return getBrandingClass;
}

/*
 * "animateNavElement()": show/hide nav & search
 * ====================================================================
 */

 // "obj" will be either the "nav" or "search" variable defined up top
function animateNavElement( obj ) {

  /*
   * Get the "bodyClass" property from the given object. If it's on
   * the <body> tag, it means the given element, the nav or the
   * searchbox, is currently in view. Then do stuff if it exists.
   */
  if( $( "body" ).hasClass( obj.bodyClass ) ) {

    // Enclose some code that returns a Promise
    q.fcall( function() {

      /*
       * Get the both "targetEl" and "hideClass" properties from the
       * given object. "targetEl" is the element being looked at...the
       * nav or the searchbox. "hideClass" is the class that hides the
       * element from view....so remove the element adding a class to
       * the <body> tag that hides it. Adding this class to the
       * element also defines its state.
       */
      $( obj.targetEl ).addClass( obj.hideClass );

      // Reset the element's state by removing whatever "bodyClass" is
      $( "body" ).removeClass( obj.bodyClass );

      /*
       * Wait 3 milliseconds after the Promise resolves, but before
       * doing stuff
       */
      return q.delay( 300 );
    }).then( function(){

      /*
       * Remove the class that hid the target element, the nav or the
       * searchbox. Also, grab the "showClass" property from the given
       * object, which is a class that element visible initially and is
       * DEFINETLY attached it at this point. Remove it as well.
       */
      $( obj.targetEl ).removeClass( obj.hideClass ).removeClass( obj.showClass );
    });
  } else {

    // Enclose some code that returns a Promise
    q.fcall( function(){

      /*
       * The opposite element MIGHT be visible now so run the
       * "removeClassCheck()" method for the given object to remove it.
       * So if the "nav" element is what's currently being focused
       * on, check to see if the "search" element is visible and
       * remove it if it is.
       */
      obj.removeClassCheck();

    // Do stuff after the Promise resolves
    }).then(function(){

      // Add a class to the element making it visible, state is defined
      $( obj.targetEl ).addClass( obj.showClass );

      /*
       * Add a class to <body> that help define the state of the
       * element, saying it's visible.
       */
      $( "body" ).addClass( obj.bodyClass );
      obj.singleRemoveClass();
    });
  }
}<commit_msg>update comments<commit_after>/**
 * entry_GLOBALS.js
 *
 * Module for loading styles and scripts related to the entire site
 *
 */

var $ = require( "jquery" ), // require jQuery
    q = require( "Q" ); // require the Q Promise library

/*
 * START MOBILE NAVIGATION CODE
 * ====================================================================
 *
 * On mobile, both the nav "hamburger" menu and search button elements
 * share the same functionality in terms of, respectively,
 * hiding/showing the site nav and search box. To make this
 * functionality reusable, create separate objects for each element
 * which contains unique element parameters, then pass the object as a
 * parameter to the "animateNavElement()" method at the bottom.
 *
 * TODO:
 * =====
 * Can the removeClassCheck() method be more dynamic?
 */

// Data object for the nav "hamburger" menu
var nav = {
  bodyClass: "show-mobile-menu",
  targetEl: "#site-navigation",
  hideClass: "hide-menu",
  showClass: "show-menu",
  removeClassCheck: function() {
    if ( $( "body" ).hasClass( "show-mobile-search" ) ) {
      $( "body" ).removeClass( "show-mobile-search" );
      $( "#searchform" ).addClass( "hide-searchbox" ).removeClass( "show-searchbox" );
    }
  },
  singleRemoveClass: function() {
    $( "#searchform" ).removeClass( "hide-searchbox" );
  }
};

// Data object for the nav "seachbox" menu
var search = {
  bodyClass: "show-mobile-search",
  targetEl: "#searchform",
  hideClass: "hide-searchbox",
  showClass: "show-searchbox",
  removeClassCheck: function() {
    if ( $( "body" ).hasClass( "show-mobile-menu" ) ) {
      $( "body" ).removeClass( "show-mobile-menu" );
      $( "#site-navigation" ).addClass( "hide-menu" ).removeClass( "show-menu" );
    }
  },
  singleRemoveClass: function() {
    $( "#site-navigation" ).removeClass( "hide-menu" );
  }
};

/*
 * CLICK METHODS FOR THE MENU & SEARCH BUTTONS
 * ====================================================================
 *
 * When clicked, each button:
 *
 * 1. runs testBranding() which toggles the #branding elements z-index
 * 2. returns a Promise
 * 3. runs animateNavElement() & the parameter is one of two vars above
 *
 */

// Menu button
$( "#mobile-menu-button" ).click( function(){

  q.fcall( function(){

    var thisTest = testBranding( "z-index: auto;", "z-index: 2;" );
    thisTest();

  }).then( function() {
    animateNavElement( nav );
  });
});

// Search button
$( "#mobile-search-button" ).click( function() {

  q.fcall( function(){

    var thisTest = testBranding( "z-index: 2;", "z-index: auto;");
    thisTest();

  }).then( function() {
    animateNavElement( search );
  });

});

/*
 * I had to write a crazy hack that toggled the z-index of the
 * "#branding" element so the main nav could stack properly and the
 * search box could be focused :-\ To redeem myself for writing a
 * crazy hack, I wrote cool code that executes the hack with a
 * closure. It runs in the "animateNavElement()" element. and the
 * "currentStyle" and "newStyle" parameters are the z-index styles
 * that get toggled.
 */
function testBranding( currentStyle, newStyle ) {

  // Store the toggled states in variables
  var isBrandingClass = $( "#branding" ).attr( "style", currentStyle ),
      isNotBrandingClass = $( "#branding" ).attr( "style", newStyle );

  // An inner function toggles the states with a ternary function check
  function getBrandingClass() {
    isBrandingClass ? isNotBrandingClass : isBrandingClass;
  }

  // Return the inner function so it's accessible when called
  return getBrandingClass;
}

/*
 * "animateNavElement()": show/hide nav & search
 * ====================================================================
 */

 // "obj" will be either the "nav" or "search" variable defined up top
function animateNavElement( obj ) {

  /*
   * Get the "bodyClass" property from the given object. If it's on
   * the <body> tag, it means the given element, the nav or the
   * searchbox, is currently in view. Then do stuff if it exists.
   */
  if( $( "body" ).hasClass( obj.bodyClass ) ) {

    // Enclose some code that returns a Promise
    q.fcall( function() {

      /*
       * Get the both "targetEl" and "hideClass" properties from the
       * given object. "targetEl" is the element being looked at...the
       * nav or the searchbox. "hideClass" is the class that hides the
       * element from view....so remove the element adding a class to
       * the <body> tag that hides it. Adding this class to the
       * element also defines its state.
       */
      $( obj.targetEl ).addClass( obj.hideClass );

      // Reset the element's state by removing whatever "bodyClass" is
      $( "body" ).removeClass( obj.bodyClass );

      /*
       * Wait 3 milliseconds after the Promise resolves, but before
       * doing stuff
       */
      return q.delay( 300 );
    }).then( function(){

      /*
       * Remove the class that hid the target element, the nav or the
       * searchbox. Also, grab the "showClass" property from the given
       * object, which is a class that element visible initially and is
       * DEFINETLY attached it at this point. Remove it as well.
       */
      $( obj.targetEl ).removeClass( obj.hideClass ).removeClass( obj.showClass );
    });
  } else {

    // Enclose some code that returns a Promise
    q.fcall( function(){

      /*
       * The opposite element MIGHT be visible now so run the
       * "removeClassCheck()" method for the given object to remove it.
       * So if the "nav" element is what's currently being focused
       * on, check to see if the "search" element is visible and
       * remove it if it is.
       */
      obj.removeClassCheck();

    // Do stuff after the Promise resolves
    }).then(function(){

      // Add a class to the element making it visible, state is defined
      $( obj.targetEl ).addClass( obj.showClass );

      /*
       * Add a class to <body> that help define the state of the
       * element, saying it's visible.
       */
      $( "body" ).addClass( obj.bodyClass );

      /*
       * The "removeClassCheck()" in the Promise-enclosed code
       * block added a class to the opposite element to help hide it.
       * Remove that class.
       */
      obj.singleRemoveClass();
    });
  }
}<|endoftext|>


<commit_before>'use strict';

const httpStatus = require('http-status-codes');
const yieldable = require('abacus-yieldable');

const carryOverDb = require('../../utils/carry-over-db');
const serviceMock = require('../..//utils/service-mock-util');
const wait = require('../../utils/wait');

const waitUntil = yieldable(wait.until);

let fixture;
let createUnhandleableEvents;

const build = () => {

  context('when reading unhandleable events from Cloud Controller', () => {
    let externalSystemsMocks;
    let unhandleableEvents;

    before(yieldable.functioncb(function *() {
      externalSystemsMocks = fixture.externalSystemsMocks();
      externalSystemsMocks.startAll();

      externalSystemsMocks
        .uaaServer
        .tokenService
        .whenScopesAre(fixture.oauth.abacusCollectorScopes)
        .return(fixture.oauth.abacusCollectorToken);

      externalSystemsMocks
        .uaaServer
        .tokenService
        .whenScopesAre(fixture.oauth.cfAdminScopes)
        .return(fixture.oauth.cfAdminToken);

      unhandleableEvents = createUnhandleableEvents(fixture);
      externalSystemsMocks
        .cloudController
        .usageEvents
        .return
        .firstTime(unhandleableEvents);

      externalSystemsMocks
        .abacusCollector
        .collectUsageService
        .return
        .always(httpStatus.CREATED);

      yield carryOverDb.setup();
      fixture.bridge.start(externalSystemsMocks);

      yield waitUntil(
        serviceMock(
          externalSystemsMocks.cloudController.usageEvents
        ).received(2));
    }));

    after((done) => {
      fixture.bridge.stop();
      carryOverDb.teardown();
      externalSystemsMocks.stopAll(done);
    });

    it('Abacus collector does not receive any usage', () => {
      expect(
        externalSystemsMocks
          .abacusCollector
          .collectUsageService
          .requests()
          .length
      ).to.equal(0);
    });

    it('Does not write an entry in carry over',
      yieldable.functioncb(function *() {
        const docs = yield carryOverDb.readCurrentMonthDocs();
        expect(docs).to.deep.equal([]);
      }));

    it('Exposes correct statistics', yieldable.functioncb(function *() {
      const response = yield fixture.bridge.readStats.withValidToken();
      expect(response.statusCode).to.equal(httpStatus.OK);
      expect(response.body.statistics.usage).to.deep.equal({
        success : {
          all: unhandleableEvents.length,
          conflicts: 0,
          skips: unhandleableEvents.length
        },
        failures : 0
      });
    }));
  });

};

const testDef = {
  fixture: (value) => {
    fixture = value;
    return testDef;
  },
  unhandleableEvents: (value) => {
    createUnhandleableEvents = value;
    return testDef;
  },
  build
};

module.exports = testDef;
<commit_msg>Remove redundant slash in ITests (#825)<commit_after>'use strict';

const httpStatus = require('http-status-codes');
const yieldable = require('abacus-yieldable');

const carryOverDb = require('../../utils/carry-over-db');
const serviceMock = require('../../utils/service-mock-util');
const wait = require('../../utils/wait');

const waitUntil = yieldable(wait.until);

let fixture;
let createUnhandleableEvents;

const build = () => {

  context('when reading unhandleable events from Cloud Controller', () => {
    let externalSystemsMocks;
    let unhandleableEvents;

    before(yieldable.functioncb(function *() {
      externalSystemsMocks = fixture.externalSystemsMocks();
      externalSystemsMocks.startAll();

      externalSystemsMocks
        .uaaServer
        .tokenService
        .whenScopesAre(fixture.oauth.abacusCollectorScopes)
        .return(fixture.oauth.abacusCollectorToken);

      externalSystemsMocks
        .uaaServer
        .tokenService
        .whenScopesAre(fixture.oauth.cfAdminScopes)
        .return(fixture.oauth.cfAdminToken);

      unhandleableEvents = createUnhandleableEvents(fixture);
      externalSystemsMocks
        .cloudController
        .usageEvents
        .return
        .firstTime(unhandleableEvents);

      externalSystemsMocks
        .abacusCollector
        .collectUsageService
        .return
        .always(httpStatus.CREATED);

      yield carryOverDb.setup();
      fixture.bridge.start(externalSystemsMocks);

      yield waitUntil(
        serviceMock(
          externalSystemsMocks.cloudController.usageEvents
        ).received(2));
    }));

    after((done) => {
      fixture.bridge.stop();
      carryOverDb.teardown();
      externalSystemsMocks.stopAll(done);
    });

    it('Abacus collector does not receive any usage', () => {
      expect(
        externalSystemsMocks
          .abacusCollector
          .collectUsageService
          .requests()
          .length
      ).to.equal(0);
    });

    it('Does not write an entry in carry over',
      yieldable.functioncb(function *() {
        const docs = yield carryOverDb.readCurrentMonthDocs();
        expect(docs).to.deep.equal([]);
      }));

    it('Exposes correct statistics', yieldable.functioncb(function *() {
      const response = yield fixture.bridge.readStats.withValidToken();
      expect(response.statusCode).to.equal(httpStatus.OK);
      expect(response.body.statistics.usage).to.deep.equal({
        success : {
          all: unhandleableEvents.length,
          conflicts: 0,
          skips: unhandleableEvents.length
        },
        failures : 0
      });
    }));
  });

};

const testDef = {
  fixture: (value) => {
    fixture = value;
    return testDef;
  },
  unhandleableEvents: (value) => {
    createUnhandleableEvents = value;
    return testDef;
  },
  build
};

module.exports = testDef;
<|endoftext|>


<commit_before>$('document').ready(function() {
	require(['composer', 'composer/controls'], function(composer, controls) {
		composer.addButton('fa fa-strikethrough', function(textarea, selectionStart, selectionEnd) {
			if(selectionStart === selectionEnd){
				controls.insertIntoTextarea(textarea, '~~Insert Text Here~~');
				controls.updateTextareaSelection(textarea, selectionStart + 2, selectionEnd + 18);
			} else {
				controls.wrapSelectionInTextareaWith(textarea, '~~','~~');
				controls.updateTextareaSelection(textarea, selectionStart + 2, selectionEnd + 2);
			}
		});
		composer.addButton('fa fa-code', function(textarea, selectionStart, selectionEnd) {
			if(selectionStart === selectionEnd){
				controls.insertIntoTextarea(textarea, '```\nInsert Code Here\n```');
				controls.updateTextareaSelection(textarea, selectionStart + 4, selectionEnd + 21);
			} else {
				controls.wrapSelectionInTextareaWith(textarea, '```\n','\n```\n');
				controls.updateTextareaSelection(textarea, selectionStart + 4, selectionEnd + 4);
			}
		});
		composer.addButton('fa fa-quote-right', function(textarea, selectionStart, selectionEnd) {
			if(selectionStart === selectionEnd){
				controls.insertIntoTextarea(textarea, '@Username / Website said:\n> \n\n\n');
				controls.updateTextareaSelection(textarea, selectionStart + 28, selectionEnd + 28);
			} else {
				controls.wrapSelectionInTextareaWith(textarea, '@Username / Website said:\n> ','\n\n\n');
				controls.updateTextareaSelection(textarea, selectionStart + 28, selectionEnd + 28);
			}
		});

	});
});
<commit_msg>Update buttons.js<commit_after>$('document').ready(function() {
	require(['composer', 'composer/controls'], function(composer, controls) {
		composer.addButton('fa fa-strikethrough', function(textarea, selectionStart, selectionEnd) {
			if(selectionStart === selectionEnd){
				controls.insertIntoTextarea(textarea, '~~Insert Text Here~~');
				controls.updateTextareaSelection(textarea, selectionStart + 2, selectionEnd + 18);
			} else {
				controls.wrapSelectionInTextareaWith(textarea, '~~','~~');
				controls.updateTextareaSelection(textarea, selectionStart + 2, selectionEnd + 2);
			}
		});
		composer.addButton('fa fa-code', function(textarea, selectionStart, selectionEnd) {
			if(selectionStart === selectionEnd){
				controls.insertIntoTextarea(textarea, '```\nInsert Code Here\n```');
				controls.updateTextareaSelection(textarea, selectionStart + 4, selectionEnd + 21);
			} else {
				controls.wrapSelectionInTextareaWith(textarea, '```\n','\n```\n');
				controls.updateTextareaSelection(textarea, selectionStart + 4, selectionEnd + 4);
			}
		});
		composer.addButton('fa fa-quote-right', function(textarea, selectionStart, selectionEnd) {
			if(selectionStart === selectionEnd){
				controls.insertIntoTextarea(textarea, '@Username / Website said:\n> ');
				controls.updateTextareaSelection(textarea, selectionStart + 28, selectionEnd + 28);
			} else {
				controls.wrapSelectionInTextareaWith(textarea, '@Username / Website said:\n> ','\n\n');
			}
		});

	});
});
<|endoftext|>