<commit_before>var config = require('../config');

var express = require('express');
var _ = require('lodash');
var request = require('request');
var fs = require('fs');
var xml2js = require('xml2js');

var async = require('async')

var router = express.Router();

var MongoClient = require('mongodb').MongoClient
var mongo_url = config.mongo + config.db;

require('../models/reactions.js');
require('../models/definition.js');
require('../models/votes.js');

// TO DO: GET list of reactions
router.get('/', function(req, res, next) {
  var example = ["UTERINE HAEMORRHAGE","BLOOD CULTURE POSITIVE","CONVULSION","DEPRESSED LEVEL OF CONSCIOUSNESS","ELECTROENCEPHALOGRAM ABNORMAL","FUNGAL INFECTION","HYPOTENSION","HYPOXIA","MENTAL STATUS CHANGES","MULTI-ORGAN FAILURE","PANCREATITIS","SEPSIS","SPUTUM CULTURE POSITIVE","BRADYCARDIA","EMBOLISM","ILEUS PARALYTIC","INTESTINAL ISCHAEMIA","OXYGEN SATURATION DECREASED","RENAL FAILURE ACUTE","RENAL TUBULAR NECROSIS","AIDS ENCEPHALOPATHY"];
  res.json(example);
});

// TO DO: Post new or update reaction definition
router.post('/', function(req, res, next) {
  // Validate that incoming request is ok... and not a duplicate
  //res.json({todo: 'post reaction definition'});
  var reaction = new Reaction();

  if(Object.keys(req.body).length != 1 ||
     req.body.reaction == null ||
     typeof req.body.reaction != "string") {
    var err = new Error();
    err.status = 400;
    err.error = "Invalid Request Body";
    err.message = "Either the incorrect number of attributes were provided or" +
                  " the 'reaction' attribute could not be found, or the" +
                  " 'reaction' attribute wasn't properly formatted.";
    next(err);
  }

  // Tries to find reaction in collection (returns the record if found)
  var findReaction = function(db, callback) {
    var collection = db.collection('reactions');
    collection.findOne({'reaction': req.body.reaction}, function(err, reaction) {
      callback(reaction);
    });
  }

  // Inserts reaction into Mongo
  var insertReaction = function(db, callback) {
    var collection = db.collection('reactions');
      collection.insert([
        reaction
      ], function(err, result) {

        callback(result);
      });

  }

  // Retrieves definition available from Merriam Webster Medical Dictionary API
  var getTermDefinitionFromMerriamWebsterMedical = function (callback) {

    var url = "http://www.dictionaryapi.com/api/v1/references/medical/xml/" + encodeURIComponent(reaction.reaction.toLowerCase()) + "?key=" + config.dictionaryapi_key;

    request(url, function (error, response, body) {

      if (!error && response.statusCode == 200) {

        var parser = new xml2js.Parser({ignoreAttrs: false});

        parser.parseString(body, function (err, result) {

          if (result) {

          _.forEach(result.entry_list.entry, function(v,k) {

            if (v['$'].id == reaction.reaction.toLowerCase()) {

                if (v.def) {

                  if (Array.isArray(v.def[0].sensb[0].sens)) {

                      _.forEach(v.def[0].sensb, function (v,k) {

                        if (v.sens[0].dt[0]['_']) {

                          if (typeof v.sens[0].dt[0]['_'] == "string") {

                            var definition = new Definition;
                            var dt = new Date();

                            definition.definition = v.sens[0].dt[0]['_'];
                            definition.source = 'dictionaryapi.com';
                            definition.created_at = dt.getTime();
                            definition.created_by = "";
                            definition.votes = new Votes();

                            reaction.addDefinition(definition);

                          }

                        } else {
                          var def = {};
                          if (typeof v.sens[0].dt[0] == "string") {

                            var definition = new Definition;
                            var dt = new Date();

                            definition.definition = v.sens[0].dt[0];
                            definition.source = 'dictionaryapi.com';
                            definition.created_at = dt.getTime();
                            definition.created_by = "";
                            definition.votes = new Votes();
                            reaction.addDefinition(definition);

                          }

                        }

                      });

                    } else {

                      if (typeof v.def[0].sensb[0].sens[0].dt == "string") {

                        var definition = new Definition;
                        var dt = new Date();

                        definition.definition = v.def[0].sensb[0].sens[0].dt;
                        definition.source = 'dictionaryapi.com';
                        definition.created_at = dt.getTime();
                        definition.created_by = "";
                        definition.votes = new Votes();
                        reaction.addDefinition(definition);

                      }

                      }

                    }

                }
            });
            }

          });

          callback(null);

      } else {
        callback(null);
      }
    })
  }

  // Retrieves definition available from Wordnik API
  var getDefinitionFromWordnik = function (callback) {
    var url = "http://api.wordnik.com:80/v4/word.json/" + encodeURIComponent(reaction.reaction.toLowerCase()) + "/definitions?limit=200&includeRelated=true&useCanonical=false&includeTags=false&api_key=" + config.wordnikapi_key ;

    request(url, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        var deflist = JSON.parse(body);
        if (deflist[0]) {
          _.forEach(deflist, function(v,k) {

            var definition = new Definition;

            if (v.partOfSpeech == "noun") {
              var dt = new Date();

              definition.definition = v.text;
              definition.source = 'wordnik.com';
              definition.created_at = dt.getTime();
              definition.created_by = "";
              definition.votes = new Votes();

              reaction.addDefinition(definition);
            }

          });

        }
       callback();

      } else {
        callback();
      }
    })

  }

  // - Establish connection to mongo
  // - Check to see if reaction exists
  // - If it does not exist, find definitions and insert

  MongoClient.connect(mongo_url, function(err, db) {

    if (err) {
      var err = new Error();
      err.status = 500;
      err.error = "Internal Error";
      next(err);
    }

    if (!err) {

      findReaction(db, function(result) {

        if(result) {
          var err = new Error();
          err.status = 400;
          err.error = "Duplicate Reaction";
          err.message = "The reaction that you are trying to create already exists" +
                        " and cannot be created again.";

          next(err);
        } else {

          var dt = new Date();

          reaction.reaction = req.body.reaction;
          reaction.definitions = [];
          reaction.created_at = dt.getTime();
          reaction.created_by = "";

          async.series([
              function(callback){
                getTermDefinitionFromMerriamWebsterMedical(function (result) {
                  callback(null);
                });
              },
              function(callback){
                getDefinitionFromWordnik(function (result) {
                  callback(null);
                });
              }
          ],

          // insert into mongo
          function(err, results){

            insertReaction(db, function(result) {

                res.json(reaction);

            });

          });

        }
     });

    }

 });

});

// TO DO: Get reaction defintion
router.get('/:id', function(req, res, next) {
  MongoClient.connect(mongo_url, function(err, db) {

    // Tries to find reaction in collection (returns the record if found)
    var findReaction = function(term, db, callback) {
      var collection = db.collection('reactions');
      collection.findOne({'reaction': term.toLowerCase()}, function(err, reaction) {
        callback(reaction);
      });
    };

    if(req.params.id == null || typeof req.params.id == "object") {
      var err = new Error();
      err.status = 500;
      err.error = "Unknown Server Error";
      err.message = "Please retry your request again or contact us if the"
                    + " problem persists";
      next(err);
    }
    findReaction(req.params.id, db, function(result) {
      if(result === null) {
        var err = new Error();
        err.status = 404;
        err.error = "Reaction Not Found";
        err.message = "The reaction that you were looking for could not be found.";
        next(err);
      } else {
        res.json(result);
      }
    });
  });
});

// TO DO: Put reaction defintion
router.put('/:id', function(req, res, next) {
  var id = req.params.id;
  var example = JSON.parse('{"reaction":"' + id + '","terms":[{"term":"urosepsis","text":"sepsis caused by bacteria from the urinary tract invading the bloodstream","attributionText":"from Wiktionary, Creative Commons Attribution/Share-Alike License","source":"wordnik"},{"term":"urosepsis","text":"sepsis caused by bacteria from the urinary tract invading the bloodstream","attributionText":"from Wiktionary, Creative Commons Attribution/Share-Alike License","source":"wordnik"}]}');
  res.json(example);
});

// TO DO: Delete reaction definition
router.delete('/:id', function(req, res, next) {
  res.json({todo: 'delete reaction definition ' +  req.params.id});
});

module.exports = router;
<commit_msg>fixed db close issue - added db close to reaction get endpoint<commit_after>var config = require('../config');

var express = require('express');
var _ = require('lodash');
var request = require('request');
var fs = require('fs');
var xml2js = require('xml2js');

var async = require('async')

var router = express.Router();

var MongoClient = require('mongodb').MongoClient
var mongo_url = config.mongo + config.db;

var db = {};

require('../models/reactions.js');
require('../models/definition.js');
require('../models/votes.js');

// TO DO: GET list of reactions
router.get('/', function(req, res, next) {
  var example = ["UTERINE HAEMORRHAGE","BLOOD CULTURE POSITIVE","CONVULSION","DEPRESSED LEVEL OF CONSCIOUSNESS","ELECTROENCEPHALOGRAM ABNORMAL","FUNGAL INFECTION","HYPOTENSION","HYPOXIA","MENTAL STATUS CHANGES","MULTI-ORGAN FAILURE","PANCREATITIS","SEPSIS","SPUTUM CULTURE POSITIVE","BRADYCARDIA","EMBOLISM","ILEUS PARALYTIC","INTESTINAL ISCHAEMIA","OXYGEN SATURATION DECREASED","RENAL FAILURE ACUTE","RENAL TUBULAR NECROSIS","AIDS ENCEPHALOPATHY"];
  res.json(example);
});

// TO DO: Post new or update reaction definition
router.post('/', function(req, res, next) {
  // Validate that incoming request is ok... and not a duplicate
  //res.json({todo: 'post reaction definition'});
  var reaction = new Reaction();

  if(Object.keys(req.body).length != 1 ||
     req.body.reaction == null ||
     typeof req.body.reaction != "string") {
    var err = new Error();
    err.status = 400;
    err.error = "Invalid Request Body";
    err.message = "Either the incorrect number of attributes were provided or" +
                  " the 'reaction' attribute could not be found, or the" +
                  " 'reaction' attribute wasn't properly formatted.";
    next(err);
  }

  // Tries to find reaction in collection (returns the record if found)
  var findReaction = function(db, callback) {
    var collection = db.collection('reactions');
    collection.findOne({'reaction': req.body.reaction}, function(err, reaction) {
      callback(reaction);
    });
  }

  // Inserts reaction into Mongo
  var insertReaction = function(db, callback) {
    var collection = db.collection('reactions');

      collection.insert([
        reaction
      ], function(err, result) {
        db.close();
        callback(result);

      });
  }

  // Retrieves definition available from Merriam Webster Medical Dictionary API
  var getTermDefinitionFromMerriamWebsterMedical = function (callback) {

    var url = "http://www.dictionaryapi.com/api/v1/references/medical/xml/" + encodeURIComponent(reaction.reaction.toLowerCase()) + "?key=" + config.dictionaryapi_key;

    request(url, function (error, response, body) {

      if (!error && response.statusCode == 200) {

        var parser = new xml2js.Parser({ignoreAttrs: false});

        parser.parseString(body, function (err, result) {

          if (result) {

          _.forEach(result.entry_list.entry, function(v,k) {

            if (v['$'].id == reaction.reaction.toLowerCase()) {

                if (v.def) {

                  if (Array.isArray(v.def[0].sensb[0].sens)) {

                      _.forEach(v.def[0].sensb, function (v,k) {

                        if (v.sens[0].dt[0]['_']) {

                          if (typeof v.sens[0].dt[0]['_'] == "string") {

                            var definition = new Definition;
                            var dt = new Date();

                            definition.definition = v.sens[0].dt[0]['_'];
                            definition.source = 'dictionaryapi.com';
                            definition.created_at = dt.getTime();
                            definition.created_by = "";
                            definition.votes = new Votes();

                            reaction.addDefinition(definition);

                          }

                        } else {
                          var def = {};
                          if (typeof v.sens[0].dt[0] == "string") {

                            var definition = new Definition;
                            var dt = new Date();

                            definition.definition = v.sens[0].dt[0];
                            definition.source = 'dictionaryapi.com';
                            definition.created_at = dt.getTime();
                            definition.created_by = "";
                            definition.votes = new Votes();
                            reaction.addDefinition(definition);

                          }

                        }

                      });

                    } else {

                      if (typeof v.def[0].sensb[0].sens[0].dt == "string") {

                        var definition = new Definition;
                        var dt = new Date();

                        definition.definition = v.def[0].sensb[0].sens[0].dt;
                        definition.source = 'dictionaryapi.com';
                        definition.created_at = dt.getTime();
                        definition.created_by = "";
                        definition.votes = new Votes();
                        reaction.addDefinition(definition);

                      }

                      }

                    }

                }
            });
            }

          });

          callback(null);

      } else {
        callback(null);
      }
    })
  }

  // Retrieves definition available from Wordnik API
  var getDefinitionFromWordnik = function (callback) {
    var url = "http://api.wordnik.com:80/v4/word.json/" + encodeURIComponent(reaction.reaction.toLowerCase()) + "/definitions?limit=200&includeRelated=true&useCanonical=false&includeTags=false&api_key=" + config.wordnikapi_key ;

    request(url, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        var deflist = JSON.parse(body);
        if (deflist[0]) {
          _.forEach(deflist, function(v,k) {

            var definition = new Definition;

            if (v.partOfSpeech == "noun") {
              var dt = new Date();

              definition.definition = v.text;
              definition.source = 'wordnik.com';
              definition.created_at = dt.getTime();
              definition.created_by = "";
              definition.votes = new Votes();

              reaction.addDefinition(definition);
            }

          });

        }
       callback();

      } else {
        callback();
      }
    })

  }

  // - Establish connection to mongo
  // - Check to see if reaction exists
  // - If it does not exist, find definitions and insert

  MongoClient.connect(mongo_url, function(err, db) {

    if (err) {
      var err = new Error();
      err.status = 500;
      err.error = "Internal Error";
      next(err);
    }

    if (!err) {

      findReaction(db, function(result) {

        if(result) {

          var err = new Error();
          err.status = 400;
          err.error = "Duplicate Reaction";
          err.message = "The reaction that you are trying to create already exists" +
                        " and cannot be created again.";
          db.close();
          next(err);
        } else {

          var dt = new Date();

          reaction.reaction = req.body.reaction;
          reaction.definitions = [];
          reaction.created_at = dt.getTime();
          reaction.created_by = "";

          async.series([
              function(callback){
                getTermDefinitionFromMerriamWebsterMedical(function (result) {
                  callback(null);
                });
              },
              function(callback){
                getDefinitionFromWordnik(function (result) {
                  callback(null);
                });
              }
          ],

          // insert into mongo
          function(err, results){

            insertReaction(db, function(result) {

                res.json(reaction);

            });

          });

        }
     });

    }

 });

});

// TO DO: Get reaction defintion
router.get('/:id', function(req, res, next) {
  MongoClient.connect(mongo_url, function(err, db) {

    // Tries to find reaction in collection (returns the record if found)
    var findReaction = function(term, db, callback) {
      var collection = db.collection('reactions');
      collection.findOne({'reaction': term.toLowerCase()}, function(err, reaction) {

        callback(reaction);
      });
    };

    if(req.params.id == null || typeof req.params.id == "object") {
      var err = new Error();
      err.status = 500;
      err.error = "Unknown Server Error";
      err.message = "Please retry your request again or contact us if the"
                    + " problem persists";
      next(err);
    }

    findReaction(req.params.id, db, function(result) {
      if(result === null) {
        var err = new Error();
        err.status = 404;
        err.error = "Reaction Not Found";
        err.message = "The reaction that you were looking for could not be found.";
        next(err);
      } else {
        res.json(result);
      }
    });
  });
});

// TO DO: Put reaction defintion
router.put('/:id', function(req, res, next) {
  var id = req.params.id;
  var example = JSON.parse('{"reaction":"' + id + '","terms":[{"term":"urosepsis","text":"sepsis caused by bacteria from the urinary tract invading the bloodstream","attributionText":"from Wiktionary, Creative Commons Attribution/Share-Alike License","source":"wordnik"},{"term":"urosepsis","text":"sepsis caused by bacteria from the urinary tract invading the bloodstream","attributionText":"from Wiktionary, Creative Commons Attribution/Share-Alike License","source":"wordnik"}]}');
  res.json(example);
});

// TO DO: Delete reaction definition
router.delete('/:id', function(req, res, next) {
  res.json({todo: 'delete reaction definition ' +  req.params.id});
});

module.exports = router;
<|endoftext|>


<commit_before>define(function (require) {
    'use strict';

    var shapes = require('shapes'),

        serializer = {
            serializePosition: function (obj, array, offset, scale) {
                var origin      = obj.position;
                array[offset]   = origin.x / scale;
                array[offset + 1] = origin.y / scale;
                array[offset + 2] = origin.z / scale;

                return offset + 3;
            },
            serializeRotation: function (obj, array, offset) {
                var rotation    = obj.quaternion;
                array[offset]   = rotation.x;
                array[offset + 1] = rotation.y;
                array[offset + 2] = rotation.z;
                array[offset + 3] = rotation.w;

                return offset + 4;
            },
            mesh: function (mesh, scale) {

                // serialize the mesh params to pass them to the
                // physics worker.

                var offset = 0,
                    object = [];

                offset = this.serializePosition(mesh, object, offset, scale);
                offset = this.serializeRotation(mesh, object, offset);
                offset = this.serializeGeometry(mesh, object, offset, scale);
                offset = this.serializeUserData(mesh, object, offset);

                object[offset] = mesh.userData.mass !== undefined ? mesh.userData.mass : 1;

                return object;
            },
            serializeGeometry: function (obj, array, offset, scale) {

                var type = obj.geometry.type;

                if (undefined !== type) {
                    offset = this.serializeGeometryType(obj, array, offset);
                    offset = this["serialize" + type](obj, array, offset, scale);
                } else {
                    console.error("Object type is undefined");
                }

                return offset;
            },
            serializeBoxGeometry: function (obj, array, offset, scale) {
                var size        = obj.geometry.parameters;
                var half = 0.5;
                array[offset]     = size.width * obj.scale.x / scale * half;
                array[offset + 1] = size.height * obj.scale.y / scale * half;
                array[offset + 2] = size.depth * obj.scale.z / scale * half;

                return offset + 3;
            },
            serializeSphereGeometry: function (obj, array, offset, scale) {
                var radius        = obj.geometry.parameters.radius;
                array[offset] = radius / scale;

                return offset + 1;
            },
            serializeGeometryType: function (obj, array, offset) {
                array[offset] = obj.geometry.type;
                return offset + 1;
            },
            serializeUserData: function (obj, array, offset) {
                var data = obj.userData;
                array[offset] = data.mass !== undefined ? data.mass : 1;

                return offset + 1;
            },
            applyData: function (data, offset, array, scale) {
                var i, body;
                for (i = 0; i < array.length; i++) {
                    body = array[i];

                    body.position.x = data[offset] * scale;
                    body.position.y = data[offset + 1] * scale;
                    body.position.z = data[offset + 2] * scale;

                    body.quaternion.x = data[offset + 3];
                    body.quaternion.y = data[offset + 4];
                    body.quaternion.z = data[offset + 5];
                    body.quaternion.w = data[offset + 6];

                    offset += 7;
                }

                return offset;
            }
        };

    return serializer;
});<commit_msg>hotfix<commit_after>define(function (require) {
    'use strict';

    var serializer = {
            serializePosition: function (obj, array, offset, scale) {
                var origin      = obj.position;
                array[offset]   = origin.x / scale;
                array[offset + 1] = origin.y / scale;
                array[offset + 2] = origin.z / scale;

                return offset + 3;
            },
            serializeRotation: function (obj, array, offset) {
                var rotation    = obj.quaternion;
                array[offset]   = rotation.x;
                array[offset + 1] = rotation.y;
                array[offset + 2] = rotation.z;
                array[offset + 3] = rotation.w;

                return offset + 4;
            },
            mesh: function (mesh, scale) {

                // serialize the mesh params to pass them to the
                // physics worker.

                var offset = 0,
                    object = [];

                offset = this.serializePosition(mesh, object, offset, scale);
                offset = this.serializeRotation(mesh, object, offset);
                offset = this.serializeGeometry(mesh, object, offset, scale);
                offset = this.serializeUserData(mesh, object, offset);

                object[offset] = mesh.userData.mass !== undefined ? mesh.userData.mass : 1;

                return object;
            },
            serializeGeometry: function (obj, array, offset, scale) {

                var type = obj.geometry.type;

                if (undefined !== type) {
                    offset = this.serializeGeometryType(obj, array, offset);
                    offset = this["serialize" + type](obj, array, offset, scale);
                } else {
                    console.error("Object type is undefined");
                }

                return offset;
            },
            serializeBoxGeometry: function (obj, array, offset, scale) {
                var size        = obj.geometry.parameters;
                var half = 0.5;
                array[offset]     = size.width * obj.scale.x / scale * half;
                array[offset + 1] = size.height * obj.scale.y / scale * half;
                array[offset + 2] = size.depth * obj.scale.z / scale * half;

                return offset + 3;
            },
            serializeSphereGeometry: function (obj, array, offset, scale) {
                var radius        = obj.geometry.parameters.radius;
                array[offset] = radius / scale;

                return offset + 1;
            },
            serializeGeometryType: function (obj, array, offset) {
                array[offset] = obj.geometry.type;
                return offset + 1;
            },
            serializeUserData: function (obj, array, offset) {
                var data = obj.userData;
                array[offset] = data.mass !== undefined ? data.mass : 1;

                return offset + 1;
            },
            applyData: function (data, offset, array, scale) {
                var i, body;
                for (i = 0; i < array.length; i++) {
                    body = array[i];

                    body.position.x = data[offset] * scale;
                    body.position.y = data[offset + 1] * scale;
                    body.position.z = data[offset + 2] * scale;

                    body.quaternion.x = data[offset + 3];
                    body.quaternion.y = data[offset + 4];
                    body.quaternion.z = data[offset + 5];
                    body.quaternion.w = data[offset + 6];

                    offset += 7;
                }

                return offset;
            }
        };

    return serializer;
});<|endoftext|>


<commit_before>/* eslint-disable new-cap */
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';
import { settingsLive, packages } from './collections';
import defaultSettings from './defaultSettings';
import { checkSiteIdOwnership, checkUserLoggedIn, purgeSite } from '../utils';

const addSettings = ({ name, namespace, siteId }) => {
  check(name, String);
  check(namespace, Match.OneOf(String, undefined));
  check(siteId, String);

  return settingsLive.findOne({
    'woronaInfo.name': name,
    'woronaInfo.siteId': siteId,
  })
    ? false
    : settingsLive.insert({
        woronaInfo: {
          name,
          namespace,
          siteId,
          active: true,
          init: false,
        },
      });
};

Meteor.methods({
  activatePackage({ name, siteId }) {
    const userId = this.userId;
    checkSiteIdOwnership(siteId, userId);

    const settings = settingsLive.findOne(
      {
        'woronaInfo.name': name,
        'woronaInfo.siteId': siteId,
      },
      { fields: { _id: 1 } },
    );

    if (settings) {
      // Check if other package with the same namespace is activated.
      const newPkg = packages.findOne({ name });
      if (newPkg.app && newPkg.app.namespace) {
        const oldPkgs = packages
          .find({ name: { $ne: name }, 'app.namespace': newPkg.app.namespace })
          .fetch();
        for (const oldPkg of oldPkgs) {
          const oldSettings = settingsLive.findOne(
            {
              'woronaInfo.name': oldPkg.name,
              'woronaInfo.siteId': siteId,
            },
            { fields: { 'woronaInfo.active': 1 } },
          );
          if (oldSettings.woronaInfo.active === true) {
            Meteor.call('deactivatePackage', { name: oldPkg.name, siteId });
          }
        }
      }
      settingsLive.update(settings._id, { $set: { 'woronaInfo.active': true } });
    } else {
      addSettings({ name, siteId });
    }
  },

  deactivatePackage({ name, siteId }) {
    const userId = this.userId;
    checkSiteIdOwnership(siteId, userId);

    const settings = settingsLive.findOne(
      {
        'woronaInfo.name': name,
        'woronaInfo.siteId': siteId,
      },
      { fields: { _id: 1 } },
    );

    if (settings) {
      settingsLive.update(settings._id, { $set: { 'woronaInfo.active': false } });
      return true;
    }
    return new Meteor.Error('Trying to deactivate non-existing package.');
  },

  saveSettings(settings) {
    const userId = this.userId;
    const name = settings.woronaInfo.name;
    const siteId = settings.woronaInfo.siteId;

    check(name, String);
    check(siteId, String);
    checkUserLoggedIn(userId);
    checkSiteIdOwnership(siteId, userId);

    const newSettingData = {};
    Object.assign(newSettingData, settings);
    delete newSettingData.woronaInfo;
    newSettingData['woronaInfo.init'] = true;

    const id = settingsLive.findOne({
      'woronaInfo.name': name,
      'woronaInfo.siteId': siteId,
    })._id;

    purgeSite(siteId);

    return settingsLive.update(id, { $set: newSettingData });
  },

  addSettings(options) {
    return addSettings(options);
  },

  addDefaultSettings(siteId) {
    defaultSettings.forEach(pkg => {
      addSettings({ name: pkg.name, namespace: pkg.namespace, siteId });
    });
  },
});
<commit_msg>Add setting if saving and settings not found.<commit_after>/* eslint-disable new-cap */
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';
import { settingsLive, packages } from './collections';
import defaultSettings from './defaultSettings';
import { checkSiteIdOwnership, checkUserLoggedIn, purgeSite } from '../utils';

const addSettings = ({ name, namespace, siteId }) => {
  check(name, String);
  check(namespace, Match.OneOf(String, undefined));
  check(siteId, String);

  return settingsLive.findOne({
    'woronaInfo.name': name,
    'woronaInfo.siteId': siteId,
  })
    ? false
    : settingsLive.insert({
        woronaInfo: {
          name,
          namespace,
          siteId,
          active: true,
          init: false,
        },
      });
};

Meteor.methods({
  activatePackage({ name, siteId }) {
    const userId = this.userId;
    checkSiteIdOwnership(siteId, userId);

    const settings = settingsLive.findOne(
      {
        'woronaInfo.name': name,
        'woronaInfo.siteId': siteId,
      },
      { fields: { _id: 1 } },
    );

    if (settings) {
      // Check if other package with the same namespace is activated.
      const newPkg = packages.findOne({ name });
      if (newPkg.app && newPkg.app.namespace) {
        const oldPkgs = packages
          .find({ name: { $ne: name }, 'app.namespace': newPkg.app.namespace })
          .fetch();
        for (const oldPkg of oldPkgs) {
          const oldSettings = settingsLive.findOne(
            {
              'woronaInfo.name': oldPkg.name,
              'woronaInfo.siteId': siteId,
            },
            { fields: { 'woronaInfo.active': 1 } },
          );
          if (oldSettings.woronaInfo.active === true) {
            Meteor.call('deactivatePackage', { name: oldPkg.name, siteId });
          }
        }
      }
      settingsLive.update(settings._id, { $set: { 'woronaInfo.active': true } });
    } else {
      addSettings({ name, siteId });
    }
  },

  deactivatePackage({ name, siteId }) {
    const userId = this.userId;
    checkSiteIdOwnership(siteId, userId);

    const settings = settingsLive.findOne(
      {
        'woronaInfo.name': name,
        'woronaInfo.siteId': siteId,
      },
      { fields: { _id: 1 } },
    );

    if (settings) {
      settingsLive.update(settings._id, { $set: { 'woronaInfo.active': false } });
      return true;
    }
    return new Meteor.Error('Trying to deactivate non-existing package.');
  },

  saveSettings(settings) {
    const userId = this.userId;
    const name = settings.woronaInfo.name;
    const siteId = settings.woronaInfo.siteId;

    check(name, String);
    check(siteId, String);
    checkUserLoggedIn(userId);
    checkSiteIdOwnership(siteId, userId);

    const newSettingData = {};
    Object.assign(newSettingData, settings);
    delete newSettingData.woronaInfo;
    newSettingData['woronaInfo.init'] = true;

    const previousSettings = settingsLive.findOne({
      'woronaInfo.name': name,
      'woronaInfo.siteId': siteId,
    });

    purgeSite(siteId);

    if (previousSettings) {
      settingsLive.update(previousSettings._id, { $set: newSettingData });
    } else {
      const id = addSettings({ name, siteId });
      settingsLive.update(id, { $set: newSettingData });
    }
  },

  addSettings(options) {
    return addSettings(options);
  },

  addDefaultSettings(siteId) {
    defaultSettings.forEach(pkg => {
      addSettings({ name: pkg.name, namespace: pkg.namespace, siteId });
    });
  },
});
<|endoftext|>


<commit_before>function optionsState() {}

var optionsTitle, testBall, testCollisionGroup, backButton;
var inputSensitivity = 400;

function sensitivityTest() {
  testBall = game.add.sprite(50, 50, 'player');
  testBall.scale.setTo(playerScale, playerScale);
  game.physics.p2.enable(testBall);
  testBall.body.setCollisionGroup(testCollisionGroup);
}

optionsState.prototype = {
  create: function() {
    game.physics.startSystem(Phaser.Physics.P2JS);
    game.physics.p2.setImpactEvents(true);
    game.physics.p2.restitution = 0.95;
    testCollisionGroup = game.physics.p2.createCollisionGroup();
    game.physics.p2.updateBoundsCollisionGroup();

    sensitivityTest();

    // this could be a prefab

    backButton = game.add.sprite(100, game.height - 100, 'back_button');
    backButton.anchor.setTo(0.5,0.5);
    backButton.scale.setTo(0.2,0.2);
    backButton.alpha = 0;
    backButton.inputEnabled = true;
    backButtonAnimation = game.add.tween(backButton).to({alpha: 0.2}, 1000, Phaser.Easing.Quadratic.InOut, true, 2000);

    var optionsTitle = game.add.sprite(centerx, oneThirdHeight, 'sensitivity');
    optionsTitle.anchor.setTo(0.5,0.5);
    optionsTitle.scale.setTo(0.5,0.5);
    optionsTitle.alpha = 0;
    optionsTitleAnimation = game.add.tween(optionsTitle).to({alpha: 1}, 1000, Phaser.Easing.Quadratic.InOut, true);

    var sensitivityOptions = [
      {name: 'sense_high', yOffset: 120},
      {name: 'sense_medium', yOffset: 250},
      {name: 'sense_low', yOffset: 380}
    ];

    var sensitivitySprites = {};

    sensitivityOptions.forEach(
      function(option){
        var sprite = game.add.sprite(optionsTitle.position.x, optionsTitle.position.y + option.yOffset, option.name);
        sprite.anchor.setTo(0.5, 0.5);
        sprite.scale.setTo(0.4);
        sprite.alpha = 0;
        sprite.inputEnabled = true;
        game.add.tween(sprite).to({alpha: 1}, 1000, Phaser.Easing.Quadratic.InOut, true, 1000 );
        sensitivitySprites[option.name] = sprite;
    });

    // have some rotten code here. Will refactor.

    function highSensitivity() {
      inputSensitivity = 500;
      game.add.tween(sensitivitySprites.sense_high.scale).to({x: 0.5, y: 0.5}, 500, Phaser.Easing.Quadratic.InOut, true);
      game.add.tween(sensitivitySprites.sense_medium.scale).to({x: 0.4, y: 0.4}, 500, Phaser.Easing.Quadratic.InOut, true);
      game.add.tween(sensitivitySprites.sense_low.scale).to({x: 0.4, y: 0.4}, 500, Phaser.Easing.Quadratic.InOut, true);
      return;
    }
    function mediumSensitivity() {
      inputSensitivity = 400;
      game.add.tween(sensitivitySprites.sense_high.scale).to({x: 0.4, y: 0.4}, 500, Phaser.Easing.Quadratic.InOut, true);
      game.add.tween(sensitivitySprites.sense_medium.scale).to({x: 0.5, y: 0.5}, 500, Phaser.Easing.Quadratic.InOut, true);
      game.add.tween(sensitivitySprites.sense_low.scale).to({x: 0.4, y: 0.4}, 500, Phaser.Easing.Quadratic.InOut, true);
      return;
    }
    function lowSensitivity() {
      inputSensitivity = 300;
      game.add.tween(sensitivitySprites.sense_high.scale).to({x: 0.4, y: 0.4}, 500, Phaser.Easing.Quadratic.InOut, true);
      game.add.tween(sensitivitySprites.sense_medium.scale).to({x: 0.4, y: 0.4}, 500, Phaser.Easing.Quadratic.InOut, true);
      game.add.tween(sensitivitySprites.sense_low.scale).to({x: 0.5, y: 0.5}, 500, Phaser.Easing.Quadratic.InOut, true);
      return;
    }

    sensitivitySprites.sense_high.events.onInputDown.add(highSensitivity, this);
    sensitivitySprites.sense_medium.events.onInputDown.add(mediumSensitivity, this);
    sensitivitySprites.sense_low.events.onInputDown.add(lowSensitivity, this);

    if (inputSensitivity === 300) {
        sensitivitySprites.sense_low.scale.setTo(0.5,0.5);
    }
    else if (inputSensitivity === 400) {
        sensitivitySprites.sense_medium.scale.setTo(0.5,0.5);
    }
    else {
        sensitivitySprites.sense_high.scale.setTo(0.5,0.5);
    }

    function backToMenu() {
      this.game.state.start('main_menu');
    }

    backButton.events.onInputDown.add(backToMenu, this);

  },

  update: function() {

  ballMovement(testBall, ax, ay, inputSensitivity, cursors);

  }
};

<commit_msg>refactored options menu and removed some global variables<commit_after>function optionsState() {}

function createCollisionGroupAndUpdatePhysics() {
  game.physics.startSystem(Phaser.Physics.P2JS);
  game.physics.p2.setImpactEvents(true);
  game.physics.p2.restitution = 0.95;
  var collisionGroup = game.physics.p2.createCollisionGroup();
  game.physics.p2.updateBoundsCollisionGroup();
  return collisionGroup;
}

function createTestBall(collisionGroup) {
  var ball = game.add.sprite(50, 50, 'player');
  ball.scale.setTo(playerScale, playerScale);
  game.physics.p2.enable(ball);
  ball.body.setCollisionGroup(collisionGroup);
  return ball;
}

optionsState.prototype = {
  create: function() {
   var testCollisionGroup = createCollisionGroupAndUpdatePhysics();
    this.testBall = createTestBall(testCollisionGroup);

    // this could be a prefab

    var backButton = game.add.sprite(100, game.height - 100, 'back_button');
    backButton.anchor.setTo(0.5,0.5);
    backButton.scale.setTo(0.2,0.2);
    backButton.alpha = 0;
    backButton.inputEnabled = true;
    backButtonAnimation = game.add.tween(backButton).to({alpha: 0.2}, 1000, Phaser.Easing.Quadratic.InOut, true, 2000);

    var optionsTitle = game.add.sprite(centerx, oneThirdHeight, 'sensitivity');
    optionsTitle.anchor.setTo(0.5,0.5);
    optionsTitle.scale.setTo(0.5,0.5);
    optionsTitle.alpha = 0;
    optionsTitleAnimation = game.add.tween(optionsTitle).to({alpha: 1}, 1000, Phaser.Easing.Quadratic.InOut, true);

    var sensitivityOptions = [
      {name: 'sense_high', yOffset: 120},
      {name: 'sense_medium', yOffset: 250},
      {name: 'sense_low', yOffset: 380}
    ];

    var sensitivitySprites = {};

    sensitivityOptions.forEach(
      function(option){
        var sprite = game.add.sprite(optionsTitle.position.x, optionsTitle.position.y + option.yOffset, option.name);
        sprite.anchor.setTo(0.5, 0.5);
        sprite.scale.setTo(0.4);
        sprite.alpha = 0;
        sprite.inputEnabled = true;
        game.add.tween(sprite).to({alpha: 1}, 1000, Phaser.Easing.Quadratic.InOut, true, 1000 );
        sensitivitySprites[option.name] = sprite;
    });

    // set sprite scale according to current sensitivity

      function selectSensitivity(selectedSprite) {
      inputSensitivity = SENSITIVITIES[selectedSprite];
      ['sense_high', 'sense_medium', 'sense_low'].forEach(function(spriteName) {
        var targetScale = (selectedSprite === spriteName) ? 0.5 : 0.3;
        game.add.tween(sensitivitySprites[spriteName].scale).to({x: targetScale, y: targetScale}, 500, Phaser.Easing.Quadratic.InOut, true);
      });
    }

      ['sense_high', 'sense_medium', 'sense_low'].forEach(function(sensitivityOption) {

      // make sure the current sensitivity is reflected in the options when screen loads
      if (inputSensitivity === SENSITIVITIES[sensitivityOption]) {
        selectSensitivity(sensitivityOption);
      }
      // in terms of compute cycle, the arrays are iterated through twice. perhaps could be refactored more.

      sensitivitySprites[sensitivityOption].events.onInputDown.add(selectSensitivity.bind(this, sensitivityOption), this);

    });

    function backToMenu() {
      this.game.state.start('main_menu');
    }

    backButton.events.onInputDown.add(backToMenu, this);

  },

  update: function() {

  ballMovement(this.testBall, ax, ay, inputSensitivity, cursors);

  }
};

<|endoftext|>


<commit_before>/* eslint-env node */
/* eslint-disable camelcase */

const browsers = {
  safariMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'Catalina',
    browser: 'Safari',
    browser_version: 'latest'
  },
  chromeMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'Catalina',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'Catalina',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  chromeWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  iphone7: {
    base: 'BrowserStack',
    os: 'ios',
    os_version: '10.0',
    device: 'iPhone 7',
    real_mobile: true
  },
  iphone11: {
    base: 'BrowserStack',
    os: 'ios',
    os_version: '13.0',
    device: 'iPhone 11',
    real_mobile: true
  },
  pixel2: {
    base: 'BrowserStack',
    os: 'android',
    os_version: '8.0',
    device: 'Google Pixel 2',
    real_mobile: true
  }
}

const browsersKeys = Object.keys(browsers)

module.exports = {
  browsers,
  browsersKeys
}
<commit_msg>BrowserStack: test on iPhone 12 (#33398)<commit_after>/* eslint-env node */
/* eslint-disable camelcase */

const browsers = {
  safariMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'Catalina',
    browser: 'Safari',
    browser_version: 'latest'
  },
  chromeMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'Catalina',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'Catalina',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  chromeWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  iphone7: {
    base: 'BrowserStack',
    os: 'ios',
    os_version: '10.0',
    device: 'iPhone 7',
    real_mobile: true
  },
  iphone12: {
    base: 'BrowserStack',
    os: 'ios',
    os_version: '14.0',
    device: 'iPhone 12',
    real_mobile: true
  },
  pixel2: {
    base: 'BrowserStack',
    os: 'android',
    os_version: '8.0',
    device: 'Google Pixel 2',
    real_mobile: true
  }
}

const browsersKeys = Object.keys(browsers)

module.exports = {
  browsers,
  browsersKeys
}
<|endoftext|>


<commit_before>'use strict';

var connect = function(){
    var napi = document.getElementById("api").value;
    if (napi != "/") {
        api = "http://" + napi;
    }
    $("#start").hide();
    $("#api").attr('disabled', true);

    new Promise(function(resolve, reject){
        navigator.getUserMedia({
            video:true,audio:true
        },function(stream){
            resolve(stream);
        }, function(error){
            reject(error);
        });
    }).then(function(stream){
        var lv = document.getElementById("local");
        try {
            lv.src = window.URL.createObjectURL(stream);
        } catch (error) {
            lv.srcObject = stream;
        }
        console.log("[navigator.getUserMedia] lv.src= " + lv.src);

        // Use a peer connection to share stream to responder.
        var conn = new window.webkitRTCPeerConnection({
            iceTransportPolicy: 'relay',
            iceServers:[{urls:["turn:stun.ossrs.net"], username:"guest", credential:"12345678"
        }]});
        conn.addStream(stream);
        console.log("[conn.addStream] add stream to peer connection");

        return conn;
    }).then(function(conn){
        // Render the remote initiator stream.
        conn.onaddstream = function(e) {
            var rv = document.getElementById("remote");
            try {
                rv.src = window.URL.createObjectURL(e.stream);
            } catch (error) {
                rv.srcObject = e.stream;
            }
            console.log("[conn.onaddstream] rv.src=remoteStream " + rv.src);
        };

        callInitiator(conn, api);
    });
};

// https://codelabs.developers.google.com/codelabs/webrtc-web/#6
var api = "";
$("#start").click(connect);
connect();

function callInitiator(conn, api) {
    Promise.all([new Promise(function(resolve, reject){
        // Request the candidates of initiator.
        var requestCandidates = function() {
            $.ajax({
                type:"GET", async:true, url:api+"/api/webrtc/icandidates", contentType:"application/json",
                success:function(data){
                    data = JSON.parse(data) || [];

                    // Wait util the rcandidates are completed, we should got 2+ candidates.
                    if (data.length < 2) {
                        setTimeout(requestCandidates, 1000);
                        return;
                    }

                    resolve(data);
                }, error:function(xhr,err){
                    reject(err);
                }
            });
        };
        requestCandidates();
    }), new Promise(function(resolve, reject){
        // Query the offer of initiator from signaling server.
        $.ajax({
            type:"GET", async:true, url:api+"/api/webrtc/offer", contentType:"application/json",
            success:function(data){
                var offer = JSON.parse(data);
                offer = offer[0];
                offer = JSON.parse(offer);
                offer = unescapeOffer(offer);
                resolve(offer);
            },
            error: function(xhr, err) {
                reject(err);
            }
        });
    })]).then(function([candidates,offer]){
        // once got the peer offer(SDP), we can generate our answer(SDP).
        conn.setRemoteDescription(offer); // trigger conn.onaddstream
        console.log("[onRemoteGotOffer] Got offer " + offer.sdp.length + "B sdp as bellow:");
        console.log(offer); console.log(offer.sdp);

        // before addIceCandidate, we must setRemoteDescription
        for (var i = 0; i < candidates.length; i++) {
            var candidate = unescapeCandicate(JSON.parse(candidates[i]));
            conn.addIceCandidate(new window.RTCIceCandidate(candidate));
            console.log("[requestCandidates] Got initiator candidate " + JSON.stringify(candidate));
            console.log(candidate);
        }

        // Transmit the responder candidates to signaling server.
        conn.onicecandidate = function(e) {
            if (!e.candidate) {
                return;
            }
            if (e.candidate.candidate.indexOf("relay") == -1) {
                console.log("[conn.onicecandidate] ignore " + e.candidate.candidate);
                return;
            }
            console.log("[conn.onicecandidate] " + e.candidate.candidate);
            console.log(e.candidate);

            var data = JSON.stringify(escapeCandicate(e.candidate));
            $.ajax({type:"POST", async:true, url:api+"/api/webrtc/rcandidates", contentType:"application/json", data:data});
        };

        // Since the 'remote' side has no media stream we need
        // to pass in the right constraints in order for it to
        // accept the incoming offer of audio and video.
        conn.createAnswer(function(answer){
            // For chrome new API, we can delay set the TURN.
            //conn.setConfiguration({iceServers:[{urls:["turn:stun.ossrs.net"], username:"guest", credential:"12345678"}]});

            conn.setLocalDescription(answer); // trigger conn.onicecandidate().
            console.log("[conn.createAnswer] answer " + answer.sdp.length + "B sdp as bellow:");
            console.log(answer); console.log(answer.sdp);

            var data = JSON.stringify(escapeOffer(answer));
            $.ajax({type:"POST", async:true, url:api+"/api/webrtc/answer", contentType:"application/json", data:data});
        }, function(error){
            console.log(error);
        });
    });
}

function escapeOffer(offer) {
    return {type:offer.type, sdp:escape(offer.sdp)};
}

function escapeCandicate(candidate) {
    return {sdpMid:candidate.sdpMid, sdpMLineIndex:candidate.sdpMLineIndex, candidate:escape(candidate.candidate)};
}

function unescapeOffer(offer) {
    return {type:offer.type, sdp:unescape(offer.sdp)};
}

function unescapeCandicate(candidate) {
    return {sdpMid:candidate.sdpMid, sdpMLineIndex:candidate.sdpMLineIndex, candidate:unescape(candidate.candidate)};
}<commit_msg>Update<commit_after>'use strict';

var connect = function(){
    var napi = document.getElementById("api").value;
    if (napi != "/") {
        api = "http://" + napi;
    }
    $("#start").hide();
    $("#api").attr('disabled', true);

    new Promise(function(resolve, reject){
        navigator.getUserMedia({
            video:true,audio:true
        },function(stream){
            resolve(stream);
        }, function(error){
            reject(error);
        });
    }).then(function(stream){
        var lv = document.getElementById("local");
        try {
            lv.src = window.URL.createObjectURL(stream);
        } catch (error) {
            lv.srcObject = stream;
        }
        console.log("[navigator.getUserMedia] lv.src= " + lv.src);

        // Use a peer connection to share stream to responder.
        var conn = new window.webkitRTCPeerConnection({
            iceTransportPolicy: 'relay',
            iceServers:[{urls:["turn:stun.ossrs.net"], username:"guest", credential:"12345678"
        }]});
        conn.addStream(stream);
        console.log("[conn.addStream] add stream to peer connection");

        return conn;
    }).then(function(conn){
        // Render the remote initiator stream.
        conn.onaddstream = function(e) {
            var rv = document.getElementById("remote");
            try {
                rv.src = window.URL.createObjectURL(e.stream);
            } catch (error) {
                rv.srcObject = e.stream;
            }
            console.log("[conn.onaddstream] rv.src=remoteStream " + rv.src);
        };

        callInitiator(conn, api);
    });
};

// https://codelabs.developers.google.com/codelabs/webrtc-web/#6
var api = "";
$("#start").click(connect);
connect();

function callInitiator(conn, api) {
    new Promise(function(resolve, reject){
        $.ajax({
            type:"POST", async:true, url:api+"/api/webrtc/answer", contentType:"application/json", data:"",
            success:function(){
                resolve();
            }, error:function(){
                reject();
            }
        });
    }).then(function() {
        return Promise.all([new Promise(function(resolve, reject){
            // Request the candidates of initiator.
            var requestCandidates = function() {
                $.ajax({
                    type:"GET", async:true, url:api+"/api/webrtc/icandidates", contentType:"application/json",
                    success:function(data){
                        data = JSON.parse(data) || [];

                        // Wait util the rcandidates are completed, we should got 2+ candidates.
                        if (data.length < 2) {
                            setTimeout(requestCandidates, 1000);
                            return;
                        }

                        resolve(data);
                    }, error:function(xhr,err){
                        reject(err);
                    }
                });
            };
            requestCandidates();
        }), new Promise(function(resolve, reject){
            // Query the offer of initiator from signaling server.
            $.ajax({
                type:"GET", async:true, url:api+"/api/webrtc/offer", contentType:"application/json",
                success:function(data){
                    var offer = JSON.parse(data);
                    offer = offer[0];
                    offer = JSON.parse(offer);
                    offer = unescapeOffer(offer);
                    resolve(offer);
                },
                error: function(xhr, err) {
                    reject(err);
                }
            });
        })]);
    }).then(function([candidates,offer]){
        // once got the peer offer(SDP), we can generate our answer(SDP).
        conn.setRemoteDescription(offer); // trigger conn.onaddstream
        console.log("[onRemoteGotOffer] Got offer " + offer.sdp.length + "B sdp as bellow:");
        console.log(offer); console.log(offer.sdp);

        // before addIceCandidate, we must setRemoteDescription
        for (var i = 0; i < candidates.length; i++) {
            var candidate = unescapeCandicate(JSON.parse(candidates[i]));
            conn.addIceCandidate(new window.RTCIceCandidate(candidate));
            console.log("[requestCandidates] Got initiator candidate " + JSON.stringify(candidate));
            console.log(candidate);
        }

        // Transmit the responder candidates to signaling server.
        conn.onicecandidate = function(e) {
            if (!e.candidate) {
                return;
            }
            if (e.candidate.candidate.indexOf("relay") == -1) {
                console.log("[conn.onicecandidate] ignore " + e.candidate.candidate);
                return;
            }
            console.log("[conn.onicecandidate] " + e.candidate.candidate);
            console.log(e.candidate);

            var data = JSON.stringify(escapeCandicate(e.candidate));
            $.ajax({type:"POST", async:true, url:api+"/api/webrtc/rcandidates", contentType:"application/json", data:data});
        };

        // Since the 'remote' side has no media stream we need
        // to pass in the right constraints in order for it to
        // accept the incoming offer of audio and video.
        conn.createAnswer(function(answer){
            // For chrome new API, we can delay set the TURN.
            //conn.setConfiguration({iceServers:[{urls:["turn:stun.ossrs.net"], username:"guest", credential:"12345678"}]});

            conn.setLocalDescription(answer); // trigger conn.onicecandidate().
            console.log("[conn.createAnswer] answer " + answer.sdp.length + "B sdp as bellow:");
            console.log(answer); console.log(answer.sdp);

            var data = JSON.stringify(escapeOffer(answer));
            $.ajax({type:"POST", async:true, url:api+"/api/webrtc/answer", contentType:"application/json", data:data});
        }, function(error){
            console.log(error);
        });
    });
}

function escapeOffer(offer) {
    return {type:offer.type, sdp:escape(offer.sdp)};
}

function escapeCandicate(candidate) {
    return {sdpMid:candidate.sdpMid, sdpMLineIndex:candidate.sdpMLineIndex, candidate:escape(candidate.candidate)};
}

function unescapeOffer(offer) {
    return {type:offer.type, sdp:unescape(offer.sdp)};
}

function unescapeCandicate(candidate) {
    return {sdpMid:candidate.sdpMid, sdpMLineIndex:candidate.sdpMLineIndex, candidate:unescape(candidate.candidate)};
}<|endoftext|>


<commit_before>const BlockStream = require('block-stream2')
const stream = require('readable-stream')

class ChunkStoreWriteStream extends stream.Writable {
  constructor (store, chunkLength, opts = {}) {
    super(opts)

    if (!store || !store.put || !store.get) {
      throw new Error('First argument must be an abstract-chunk-store compliant store')
    }
    chunkLength = Number(chunkLength)
    if (!chunkLength) throw new Error('Second argument must be a chunk length')

    this._blockstream = new BlockStream(chunkLength, { zeroPadding: false })

    let index = 0
    const onData = chunk => {
      if (this.destroyed) return
      store.put(index, chunk)
      index += 1
    }

    this._blockstream
      .on('data', onData)
      .on('error', err => { this.destroy(err) })

    this.on('finish', this._blockstream.end)
  }

  _write (chunk, encoding, callback) {
    this._blockstream.write(chunk, encoding, callback)
  }

  destroy (err) {
    if (this.destroyed) return
    this.destroyed = true

    if (err) this.emit('error', err)
    this.emit('close')
  }
}

module.exports = ChunkStoreWriteStream
<commit_msg>fix: Ensure blockstream is bound<commit_after>const BlockStream = require('block-stream2')
const stream = require('readable-stream')

class ChunkStoreWriteStream extends stream.Writable {
  constructor (store, chunkLength, opts = {}) {
    super(opts)

    if (!store || !store.put || !store.get) {
      throw new Error('First argument must be an abstract-chunk-store compliant store')
    }
    chunkLength = Number(chunkLength)
    if (!chunkLength) throw new Error('Second argument must be a chunk length')

    this._blockstream = new BlockStream(chunkLength, { zeroPadding: false })

    let index = 0
    const onData = chunk => {
      if (this.destroyed) return
      store.put(index, chunk)
      index += 1
    }

    this._blockstream
      .on('data', onData)
      .on('error', err => { this.destroy(err) })

    this.on('finish', () => this._blockstream.end())
  }

  _write (chunk, encoding, callback) {
    this._blockstream.write(chunk, encoding, callback)
  }

  destroy (err) {
    if (this.destroyed) return
    this.destroyed = true

    if (err) this.emit('error', err)
    this.emit('close')
  }
}

module.exports = ChunkStoreWriteStream
<|endoftext|>


<commit_before>/*global $,app,L,accounting*/

app.views.property = function (accountNumber) {
  var alreadyGettingOpaData, opaRendered, opaDetailsRendered;

  // Search area prep
  app.hooks.propertyTitle.find('h1').html(' ');
  app.hooks.propertyTitle.find('.small-text').empty();
  app.hooks.search.val('');
  app.hooks.search.attr('placeholder', 'Search for another property');
  app.hooks.searchForm.removeClass('hint');
  app.hooks.searchForm.find('p').addClass('hidden');
  app.hooks.searchLeft.removeClass('medium-4').addClass('medium-14')
    .empty().append(app.hooks.propertyTitle);
    app.hooks.searchRight.html('');
  app.hooks.searchBox.removeClass('medium-16').addClass('medium-10 float-right');

  // Clear existing elements out of the way
  app.hooks.content.children().detach();

  if (!history.state) history.replaceState({}, '');

  if (history.state.error) return renderError();

  if (history.state.opa) {
    renderOpa();
  } else {
    app.hooks.content.append(app.hooks.loading);
    getOpaData();
  }

  // The less-detailed search result contains address_match
  if (history.state.opa && !history.state.opa.address_match) {
    renderOpaDetails();
  } else {
    if (!alreadyGettingOpaData) getOpaData();
  }

  if (history.state.sa) {
    renderSa();
  } else if (history.state.address) {
    getSaData();
  }

  function getOpaData () {
    alreadyGettingOpaData = true;
    $.ajax('https://api.phila.gov/opa/v1.1/account/' + accountNumber + '?format=json',
      {dataType: app.settings.ajaxType})
      .done(function (data) {
        var state = $.extend({}, history.state);
        var property = data.data.property;
        state.opa = property;
        state.address = app.util.addressWithUnit(property);
        history.replaceState(state, ''); // Second param not optional in IE10
        if (!opaRendered) renderOpa();
        if (!opaDetailsRendered) renderOpaDetails();
        if (!state.sa) getSaData();
      })
      .fail(function () {
        history.replaceState({error: true}, '');
        renderError();
      });
  }

  function getSaData () {
    $.ajax('https://api.phila.gov/ulrs/v3/addresses/' + encodeURIComponent(history.state.address) +
      '/service-areas?format='+app.settings.ajaxType, {dataType: app.settings.ajaxType})
      .done(function (data) {
        var state = $.extend({}, history.state);
        state.sa = data.serviceAreaValues;
        history.replaceState(state, '');
        renderSa();
      })
      .fail(function () {
        var state = $.extend({}, history.state);
        state.sa = {error: true};
        history.replaceState(state, '');
      });
  }

  function renderOpa () {
    var state = history.state;

    // Breadcrumbs
    app.hooks.propertyCrumb.text(state.address);
    app.hooks.crumbs.update(app.hooks.propertyCrumb);

    // Search area
    app.hooks.propertyTitle.find('h1').text(state.address);
    app.hooks.propertyTitle.find('.small-text').text('#' + state.opa.account_number);

    // Clear loading...
    app.hooks.content.empty();

    // Render owners
    app.hooks.propertyOwners.empty();
    state.opa.ownership.owners.forEach(function (owner) {
      app.hooks.propertyOwners.append($('
').text(owner));
    });

    // Render improvement stuff
    app.hooks.improvementDescription.text(state.opa.characteristics.description);
    app.hooks.landArea.text(accounting.formatNumber(state.opa.characteristics.land_area));
    app.hooks.improvementArea.text(accounting.formatNumber(state.opa.characteristics.improvement_area));

    // Empty zoning in prep for details
    app.hooks.zoning.empty();

    // Render sales details
    app.hooks.salesPrice.text(accounting.formatMoney(state.opa.sales_information.sales_price));
    app.hooks.salesDate.text(app.util.formatSalesDate(state.opa.sales_information.sales_date));

    // Empty mailing address in prep for details
    app.hooks.propertyMailingHeader.detach();
    app.hooks.propertyMailing.empty();

    // Empty valuation history
    app.hooks.valuation.empty();

    app.hooks.content.append(app.hooks.propertyMain);
    app.hooks.content.append(app.hooks.propertySide);
    app.hooks.belowContent.append(app.hooks.propertySecondary);

    // Render Map
    renderMap();

    opaRendered = true;
  }

  function renderMap() {
    var state = history.state;

    // Init the map
    var map = L.map(app.hooks.map[0], {
      center: [state.opa.geometry.y, state.opa.geometry.x],
      zoom: 15,
      minZoom: 11,
      maxZoom: 15,
      scrollWheelZoom: false
    });

    // This is the map layer we want to use, but there's something not working about the config
    // L.esri.tiledMapLayer("http://tiles.arcgis.com/tiles/fLeGjb7u4uXqeF9q/arcgis/rest/services/CityMap_20150515/MapServer", {
    // }).addTo(map);

    // Test layer
    L.esri.tiledMapLayer("http://services.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer", {
    }).addTo(map);

    // Add a marker to highlight the property
    L.marker([state.opa.geometry.y, state.opa.geometry.x]).addTo(map);
  }

  function renderOpaDetails () {
    var state = history.state;

    // Render mailing address
    var pm = app.hooks.propertyMailing;
    var ma = state.opa.ownership.mailing_address;
    app.hooks.propertyMailingHeader.insertBefore(pm);
    pm.append($('
').text(state.opa.ownership.liaison));
    pm.append($('
').text(ma.street));
    pm.append($('
').text(ma.city + ', ' + ma.state));
    pm.append($('
').text(ma.zip));

    // Render zoning
    app.hooks.zoning.html(state.opa.characteristics.zoning + '
' +
      state.opa.characteristics.zoning_description);

    // Render valuation history
    state.opa.valuation_history.forEach(function (vh) {
      var row = $('
');
      row.append($('').text(vh.certification_year));
      row.append($('').text(accounting.formatMoney(vh.market_value)));
      row.append($('').text(accounting.formatMoney(vh.land_taxable)));
      row.append($('').text(accounting.formatMoney(vh.improvement_taxable)));
      row.append($('').text(accounting.formatMoney(vh.land_exempt)));
      row.append($('').text(accounting.formatMoney(vh.improvement_exempt)));
      app.hooks.valuation.append(row);
    });

    opaDetailsRendered = true;
  }

  function renderSa () {
    var state = history.state;

    // No use rendering if there's been a data error
    if (state.error || state.sa.error) return;

    // Wait for both OPA render and SA data
    if (!opaRendered || !state.sa) return;

    // Render service areas
    state.sa.forEach(function (sa) {
      switch (sa.serviceAreaId) {
        // Sidebox
        case 'SA_STREETS_Rubbish_Recyc':
          return app.hooks.rubbishDay.text(sa.value);

        // School catchment
        case 'SA_SCHOOLS_Elementary_School_Catchment':
          return app.hooks.elementarySchool.text(sa.value);
        case 'SA_SCHOOLS_Middle_School_Catchment':
          return app.hooks.middleSchool.text(sa.value);
        case 'SA_SCHOOLS_High_School_Catchment':
          return app.hooks.highSchool.text(sa.value);

        // Political
        case 'SA_PLANNING_2016Councilmanic':
          return app.hooks.councilDistrict.text(sa.value);
        case 'SA_PLANNING_Ward':
          return app.hooks.ward.text(sa.value);
        case 'SA_PLANNING_Ward_Divisions':
          return app.hooks.wardDivisions.text(sa.value);

        // Public safety
        case 'SA_POLICE_PSA':
          return app.hooks.policePsa.text(sa.value);
        case 'SA_POLICE_District':
          return app.hooks.policeDistrict.text(sa.value);
        case 'SA_POLICE_Sector':
          return app.hooks.policeSector.text(sa.value);
        case 'SA_POLICE_Division':
          return app.hooks.policeDivision.text(sa.value);
        case 'SA_POLICE_FireDistricts':
          return app.hooks.fireDistrict.text(sa.value);

        // Streets
        case 'SA_STREETS_Highway_District':
          return app.hooks.highwayDistrict.text(sa.value);
        case 'SA_STREETS_Highway_Section':
          return app.hooks.highwaySection.text(sa.value);
        case 'SA_STREETS_Highway_Subsection':
          return app.hooks.highwaySubsection.text(sa.value);
        case 'SA_STREETS_Street_Lights_Routes':
          return app.hooks.streetLightRoutes.text(sa.value);
        case 'SA_Streets_Traffic_District':
          return app.hooks.trafficDistrict.text(sa.value);
        case 'SA_STREETS_Recycling_Diversion_Rate':
          return app.hooks.recyclingDiversion.text(sa.value);
        case 'SA_STREETS_Sanitation_Area':
          return app.hooks.sanitationArea.text(sa.value);
        case 'SA_STREETS_Sanitation_Districts':
          return app.hooks.sanitationDistrict.text(sa.value);
        case 'SA_STREETS_Leaf':
          return app.hooks.leafCollection.text(sa.value);
        case 'SA_Streets_Traffic_PM_District':
          return app.hooks.trafficPmDistrict.text(sa.value);

        // Districts
        case 'SA_PLANNING_Planning_Districts':
          return app.hooks.planning.text(sa.value);
        case 'SA_LNI_DISTRICT':
          return app.hooks.liDistrict.text(sa.value);
        case 'SA_STREETS_HISTORIC':
          return app.hooks.historic.text(app.util.default(sa.value, 'No'));
        case 'SA_RECREATION_Recreation_District':
          return app.hooks.recreation.text(sa.value);
        case 'SA_PHILLYRISING':
          return app.hooks.phillyRising.text(app.util.default(sa.value, 'No'));

        // Water
        case 'PWD_MAINT_DIST':
          return app.hooks.pwdMaintenance.text(sa.value);
        case 'PWD_PRES_DIST':
          return app.hooks.pwdPressure.text(sa.value);
        case 'PWD_WTPSA':
          return app.hooks.waterTreatment.text(sa.value);
        case 'SA_WATER_Water_Plate_Index':
          return app.hooks.waterPlate.text(sa.value);
      }
    });
  }

  function renderError () {
    // TODO Display an error message that looks nice
  }

  // // TODO Get L&I data
  // // Tim also pointed at http://api.phila.gov/ULRS311/Data/LIAddressKey/340%20n%2012th%20st
  // var topicsUrl = 'https://api.phila.gov/ulrs/v3/addresses/' + encodeURIComponent(params.p) + '/topics?format=json';
  // $.ajax(topicsUrl)
  //   .done(function (data) {
  //     var addressKey;
  //     data.topics.some(function (topic) {
  //       if (topic.topicName === 'AddressKeys') {
  //         return topic.keys.some(function (key) {
  //           if (key.topicId) {
  //             addressKey = key.topicId;
  //             return true;
  //           }
  //         });
  //       }
  //     });
  //     if (!addressKey) {
  //       propertyData.li = {error: 'No L&I key found at ' + topicsUrl + '.'};
  //       return --pending || app.views.address(propertyData);
  //     }
  //     $.ajax('https://services.phila.gov/PhillyApi/Data/v1.0/locations(' + addressKey + ')?$format=json')
  //       .done(function (data) {
  //         propertyData.li = data.d;
  //         --pending || app.views.property(propertyData);
  //       })
  //       .fail(function () {
  //         propertyData.li = {error: 'Failed to retrieve L&I address data.'};
  //         --pending || app.views.property(propertyData);
  //       });
  //   })
  //   .fail(function () {
  //     propertyData.li = {error: 'Failed to retrieve address topics.'};
  //     --pending || app.views.property(propertyData);
  //   });
  //
  // function renderLi () {
  // }
};
<commit_msg>Update test layer to another phila.gov base layer.<commit_after>/*global $,app,L,accounting*/

app.views.property = function (accountNumber) {
  var alreadyGettingOpaData, opaRendered, opaDetailsRendered;

  // Search area prep
  app.hooks.propertyTitle.find('h1').html(' ');
  app.hooks.propertyTitle.find('.small-text').empty();
  app.hooks.search.val('');
  app.hooks.search.attr('placeholder', 'Search for another property');
  app.hooks.searchForm.removeClass('hint');
  app.hooks.searchForm.find('p').addClass('hidden');
  app.hooks.searchLeft.removeClass('medium-4').addClass('medium-14')
    .empty().append(app.hooks.propertyTitle);
    app.hooks.searchRight.html('');
  app.hooks.searchBox.removeClass('medium-16').addClass('medium-10 float-right');

  // Clear existing elements out of the way
  app.hooks.content.children().detach();

  if (!history.state) history.replaceState({}, '');

  if (history.state.error) return renderError();

  if (history.state.opa) {
    renderOpa();
  } else {
    app.hooks.content.append(app.hooks.loading);
    getOpaData();
  }

  // The less-detailed search result contains address_match
  if (history.state.opa && !history.state.opa.address_match) {
    renderOpaDetails();
  } else {
    if (!alreadyGettingOpaData) getOpaData();
  }

  if (history.state.sa) {
    renderSa();
  } else if (history.state.address) {
    getSaData();
  }

  function getOpaData () {
    alreadyGettingOpaData = true;
    $.ajax('https://api.phila.gov/opa/v1.1/account/' + accountNumber + '?format=json',
      {dataType: app.settings.ajaxType})
      .done(function (data) {
        var state = $.extend({}, history.state);
        var property = data.data.property;
        state.opa = property;
        state.address = app.util.addressWithUnit(property);
        history.replaceState(state, ''); // Second param not optional in IE10
        if (!opaRendered) renderOpa();
        if (!opaDetailsRendered) renderOpaDetails();
        if (!state.sa) getSaData();
      })
      .fail(function () {
        history.replaceState({error: true}, '');
        renderError();
      });
  }

  function getSaData () {
    $.ajax('https://api.phila.gov/ulrs/v3/addresses/' + encodeURIComponent(history.state.address) +
      '/service-areas?format='+app.settings.ajaxType, {dataType: app.settings.ajaxType})
      .done(function (data) {
        var state = $.extend({}, history.state);
        state.sa = data.serviceAreaValues;
        history.replaceState(state, '');
        renderSa();
      })
      .fail(function () {
        var state = $.extend({}, history.state);
        state.sa = {error: true};
        history.replaceState(state, '');
      });
  }

  function renderOpa () {
    var state = history.state;

    // Breadcrumbs
    app.hooks.propertyCrumb.text(state.address);
    app.hooks.crumbs.update(app.hooks.propertyCrumb);

    // Search area
    app.hooks.propertyTitle.find('h1').text(state.address);
    app.hooks.propertyTitle.find('.small-text').text('#' + state.opa.account_number);

    // Clear loading...
    app.hooks.content.empty();

    // Render owners
    app.hooks.propertyOwners.empty();
    state.opa.ownership.owners.forEach(function (owner) {
      app.hooks.propertyOwners.append($('
').text(owner));
    });

    // Render improvement stuff
    app.hooks.improvementDescription.text(state.opa.characteristics.description);
    app.hooks.landArea.text(accounting.formatNumber(state.opa.characteristics.land_area));
    app.hooks.improvementArea.text(accounting.formatNumber(state.opa.characteristics.improvement_area));

    // Empty zoning in prep for details
    app.hooks.zoning.empty();

    // Render sales details
    app.hooks.salesPrice.text(accounting.formatMoney(state.opa.sales_information.sales_price));
    app.hooks.salesDate.text(app.util.formatSalesDate(state.opa.sales_information.sales_date));

    // Empty mailing address in prep for details
    app.hooks.propertyMailingHeader.detach();
    app.hooks.propertyMailing.empty();

    // Empty valuation history
    app.hooks.valuation.empty();

    app.hooks.content.append(app.hooks.propertyMain);
    app.hooks.content.append(app.hooks.propertySide);
    app.hooks.belowContent.append(app.hooks.propertySecondary);

    // Render Map
    renderMap();

    opaRendered = true;
  }

  function renderMap() {
    var state = history.state;

    // Init the map
    var map = L.map(app.hooks.map[0], {
      center: [state.opa.geometry.y, state.opa.geometry.x],
      zoom: 17,
      minZoom: 11,
      maxZoom: 18,
      scrollWheelZoom: false
    });

    // This is the map layer we want to use, but there's something not working about the config
    // L.esri.tiledMapLayer("http://tiles.arcgis.com/tiles/fLeGjb7u4uXqeF9q/arcgis/rest/services/CityMap_20150515/MapServer", {
    // }).addTo(map);

    L.esri.tiledMapLayer("http://gis.phila.gov/arcgis/rest/services/BaseMaps/GrayBase_WM/MapServer", {
    }).addTo(map);

    // Add a marker to highlight the property
    L.marker([state.opa.geometry.y, state.opa.geometry.x]).addTo(map);
  }

  function renderOpaDetails () {
    var state = history.state;

    // Render mailing address
    var pm = app.hooks.propertyMailing;
    var ma = state.opa.ownership.mailing_address;
    app.hooks.propertyMailingHeader.insertBefore(pm);
    pm.append($('
').text(state.opa.ownership.liaison));
    pm.append($('
').text(ma.street));
    pm.append($('
').text(ma.city + ', ' + ma.state));
    pm.append($('
').text(ma.zip));

    // Render zoning
    app.hooks.zoning.html(state.opa.characteristics.zoning + '
' +
      state.opa.characteristics.zoning_description);

    // Render valuation history
    state.opa.valuation_history.forEach(function (vh) {
      var row = $('
');
      row.append($('').text(vh.certification_year));
      row.append($('').text(accounting.formatMoney(vh.market_value)));
      row.append($('').text(accounting.formatMoney(vh.land_taxable)));
      row.append($('').text(accounting.formatMoney(vh.improvement_taxable)));
      row.append($('').text(accounting.formatMoney(vh.land_exempt)));
      row.append($('').text(accounting.formatMoney(vh.improvement_exempt)));
      app.hooks.valuation.append(row);
    });

    opaDetailsRendered = true;
  }

  function renderSa () {
    var state = history.state;

    // No use rendering if there's been a data error
    if (state.error || state.sa.error) return;

    // Wait for both OPA render and SA data
    if (!opaRendered || !state.sa) return;

    // Render service areas
    state.sa.forEach(function (sa) {
      switch (sa.serviceAreaId) {
        // Sidebox
        case 'SA_STREETS_Rubbish_Recyc':
          return app.hooks.rubbishDay.text(sa.value);

        // School catchment
        case 'SA_SCHOOLS_Elementary_School_Catchment':
          return app.hooks.elementarySchool.text(sa.value);
        case 'SA_SCHOOLS_Middle_School_Catchment':
          return app.hooks.middleSchool.text(sa.value);
        case 'SA_SCHOOLS_High_School_Catchment':
          return app.hooks.highSchool.text(sa.value);

        // Political
        case 'SA_PLANNING_2016Councilmanic':
          return app.hooks.councilDistrict.text(sa.value);
        case 'SA_PLANNING_Ward':
          return app.hooks.ward.text(sa.value);
        case 'SA_PLANNING_Ward_Divisions':
          return app.hooks.wardDivisions.text(sa.value);

        // Public safety
        case 'SA_POLICE_PSA':
          return app.hooks.policePsa.text(sa.value);
        case 'SA_POLICE_District':
          return app.hooks.policeDistrict.text(sa.value);
        case 'SA_POLICE_Sector':
          return app.hooks.policeSector.text(sa.value);
        case 'SA_POLICE_Division':
          return app.hooks.policeDivision.text(sa.value);
        case 'SA_POLICE_FireDistricts':
          return app.hooks.fireDistrict.text(sa.value);

        // Streets
        case 'SA_STREETS_Highway_District':
          return app.hooks.highwayDistrict.text(sa.value);
        case 'SA_STREETS_Highway_Section':
          return app.hooks.highwaySection.text(sa.value);
        case 'SA_STREETS_Highway_Subsection':
          return app.hooks.highwaySubsection.text(sa.value);
        case 'SA_STREETS_Street_Lights_Routes':
          return app.hooks.streetLightRoutes.text(sa.value);
        case 'SA_Streets_Traffic_District':
          return app.hooks.trafficDistrict.text(sa.value);
        case 'SA_STREETS_Recycling_Diversion_Rate':
          return app.hooks.recyclingDiversion.text(sa.value);
        case 'SA_STREETS_Sanitation_Area':
          return app.hooks.sanitationArea.text(sa.value);
        case 'SA_STREETS_Sanitation_Districts':
          return app.hooks.sanitationDistrict.text(sa.value);
        case 'SA_STREETS_Leaf':
          return app.hooks.leafCollection.text(sa.value);
        case 'SA_Streets_Traffic_PM_District':
          return app.hooks.trafficPmDistrict.text(sa.value);

        // Districts
        case 'SA_PLANNING_Planning_Districts':
          return app.hooks.planning.text(sa.value);
        case 'SA_LNI_DISTRICT':
          return app.hooks.liDistrict.text(sa.value);
        case 'SA_STREETS_HISTORIC':
          return app.hooks.historic.text(app.util.default(sa.value, 'No'));
        case 'SA_RECREATION_Recreation_District':
          return app.hooks.recreation.text(sa.value);
        case 'SA_PHILLYRISING':
          return app.hooks.phillyRising.text(app.util.default(sa.value, 'No'));

        // Water
        case 'PWD_MAINT_DIST':
          return app.hooks.pwdMaintenance.text(sa.value);
        case 'PWD_PRES_DIST':
          return app.hooks.pwdPressure.text(sa.value);
        case 'PWD_WTPSA':
          return app.hooks.waterTreatment.text(sa.value);
        case 'SA_WATER_Water_Plate_Index':
          return app.hooks.waterPlate.text(sa.value);
      }
    });
  }

  function renderError () {
    // TODO Display an error message that looks nice
  }

  // // TODO Get L&I data
  // // Tim also pointed at http://api.phila.gov/ULRS311/Data/LIAddressKey/340%20n%2012th%20st
  // var topicsUrl = 'https://api.phila.gov/ulrs/v3/addresses/' + encodeURIComponent(params.p) + '/topics?format=json';
  // $.ajax(topicsUrl)
  //   .done(function (data) {
  //     var addressKey;
  //     data.topics.some(function (topic) {
  //       if (topic.topicName === 'AddressKeys') {
  //         return topic.keys.some(function (key) {
  //           if (key.topicId) {
  //             addressKey = key.topicId;
  //             return true;
  //           }
  //         });
  //       }
  //     });
  //     if (!addressKey) {
  //       propertyData.li = {error: 'No L&I key found at ' + topicsUrl + '.'};
  //       return --pending || app.views.address(propertyData);
  //     }
  //     $.ajax('https://services.phila.gov/PhillyApi/Data/v1.0/locations(' + addressKey + ')?$format=json')
  //       .done(function (data) {
  //         propertyData.li = data.d;
  //         --pending || app.views.property(propertyData);
  //       })
  //       .fail(function () {
  //         propertyData.li = {error: 'Failed to retrieve L&I address data.'};
  //         --pending || app.views.property(propertyData);
  //       });
  //   })
  //   .fail(function () {
  //     propertyData.li = {error: 'Failed to retrieve address topics.'};
  //     --pending || app.views.property(propertyData);
  //   });
  //
  // function renderLi () {
  // }
};
<|endoftext|>


<commit_before>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    $('img.botico').load(function(){
        $('#bot-wrapper span').show();
        setTimeout(function(){
            $('#bot-wrapper span').hide();
        },10*1000);
    });

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    interval = typeof interval !== 'undefined' ? interval : 30;
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && _dubug(uninstalled.length.toString()+" nodes to update");
    uninstalled.length && installbot(uninstalled);
}

function chatbot() {
    botupdate();

    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    //reply in current chat window
    typeof(observer) !== 'undefined' && observer.disconnect();
    if ( $('.activeColumn:has(".bot.active")').length ) {
         observer = new MutationObserver(function(mutations) {
         mutations.forEach(function(mutation) {
            e = mutation.addedNodes;
            console.log(e);
         });
        });
        observer.observe($('#chat_chatmsglist')[0], { childList: true});
    }

    //reply for red dotted item
    //$('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(runtimeGlobal.interval);
botupdate();
<commit_msg>测试mutation observer<commit_after>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
        typeof(observer) !== 'undefined' && observer.disconnect();
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    $('img.botico').load(function(){
        $('#bot-wrapper span').show();
        setTimeout(function(){
            $('#bot-wrapper span').hide();
        },10*1000);
    });

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    interval = typeof interval !== 'undefined' ? interval : 30;
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && _dubug(uninstalled.length.toString()+" nodes to update");
    uninstalled.length && installbot(uninstalled);
}

function chatbot() {
    botupdate();

    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    //reply in current chat window
    typeof(observer) !== 'undefined' && observer.disconnect();
    if ( $('.activeColumn:has(".bot.active")').length ) {
        observer = new MutationObserver(function(mutations) {
            var m = mutations.pop();
            if (m.nextSibling) {
                var newnode = m.addedNodes[1];
                var newmsg = $(newmsg).find('pre').text();
                var name = $('.activeColumn:has(".bot.active")');
                _dubug("msg from: " + name);
                if (newmsg) {
                    _dubug("msg content: " + newmsg);
                    callBotAPI(newmsg,sendmsg);
                } else {
                    _dubug("no msg found")
                }
            }
        });
        observer.observe($('#chat_chatmsglist')[0], { childList: true});
    }

    //reply for red dotted item
    //$('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        var name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(runtimeGlobal.interval);
botupdate();
<|endoftext|>


<commit_before>(function() {
	// if we have tab-bar handle hiding/showing tab-body with ID
	if ($('.tab-bar').length) {
		if (getCookie('TabHistory') == null) {
			console.log('no past tab clicked ');
			var first = $('.tab-bar > ul li:first-child a'),
				rel = first.attr('rel');

			// select the tab
			first.closest('li').addClass('current');

			// show the first tab body
			$(rel).addClass('current');
		}else{
			var recentTabId = getCookie('TabHistory');
			console.log('recent tab: ' + recentTabId);
			var recentTab = $("#" + recentTabId +' a'),
				rel = recentTab.attr('rel');
				$("#" + recentTabId).addClass('current');
				$(rel).addClass('current');
		}

		$('.tab-bar > ul li').on('click', function() {
			//clicked tab id
			var tabId = $(this).attr('id');
			// remove current from list item
			$('.tab-bar > ul li').removeClass('current');

			// add current to this list item
			$(this).addClass('current');

			// remove current from all tab bodies
			$('.tab-body').removeClass('current');

			// show the tab-body for clicked item
			$($('a', $(this)).attr('rel')).addClass('current');

			//set cookie on clicked tab
			setCookie('TabHistory', tabId);
		});
	}

//Cookies
function setCookie(key, value) {
	var expires = new Date();
	expires.setTime(expires.getTime() + (1 * 24 * 60 * 60 * 1000));
	document.cookie = key + '=' + value + ';expires=' + expires.toUTCString();
}

function getCookie(key) {
	var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
	return keyValue ? keyValue[2] : null;
}

})();

<commit_msg>added tab click history to url<commit_after>(function() {
    // if we have tab-bar handle hiding/showing tab-body with ID
    if ($('.tab-bar').length) {
        //get tab id from hash
        var selectedTab = window.location.hash.substr(1);
        if (selectedTab !='' && selectedTab.substring(0, 4) == 'tab_') {

            var recentTabId = selectedTab;
            var recentTab = $("#" + recentTabId + ' a'),
                rel = recentTab.attr('rel');
            $("#" + recentTabId).addClass('current');
            $(rel).addClass('current');
        } else {
            var first = $('.tab-bar > ul li:first-child a'),
                rel = first.attr('rel');

            // select the tab
            first.closest('li').addClass('current');

            // show the first tab body
            $(rel).addClass('current');
        }

        $('.tab-bar > ul li').on('click', function(e) {
            //clicked tab id
            var tabId = $(this).attr('id');
            // remove current from list item
            $('.tab-bar > ul li').removeClass('current');

            // add current to this list item
            $(this).addClass('current');

            // remove current from all tab bodies
            $('.tab-body').removeClass('current');

            // show the tab-body for clicked item
            $($('a', $(this)).attr('rel')).addClass('current');
            e.preventDefault();
            window.location.hash = tabId;
        });
    }

    //Cookies
    function setCookie(key, value) {
        var expires = new Date();
        expires.setTime(expires.getTime() + (1 * 24 * 60 * 60 * 1000));
        document.cookie = key + '=' + value + ';expires=' + expires.toUTCString();
    }

    function getCookie(key) {
        var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
        return keyValue ? keyValue[2] : null;
    }

})();
<|endoftext|>