<commit_before>
var oboe = (function(oboe){
   "use strict";

   /**
    * @param {Object} opt an object of options. Passed though
    * directly to clarinet.js but oboe.js does not
    * currently provide options.
    */
   oboe.parser = function(opt){
      return new OboeParser(opt);
   };

   /**
    * Convenient alias. Creates a new parser, starts an ajax request and returns the parser
    * ready to call .onPath() or .onFind() to register some callbacks
    * @param url
    */
   oboe.fetch = function(url){
      return new OboeParser().fetch(url);
   };

   function OboeParser(opt) {

      var clarinetParser = clarinet.parser(opt);

      this._thingFoundListeners = [];
      this._pathMatchedListeners = [];
      this._errorListeners = [];
      this._clarinet = clarinetParser;

      this._listenForSaxEvents(clarinetParser)
   }

   OboeParser.prototype._listenForSaxEvents = function( clarinet ) {

      var   oboeInstance = this
      ,     curNode
      ,     curKey
      ,     nodeStack = [] // TODO: use fastlist
      ,     pathStack = [];

      clarinet.onkey = function (nextKey) {
         oboeInstance._notifyListeners(oboeInstance._pathMatchedListeners, null, pathStack.concat(nextKey), nodeStack);

         curKey = nextKey;
      };

      function entityFound( thingFound, foundIn ) {

         var foundInArray = isArray(foundIn);

         if( foundInArray ) {
            // for arrays we aren't pre-warned of the coming paths (there is no call to onkey like there is for objects)
            // so we need to notify of the paths when we find the items:
            oboeInstance._notifyListeners(oboeInstance._pathMatchedListeners, curNode, pathStack.concat(curKey), nodeStack);
         }

         foundIn[curKey] = thingFound;

         pathStack.push(curKey);
      }

      /**
       * implementation of onopenobject and onopenarray
       * */
      function onOpen( newObject, firstKey, hasKnownContents ) {

         var openedObjectIsRoot = !curNode,
             parentNode = curNode;

         curNode = newObject;

         if( openedObjectIsRoot ) {

            // Parsed the root object. Notify path listeners (eg to '!' or '*') that the root object has been found:
            oboeInstance._notifyListeners(oboeInstance._pathMatchedListeners, curNode, pathStack, nodeStack);

         } else {

            // found some object other than the root object. no new path to notify of for this object because
            // should have already been notified.
            //parentNode[curKey] = curNode;

            entityFound(newObject, parentNode);
         }

         nodeStack.push(curNode);

         // We know the first key of the newly parsed object. Notify that path has been found but don't put firstKey
         // perminantly onto pathStack yet because we haven't identified what is at that key yet. We also give null
         // as the curNode because we've only so far seen the key, not the node.
         // If the entity just opened is an empty object or an array, there are no known contents so this will not be
         // notified here. For non-empty arrays the paths will have to be notified in the following calls to
         // onvalue or onopenfoo.
         if( hasKnownContents ) {
            oboeInstance._notifyListeners(oboeInstance._pathMatchedListeners, null, pathStack.concat(firstKey), nodeStack);
         }

         // clarinet always gives the first key of the new object.
         curKey = firstKey;
      }

      clarinet.onopenobject = function (firstKey) {

         onOpen({}, firstKey, firstKey !== undefined);
      };

      clarinet.onopenarray = function () {

         onOpen([], 0, false);
      };

      function entityFinished( thingFound) {

         oboeInstance._notifyListeners(oboeInstance._thingFoundListeners, thingFound, pathStack, nodeStack);

         if( isArray(curNode) ) {
            // we're going back to an array, the curKey (the key the next item will be given) needs to match
            // the length of that array:
            curKey = curNode.length;
         } else {
            // we're in an object, curKey has been used now and we don't know what the next key will
            // be so mark as null:
            curKey = null;
         }

         pathStack.pop();
      }

      clarinet.onvalue = function (value) {
         // Called for strings, numbers, boolean, null etc. These are found and finished at once since they can't have
         // ancestors.

         entityFound(value, curNode);

         entityFinished(value);
      };

      clarinet.onend =
      clarinet.oncloseobject =
      clarinet.onclosearray = function () {

         // pop the curNode off the nodestack because curNode is the thing we just
         // identified and it shouldn't be listed as an ancestor of itself:
         var closedItem = curNode;

         // go up one level in the parsed json's tree
         nodeStack.pop();
         curNode = lastOf(nodeStack);

         entityFinished(closedItem);
      };

      clarinet.onerror = function(e) {
         oboeInstance._notifyErrors(e);

         // after parse errors the json is invalid so, we won't bother trying to recover, so just give up
         oboeInstance.close();
      };
   };

   OboeParser.prototype.fetch = function(url) {

      // TODO: in if in node, use require('http') instead of ajax

      streamingXhr.fetch(
         url,
         this.read.bind(this),
         this.close.bind(this) );

      return this;
   };

   /**
    * notify any of the listeners that are interested in the path.
    */
   OboeParser.prototype._notifyListeners = function ( listenerList, curNode, path, ancestors ) {

      var nodeList = ancestors.concat([curNode]);

      listenerList
         .forEach( function(listener) {

            var foundNode = listener.test( path, nodeList );

            // possible values for foundNode now:
            //
            //    false:
            //       we did not match
            //    an object/array/string/number:
            //       that node is the one that matched
            //    null: like above, but we don't have the node yet. ie, we know there is a
            //          node that matches but we don't know if it is an array, object, string
            //          etc yet so we can't say anything about it

            if( foundNode !== false ) {
               var context = listener.context || window;

               // change curNode to foundNode when it stops breaking tests
               try{
                  listener.callback.call(context, foundNode, path, ancestors );
               } catch(e) {
                  this._notifyErrors(Error('Error thrown by callback ' + e.message));
               }
            }
         }, this);
   };

   OboeParser.prototype._notifyErrors = function(error) {
      this._errorListeners.forEach( function( listener ) {
         listener(error);
      });
   };

   /**
    * called when there is new text to parse
    *
    * @param {String} nextDrip
    */
   OboeParser.prototype.read = function (nextDrip) {
      if( this.closed ) {
         throw Error('closed');
      }

      try {
         this._clarinet.write(nextDrip);
      } catch(e) {
         // we don't have to do anything here because we always assign a .onerror
         // to clarinet which will have already been called by the time this
         // exception is thrown.
      }
   };

   /**
    * called when the input is done
    *
    */
   OboeParser.prototype.close = function () {
      this.closed = true;

      // we won't fire any more events again so forget our listeners:
      this._thingFoundListeners = [];
      this._pathMatchedListeners = [];
      this._errorListeners = [];

      var clarinet = this._clarinet;

      // quit listening to clarinet as well. We've done with this stream:
      clarinet.onkey =
      clarinet.onvalue =
      clarinet.onopenobject =
      clarinet.onopenarray =
      clarinet.onend =
      clarinet.oncloseobject =
      clarinet.onclosearray =
      clarinet.onerror = null;

      clarinet.close();
   };

   /**
    * @returns {*} an identifier that can later be used to de-register this listener
    */
   function pushListener(listenerList, pattern, callback, context) {
      return listenerList.push({
         pattern:pattern,
         test: jsonPathCompiler(pattern),
         callback: callback,
         context: context
      });
   }

   /**
    *
    * @param listenerMap
    */
   function pushListeners(listenerList, listenerMap) {
      for( var path in listenerMap ) {
         pushListener(listenerList, path, listenerMap[path]);
      }
   }

   function on(listenerList, jsonPath, callback, context) {
      if( typeof jsonPath === 'string' ) {
         pushListener(listenerList, jsonPath, callback, context);
      } else {
         pushListeners(listenerList, jsonPath);
      }
   }

   /**
    * Add a new json path to the parser, to be called as soon as the path is found, but before we know
    * what value will be in there.
    *
    * @param {String} jsonPath
    *    The jsonPath is a variant of JSONPath patterns and supports these special meanings.
    *    See http://goessner.net/articles/JsonPath/
    *          !                - root json object
    *          .                - path separator
    *          foo              - path node 'foo'
    *          ['foo']          - paFth node 'foo'
    *          [1]              - path node '1' (only for numbers indexes, usually arrays)
    *          *                - wildcard - all objects/properties
    *          ..               - any number of intermediate nodes (non-greedy)
    *          [*]              - equivalent to .*
    *
    * @param {Function} callback({Object}foundNode, {String[]}path, {Object[]}ancestors)
    *
    * @param {Object} [context] the context ('this') for the callback
    */
   OboeParser.prototype.onPath = function (jsonPath, callback, context) {

      on(this._pathMatchedListeners, jsonPath, callback, context);
      return this;
   };

   /**
    * Add a new json path to the parser, which will be called when a value is found at the given path
    *
    * @param {String} jsonPath supports the same syntax as .onPath.
    *
    * @param {Function} callback({Object}foundNode, {String[]}path, {Object[]}ancestors)
    * @param {Object} [context] the context ('this') for the callback
    */
   OboeParser.prototype.onFind = function (jsonPath, callback, context) {

      on(this._thingFoundListeners, jsonPath, callback, context);
      return this;
   };

   /**
    * Add a new json path to the parser, which will be called when a value is found at the given path
    *
    * @param {Function} callback
    */
   OboeParser.prototype.onError = function (callback) {

      this._errorListeners.push(callback);
      return this;
   };

   return oboe;

})( typeof exports === "undefined" ? {} : exports );<commit_msg>more extraction in core oboe<commit_after>
var oboe = (function(oboe){
   "use strict";

   /**
    * @param {Object} opt an object of options. Passed though
    * directly to clarinet.js but oboe.js does not
    * currently provide options.
    */
   oboe.parser = function(opt){
      return new OboeParser(opt);
   };

   /**
    * Convenient alias. Creates a new parser, starts an ajax request and returns the parser
    * ready to call .onPath() or .onFind() to register some callbacks
    * @param url
    */
   oboe.fetch = function(url){
      return new OboeParser().fetch(url);
   };

   function OboeParser(opt) {

      var clarinetParser = clarinet.parser(opt);

      this._thingFoundListeners = [];
      this._pathMatchedListeners = [];
      this._errorListeners = [];
      this._clarinet = clarinetParser;

      this._listenForSaxEvents(clarinetParser)
   }

   OboeParser.prototype._listenForSaxEvents = function( clarinet ) {

      var   oboeInstance = this
      ,     curNode
      ,     curKey
      ,     nodeStack = [] // TODO: use fastlist
      ,     pathStack = [];

      /* For when we find a new key in the json. The value may not be known in which case null can be given */
      function notifyOfKeyFound(key, value) {
         oboeInstance._notifyListeners(oboeInstance._pathMatchedListeners, value, pathStack.concat(key), nodeStack);
      }

      clarinet.onkey = function (nextKey) {
         // called by Clarinet when keys are found in objects

         notifyOfKeyFound(nextKey, null);

         curKey = nextKey;
      };

      function entityFound( thingFound, foundIn, foundAtKey ) {

         var thingIsRoot = !foundIn;

         if( isArray(foundIn) ) {
            // for arrays we aren't pre-warned of the coming paths (there is no call to onkey like there is for objects)
            // so we need to notify of the paths when we find the items:
            notifyOfKeyFound(curKey, thingFound);
         }

         if( thingIsRoot ) {
            // Parsed the root object. Notify path listeners (eg to '!' or '*') that the root path has been satisfied:
            oboeInstance._notifyListeners(oboeInstance._pathMatchedListeners, thingFound, pathStack, nodeStack);
         }

         if( !thingIsRoot ) {
            foundIn[curKey] = thingFound;
            pathStack.push(curKey);
         }

         curKey = foundAtKey;
      }

      /**
       * implementation of onopenobject and onopenarray
       * */
      function onOpen( newObject, firstKey, hasKnownContents ) {

         var parentNode = curNode;

         // found some object other than the root object. no new path to notify of for this object because
         // should have already been notified.
         //parentNode[curKey] = curNode;
         entityFound(newObject, parentNode, firstKey);

         curNode = newObject;
         nodeStack.push(curNode);

         // We know the first key of the newly parsed object. Notify that path has been found but don't put firstKey
         // perminantly onto pathStack yet because we haven't identified what is at that key yet. We also give null
         // as the curNode because we've only so far seen the key, not the node.
         // If the entity just opened is an empty object or an array, there are no known contents so this will not be
         // notified here. For non-empty arrays the paths will have to be notified in the following calls to
         // onvalue or onopenfoo.
         if( hasKnownContents ) {
            oboeInstance._notifyListeners(oboeInstance._pathMatchedListeners, null, pathStack.concat(firstKey), nodeStack);
         }
      }

      clarinet.onopenobject = function (firstKey) {

         onOpen({}, firstKey, firstKey !== undefined);
      };

      clarinet.onopenarray = function () {

         onOpen([], 0, false);
      };

      function entityFinished( thingFound) {

         oboeInstance._notifyListeners(oboeInstance._thingFoundListeners, thingFound, pathStack, nodeStack);

         if( isArray(curNode) ) {
            // we're going back to an array, the curKey (the key the next item will be given) needs to match
            // the length of that array:
            curKey = curNode.length;
         } else {
            // we're in an object, curKey has been used now and we don't know what the next key will
            // be so mark as null:
            curKey = null;
         }

         pathStack.pop();
      }

      clarinet.onvalue = function (value) {
         // Called for strings, numbers, boolean, null etc. These are found and finished at once since they can't have
         // ancestors.

         entityFound(value, curNode, curKey);

         entityFinished(value);
      };

      clarinet.onend =
      clarinet.oncloseobject =
      clarinet.onclosearray = function () {

         // pop the curNode off the nodestack because curNode is the thing we just
         // identified and it shouldn't be listed as an ancestor of itself:
         var closedItem = curNode;

         // go up one level in the parsed json's tree
         nodeStack.pop();
         curNode = lastOf(nodeStack);

         entityFinished(closedItem);
      };

      clarinet.onerror = function(e) {
         oboeInstance._notifyErrors(e);

         // after parse errors the json is invalid so, we won't bother trying to recover, so just give up
         oboeInstance.close();
      };
   };

   OboeParser.prototype.fetch = function(url) {

      // TODO: in if in node, use require('http') instead of ajax

      streamingXhr.fetch(
         url,
         this.read.bind(this),
         this.close.bind(this) );

      return this;
   };

   /**
    * notify any of the listeners that are interested in the path.
    */
   OboeParser.prototype._notifyListeners = function ( listenerList, node, path, ancestors ) {

      var nodeList = ancestors.concat([node]);

      listenerList
         .forEach( function(listener) {

            var foundNode = listener.test( path, nodeList );

            // possible values for foundNode now:
            //
            //    false:
            //       we did not match
            //    an object/array/string/number:
            //       that node is the one that matched
            //    null: like above, but we don't have the node yet. ie, we know there is a
            //          node that matches but we don't know if it is an array, object, string
            //          etc yet so we can't say anything about it

            if( foundNode !== false ) {
               var context = listener.context || window;

               // change curNode to foundNode when it stops breaking tests
               try{
                  listener.callback.call(context, foundNode, path, ancestors );
               } catch(e) {
                  this._notifyErrors(Error('Error thrown by callback ' + e.message));
               }
            }
         }, this);
   };

   OboeParser.prototype._notifyErrors = function(error) {
      this._errorListeners.forEach( function( listener ) {
         listener(error);
      });
   };

   /**
    * called when there is new text to parse
    *
    * @param {String} nextDrip
    */
   OboeParser.prototype.read = function (nextDrip) {
      if( this.closed ) {
         throw Error('closed');
      }

      try {
         this._clarinet.write(nextDrip);
      } catch(e) {
         // we don't have to do anything here because we always assign a .onerror
         // to clarinet which will have already been called by the time this
         // exception is thrown.
      }
   };

   /**
    * called when the input is done
    *
    */
   OboeParser.prototype.close = function () {
      this.closed = true;

      // we won't fire any more events again so forget our listeners:
      this._thingFoundListeners = [];
      this._pathMatchedListeners = [];
      this._errorListeners = [];

      var clarinet = this._clarinet;

      // quit listening to clarinet as well. We've done with this stream:
      clarinet.onkey =
      clarinet.onvalue =
      clarinet.onopenobject =
      clarinet.onopenarray =
      clarinet.onend =
      clarinet.oncloseobject =
      clarinet.onclosearray =
      clarinet.onerror = null;

      clarinet.close();
   };

   /**
    * @returns {*} an identifier that can later be used to de-register this listener
    */
   function pushListener(listenerList, pattern, callback, context) {
      return listenerList.push({
         pattern:pattern,
         test: jsonPathCompiler(pattern),
         callback: callback,
         context: context
      });
   }

   /**
    *
    * @param listenerMap
    */
   function pushListeners(listenerList, listenerMap) {
      for( var path in listenerMap ) {
         pushListener(listenerList, path, listenerMap[path]);
      }
   }

   function on(listenerList, jsonPath, callback, context) {
      if( typeof jsonPath === 'string' ) {
         pushListener(listenerList, jsonPath, callback, context);
      } else {
         pushListeners(listenerList, jsonPath);
      }
   }

   /**
    * Add a new json path to the parser, to be called as soon as the path is found, but before we know
    * what value will be in there.
    *
    * @param {String} jsonPath
    *    The jsonPath is a variant of JSONPath patterns and supports these special meanings.
    *    See http://goessner.net/articles/JsonPath/
    *          !                - root json object
    *          .                - path separator
    *          foo              - path node 'foo'
    *          ['foo']          - paFth node 'foo'
    *          [1]              - path node '1' (only for numbers indexes, usually arrays)
    *          *                - wildcard - all objects/properties
    *          ..               - any number of intermediate nodes (non-greedy)
    *          [*]              - equivalent to .*
    *
    * @param {Function} callback({Object}foundNode, {String[]}path, {Object[]}ancestors)
    *
    * @param {Object} [context] the context ('this') for the callback
    */
   OboeParser.prototype.onPath = function (jsonPath, callback, context) {

      on(this._pathMatchedListeners, jsonPath, callback, context);
      return this;
   };

   /**
    * Add a new json path to the parser, which will be called when a value is found at the given path
    *
    * @param {String} jsonPath supports the same syntax as .onPath.
    *
    * @param {Function} callback({Object}foundNode, {String[]}path, {Object[]}ancestors)
    * @param {Object} [context] the context ('this') for the callback
    */
   OboeParser.prototype.onFind = function (jsonPath, callback, context) {

      on(this._thingFoundListeners, jsonPath, callback, context);
      return this;
   };

   /**
    * Add a new json path to the parser, which will be called when a value is found at the given path
    *
    * @param {Function} callback
    */
   OboeParser.prototype.onError = function (callback) {

      this._errorListeners.push(callback);
      return this;
   };

   return oboe;

})( typeof exports === "undefined" ? {} : exports );<|endoftext|>


<commit_before>var OEIS = new Object();

OEIS.proxy = "http://crossorigin.me/";
OEIS.endpoint = OEIS.proxy + "http://oeis.org/";
OEIS.lastRequest = "";

OEIS.searchByID = function (id, format, callback) {
    URL = OEIS.endpoint + "search?" + "q=" + "id:A" + id + "&" + "fmt=" + format;
    OEIS.doRequest(URL, callback);
};

OEIS.searchByTerms = function (terms, format, callback) {
    URL = OEIS.endpoint + "search?" + "q=" + terms.toString() + "&" + "fmt=" + format;
    OEIS.doRequest(URL, callback);
}

OEIS.createCORSRequest = function (method, url) {
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr) {

        // Check if the XMLHttpRequest object has a "withCredentials" property.
        // "withCredentials" only exists on XMLHTTPRequest2 objects.
        xhr.open(method, url, true);

    } else if (typeof XDomainRequest != "undefined") {

        // Otherwise, check if XDomainRequest.
        // XDomainRequest only exists in IE, and is IE's way of making CORS requests.
        xhr = new XDomainRequest();
        xhr.open(method, url);

    } else {

        // Otherwise, CORS is not supported by the browser.
        xhr = null;

    }
    return xhr;
};

OEIS.doRequest = function (URL, callback) {
    var xhr = OEIS.createCORSRequest("GET", URL);
    if (!xhr) {
        throw new Error('CORS not supported');
    }
    xhr.onload = function() {
        OEIS.lastRequest = xhr.responseText;
        if (callback) {
            callback(xhr.responseText);
        }
    };
    xhr.send();
};
<commit_msg>Added attribution to www.html5rocks.com for CORS code<commit_after>var OEIS = new Object();

OEIS.proxy = "http://crossorigin.me/";
OEIS.endpoint = OEIS.proxy + "http://oeis.org/";
OEIS.lastRequest = "";

OEIS.searchByID = function (id, format, callback) {
    URL = OEIS.endpoint + "search?" + "q=" + "id:A" + id + "&" + "fmt=" + format;
    OEIS.doRequest(URL, callback);
};

OEIS.searchByTerms = function (terms, format, callback) {
    URL = OEIS.endpoint + "search?" + "q=" + terms.toString() + "&" + "fmt=" + format;
    OEIS.doRequest(URL, callback);
}

// Based heavily on code found on www.html5rocks.com by
// Monsur Hossain.
// https://www.html5rocks.com/en/tutorials/cors/
OEIS.createCORSRequest = function (method, url) {
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr) {

        // Check if the XMLHttpRequest object has a "withCredentials" property.
        // "withCredentials" only exists on XMLHTTPRequest2 objects.
        xhr.open(method, url, true);

    } else if (typeof XDomainRequest != "undefined") {

        // Otherwise, check if XDomainRequest.
        // XDomainRequest only exists in IE, and is IE's way of making CORS requests.
        xhr = new XDomainRequest();
        xhr.open(method, url);

    } else {

        // Otherwise, CORS is not supported by the browser.
        xhr = null;

    }
    return xhr;
};

OEIS.doRequest = function (URL, callback) {
    var xhr = OEIS.createCORSRequest("GET", URL);
    if (!xhr) {
        throw new Error('CORS not supported');
    }
    xhr.onload = function() {
        OEIS.lastRequest = xhr.responseText;
        if (callback) {
            callback(xhr.responseText);
        }
    };
    xhr.send();
};
<|endoftext|>


<commit_before>var Todo = {
  base: function(content) {
    this.content = content;
    return this;
  },
  done: function() {
    this.done = true;
  },
  notDone: function() {
    this.done = false;
  }
};

var TodoWithUser = Object.create(Todo);

TodoWithUser.SetUser = function(user) {
  this.user = user;
};

//------------------- Douglas Crackford

function Todo(spec) {
  let { member } = spec, //destructuring
      { other } = baseCtor(spec),
      method = function() {
          // member, other, methid, spec
      };

  return Object.freeze({
      method,
      other
  });
}
<commit_msg>removed oloo.js<commit_after><|endoftext|>


<commit_before>import SocketIO from 'socket.io';
import { createClient } from 'redis';

import { redisUrl } from './config';

const io = SocketIO();

io.use((socket, next) => {
  return next();
});

io.of('/live-chatroom')
  .use((socket, next) => {
    return next();
  })
  .on('connection', (socket) => {
    const redis = createClient(redisUrl);
    let currentRoom = '';

    socket.on('subscribe', (id) => {
      currentRoom = `live:${id}:comments`;
      socket.join(currentRoom);

      redis.subscribe(`${currentRoom}:latest`);

      redis.exists('live', id, (err, result) => {
        if (result < 2) {
          redis.lpush('live', id);
        }
      });

      socket.emit('subscribed');
    });

    redis.on('message', (channel, message) => {
      socket.emit('comment', message);
    });

    socket.on('unsubscribe', (id) => {
      socket.leave(id);
      socket.emit('unsubscribed');
    });

    socket.on('disconnect', () => {
      redis.unsubscribe(`${currentRoom}:latest`);
      redis.quit();
    })
  });

export default io;<commit_msg>Fix redis error => If redis client subscribed a key, it cannot run another commands.<commit_after>import SocketIO from 'socket.io';
import { createClient } from 'redis';

import { redisUrl } from './config';

const io = SocketIO();

io.use((socket, next) => {
  return next();
});

io.of('/live-chatroom')
  .use((socket, next) => {
    return next();
  })
  .on('connection', (socket) => {
    const redisSubscriber = createClient(redisUrl);
    let currentRoom = '';

    socket.on('subscribe', (id) => {
      currentRoom = `live:${id}:comments`;
      socket.join(currentRoom);

      redisSubscriber.subscribe(`${currentRoom}:latest`);

      const redis = createClient(redisUrl);
      redis.exists('live', id, (err, result) => {
        if (result < 2) {
          redis.lpush('live', id);
        }
      });
      redis.quit();

      socket.emit('subscribed');
    });

    redisSubscriber.on('message', (channel, message) => {
      socket.emit('comment', message);
    });

    socket.on('unsubscribe', (id) => {
      socket.leave(id);
      socket.emit('unsubscribed');
    });

    socket.on('disconnect', () => {
      redisSubscriber.unsubscribe(`${currentRoom}:latest`);
      redisSubscriber.quit();
    })
  });

export default io;<|endoftext|>


<commit_before>export default function(socketRetryInterceptorProvider, socketCacheBusterProvider) {
  'ngInject';
  var WS_PREF;

  this.setApiEndpoint = setApiEndpoint;

  function setApiEndpoint(endpoint) {
    WS_PREF = endpoint;
    socketRetryInterceptorProvider.setApiEndpoint(endpoint);
    socketCacheBusterProvider.setApiEndpoint(endpoint);
  }

  this.$get = function socket($rootScope,
                              $log,
                              $location,
                              $http,
                              $q) {
    'ngInject';

    var allSockets = {};

    var handleErr = function handleErr(data) {
      var err = data && data.err;

      if (err) {
        return $log.error(err);
      }
    };

    function SocketDefer() {

      var deferred = $q.defer();
      var promise = deferred.promise;
      promise['catch'](handleErr);

      return deferred;
    }

    function Or2ComboSocket(namespace, rootKey, rootKeyPlural) {

      this.namespace = namespace;
      this.rootKey = rootKey;
      this.rootKeyPlural = rootKeyPlural;
      this.endpoint = WS_PREF + this.namespace;
      this.handlers = {};

      var self = this;

      this.query = function query(qryObj) {

        var deferred = SocketDefer();
        var params = {
          _idsonly: true,
          _spaging: true
        };

        // Explicitly stringify the queryObj here because we don't want angular removing
        // any of our keys (they're likely to have '$' in them)
        var req = $http.post(this.endpoint + '/query', JSON.stringify(qryObj), {
          params: params
        });

        req.then(function({data, status: statusCode}) {

          // A statusCode of 0 or lower means (essentially) we're offline. Resolve as successful
          // but with no data
          if (statusCode <= 0) {
            deferred.resolve();
            return;
          } else if (statusCode !== 200) {
            deferred.reject(data);
            return;
          }

          var ids = data[self.rootKeyPlural];

          var pagingOpts = {
            next: data.next,
            prev: data.prev
          };

          return deferred.resolve({
            data:  {
              ids: ids,
              pagingOpts: pagingOpts
            }
          });
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.get = function get(ids) {
        var params, req;

        var deferred = SocketDefer();

        if (Array.isArray(ids)) {
          params = {};

          req = $http.post(this.endpoint + '/bulk', {
            ids: ids
          }, {
            params: params
          });

          req.then(function({data: resdata, status: statusCode}) {

            // A statusCode of 0 or lower means (essentially) we're offline. Resolve as successful
            // but with no data
            if (statusCode <= 0) {
              deferred.resolve();
              return;
            } else if (statusCode !== 200) {
              deferred.reject(resdata);
              return;
            }

            var data = resdata[self.rootKeyPlural];
            deferred.resolve(data);
          }).catch(function(err) {
            deferred.reject(err);
          });
        } else {
          var id = ids;
          params = {};

          req = $http.get(this.endpoint + '/' + id, {
            params: params
          });

          req.then(function success({data: resdata, status: statusCode}) {

            // A statusCode of 0 or lower means (essentially) we're offline. Resolve as successful
            // but with no data
            if (statusCode <= 0) {
              deferred.resolve();
              return;
            } else if (statusCode !== 200) {
              deferred.reject(resdata);
              return;
            }

            var data = resdata[self.rootKey];
            deferred.resolve(data);
          }).catch(function(err) {
            deferred.reject(err);
          });
        }

        return deferred.promise;
      };

      this.create = function create(data) {

        var deferred = SocketDefer();
        var params = {};
        var payload = {};

        payload[this.rootKey] = data;

        var req = $http.post(this.endpoint, payload, {
          params: params
        });

        req.then(function success({data: resdata, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(resdata);
            return;
          }

          data = resdata[self.rootKey];
          deferred.resolve(data);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.patch = function patch(id, patchData) {
        var deferred = SocketDefer();
        var payload = {};
        var params = {};

        payload[this.rootKey] = patchData;

        var req = $http.patch(this.endpoint + '/' + id, payload, {
          params: params
        });

        req.then(function({data: response, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(response);
            return;
          }

          var data = response[self.rootKey];
          deferred.resolve(data);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.update = function update(id, data) {

        var deferred = SocketDefer();
        var payload = {};
        var params = {};

        payload[this.rootKey] = data;

        var req = $http.post(this.endpoint + '/' + id, payload, {
          params: params
        });

        req.then(function({data: response, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(response);
            return;
          }

          data = response[self.rootKey];
          deferred.resolve(data);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.remove = function remove(id) {
        var deferred = SocketDefer();
        var params = {};

        var req = $http['delete'](this.endpoint + '/' + id, {
          params: params
        });

        req.then(function({data, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(data);
            return;
          }

          deferred.resolve(data.success);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };
    }

    // Create the socket factory
    function SocketFactory(namespace, rootKey, rootKeyPlural) {
      // Have we already got one for this namespace?
      if (!allSockets[rootKey]) {
        allSockets[rootKey] = new Or2ComboSocket(namespace, rootKey, rootKeyPlural);
      }

      return allSockets[rootKey];
    }

    return SocketFactory;

  };

}
<commit_msg>remove all references to cachebusting<commit_after>export default function(socketRetryInterceptorProvider) {
  'ngInject';
  var WS_PREF;

  this.setApiEndpoint = setApiEndpoint;

  function setApiEndpoint(endpoint) {
    WS_PREF = endpoint;
    socketRetryInterceptorProvider.setApiEndpoint(endpoint);
  }

  this.$get = function socket($rootScope,
                              $log,
                              $location,
                              $http,
                              $q) {
    'ngInject';

    var allSockets = {};

    var handleErr = function handleErr(data) {
      var err = data && data.err;

      if (err) {
        return $log.error(err);
      }
    };

    function SocketDefer() {

      var deferred = $q.defer();
      var promise = deferred.promise;
      promise['catch'](handleErr);

      return deferred;
    }

    function Or2ComboSocket(namespace, rootKey, rootKeyPlural) {

      this.namespace = namespace;
      this.rootKey = rootKey;
      this.rootKeyPlural = rootKeyPlural;
      this.endpoint = WS_PREF + this.namespace;
      this.handlers = {};

      var self = this;

      this.query = function query(qryObj) {

        var deferred = SocketDefer();
        var params = {
          _idsonly: true,
          _spaging: true
        };

        // Explicitly stringify the queryObj here because we don't want angular removing
        // any of our keys (they're likely to have '$' in them)
        var req = $http.post(this.endpoint + '/query', JSON.stringify(qryObj), {
          params: params
        });

        req.then(function({data, status: statusCode}) {

          // A statusCode of 0 or lower means (essentially) we're offline. Resolve as successful
          // but with no data
          if (statusCode <= 0) {
            deferred.resolve();
            return;
          } else if (statusCode !== 200) {
            deferred.reject(data);
            return;
          }

          var ids = data[self.rootKeyPlural];

          var pagingOpts = {
            next: data.next,
            prev: data.prev
          };

          return deferred.resolve({
            data:  {
              ids: ids,
              pagingOpts: pagingOpts
            }
          });
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.get = function get(ids) {
        var params, req;

        var deferred = SocketDefer();

        if (Array.isArray(ids)) {
          params = {};

          req = $http.post(this.endpoint + '/bulk', {
            ids: ids
          }, {
            params: params
          });

          req.then(function({data: resdata, status: statusCode}) {

            // A statusCode of 0 or lower means (essentially) we're offline. Resolve as successful
            // but with no data
            if (statusCode <= 0) {
              deferred.resolve();
              return;
            } else if (statusCode !== 200) {
              deferred.reject(resdata);
              return;
            }

            var data = resdata[self.rootKeyPlural];
            deferred.resolve(data);
          }).catch(function(err) {
            deferred.reject(err);
          });
        } else {
          var id = ids;
          params = {};

          req = $http.get(this.endpoint + '/' + id, {
            params: params
          });

          req.then(function success({data: resdata, status: statusCode}) {

            // A statusCode of 0 or lower means (essentially) we're offline. Resolve as successful
            // but with no data
            if (statusCode <= 0) {
              deferred.resolve();
              return;
            } else if (statusCode !== 200) {
              deferred.reject(resdata);
              return;
            }

            var data = resdata[self.rootKey];
            deferred.resolve(data);
          }).catch(function(err) {
            deferred.reject(err);
          });
        }

        return deferred.promise;
      };

      this.create = function create(data) {

        var deferred = SocketDefer();
        var params = {};
        var payload = {};

        payload[this.rootKey] = data;

        var req = $http.post(this.endpoint, payload, {
          params: params
        });

        req.then(function success({data: resdata, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(resdata);
            return;
          }

          data = resdata[self.rootKey];
          deferred.resolve(data);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.patch = function patch(id, patchData) {
        var deferred = SocketDefer();
        var payload = {};
        var params = {};

        payload[this.rootKey] = patchData;

        var req = $http.patch(this.endpoint + '/' + id, payload, {
          params: params
        });

        req.then(function({data: response, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(response);
            return;
          }

          var data = response[self.rootKey];
          deferred.resolve(data);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.update = function update(id, data) {

        var deferred = SocketDefer();
        var payload = {};
        var params = {};

        payload[this.rootKey] = data;

        var req = $http.post(this.endpoint + '/' + id, payload, {
          params: params
        });

        req.then(function({data: response, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(response);
            return;
          }

          data = response[self.rootKey];
          deferred.resolve(data);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };

      this.remove = function remove(id) {
        var deferred = SocketDefer();
        var params = {};

        var req = $http['delete'](this.endpoint + '/' + id, {
          params: params
        });

        req.then(function({data, status: statusCode}) {

          if (statusCode !== 200) {
            deferred.reject(data);
            return;
          }

          deferred.resolve(data.success);
        }).catch(function(err) {
          deferred.reject(err);
        });

        return deferred.promise;
      };
    }

    // Create the socket factory
    function SocketFactory(namespace, rootKey, rootKeyPlural) {
      // Have we already got one for this namespace?
      if (!allSockets[rootKey]) {
        allSockets[rootKey] = new Or2ComboSocket(namespace, rootKey, rootKeyPlural);
      }

      return allSockets[rootKey];
    }

    return SocketFactory;

  };

}
<|endoftext|>


<commit_before>/**
 * Controller for the search tab. pops in sub controllers for geographic/cultural/etc
 *
 * @param $scope
 * @param colorMapService
 * @param searchModelService
 * @param FindSocieties
 * @constructor
 */
function SearchCtrl($scope, colorMapService, searchModelService, FindSocieties) {
    $scope.setActive('search');
    $scope.searchModel = searchModelService.getModel();
    $scope.selectedButton = $scope.searchModel.selectedButton;
    var rP = 'radioPlaces';
    var rL = 'radioLanguage';
    var rC = 'radioCulture';
    var rE = 'radioEnv';
    // preserve active button style if any
    if($scope.selectedButton) {
        switch($scope.selectedButton.radioClass) {
        case 'radioPlaces':
            rP += ' active';
            break;
        case 'radioLanguage':
            rL += ' active';
            break;
        case 'radioCulture':
            rC += ' active';
            break;
        case 'radioEnv':
            rE += ' active';
            break;
        }
    }
    $scope.buttons = [
        {radioClass: rP, value:'geographic', name:'PLACES', badgeValue:
            function() { return $scope.searchModel.getGeographicRegions().badgeValue; }
        },
        {radioClass: rL, value:'language', name:'LANGUAGE', badgeValue:
            function() { return $scope.searchModel.getLanguageClassifications().badgeValue; }
        },
        {radioClass: rC, value:'cultural', name:'CULTURE', badgeValue:
            function() { return $scope.searchModel.getCulturalTraits().badgeValue; }
        },
        {radioClass: rE, value:'environmental', name:'ENVIRONMENT', badgeValue:
            function() { return $scope.searchModel.getEnvironmentalData().badgeValue; }
        }
    ];

    $scope.buttonChanged = function(selectedButton) {
        $scope.selectedButton = selectedButton;
        $scope.searchModel.selectedButton = selectedButton;
    };

    // All of this needs to move into model
    $scope.disableSearchButton = function () {
        $scope.searchButton.disabled = true;
        $scope.searchButton.text = 'Working...';
    };

    $scope.enableSearchButton = function () {
        $scope.searchButton.disabled = false;
        $scope.searchButton.text = 'Search';
    };

    $scope.isEmpty = function(object) {
        for (var key in object) {
            if (object[key].length > 0)
                return false;
        }
        return true;
    };
    $scope.searchCriteria = "View my selected search criteria";

    $scope.showCriteria = function() {
        $("#selected-criteria").toggleClass('hidden');
        $("#search-panel").toggleClass('col-md-9', 'col-md-12');
    };

    $scope.checkIfSelected = function() {
        if ($scope.searchModel.getGeographicRegions().selectedRegions.length > 0) return true;
        if ($scope.searchModel.getEnvironmentalData().selectedVariables.length > 0) return true;
        if (!$scope.isEmpty($scope.searchModel.getCulturalTraits().selected)) return true;
        if (!$scope.isEmpty($scope.searchModel.getLanguageClassifications().selected)) return true;
        return false;
    }

    //removes a variable, language, or region from search parameters
    $scope.removeFromSearch = function(object, searchType) {
        var index = -1;
        switch(searchType) {
            case 'geographic':
                index = $scope.searchModel.getGeographicRegions().selectedRegions.indexOf(object);
                $scope.searchModel.getGeographicRegions().selectedRegions.splice(index, 1);
                $scope.searchModel.getGeographicRegions().badgeValue = $scope.searchModel.getGeographicRegions().selectedRegions.length;
                break;
            case 'environmental':
                index = $scope.searchModel.getEnvironmentalData().selectedVariables.indexOf(object);
                $scope.searchModel.getEnvironmentalData().selectedVariables.splice(index, 1);
                $scope.searchModel.getEnvironmentalData().badgeValue = $scope.searchModel.getEnvironmentalData().selectedVariables.length;
                break;
            case 'language':
                if (object.family.name in $scope.searchModel.getLanguageClassifications().selected) {
                    for (var i = 0; i < $scope.searchModel.getLanguageClassifications().selected[object.family.name].length; i++) {
                        if ($scope.searchModel.getLanguageClassifications().selected[object.family.name][i].id == object.id) {
                            $scope.searchModel.getLanguageClassifications().selected[object.family.name][i].isSelected = false;
                            index = i;
                            break;
                        }
                    }
                    if (index > -1) {
                        $scope.searchModel.getLanguageClassifications().selected[object.family.name].splice(index, 1);
                        $scope.searchModel.getLanguageClassifications().badgeValue--;
                    }
                }
                break;
            case 'culture':
                if (object.variable in $scope.searchModel.getCulturalTraits().selected) {
                    for (var i = 0; i < $scope.searchModel.getCulturalTraits().selected[object.variable].length; i++) {
                        if (($scope.searchModel.getCulturalTraits().selected[object.variable][i].id == object.id) || ($scope.searchModel.getCulturalTraits().selected[object.variable][i].description == object.description)) {
                            $scope.searchModel.getCulturalTraits().selected[object.variable][i].isSelected = false;
                            index = i;
                            break;
                        }
                    }
                    if (index > -1) {
                        $scope.searchModel.getCulturalTraits().selected[object.variable].splice(index, 1);
                        $scope.searchModel.getCulturalTraits().selected[object.variable].allSelected = false;
                        $scope.searchModel.getCulturalTraits().badgeValue--;
                        $scope.$broadcast('variableCheck');
                    }

                }
        }
        if (!$scope.checkIfSelected()) {
            d3.select("#selected-criteria").classed("hidden", true);
            d3.select("#search-panel").classed("col-md-12", true);
            d3.select("#search-panel").classed("col-md-9", false);
        }
    };

    //calculates the range for environmental variables
    //needed for coloring of markers
    $scope.calculateRange = function(results) {
        societies = results.societies;
        for (var i = 0; i < results.environmental_variables.length; i++) {
            extractedValues = societies.map(function(society) {
                for (var j = 0; j < society.environmental_values.length; j++) {
                    if (society.environmental_values[j].variable == results.environmental_variables[i].id) {
                        if (society.environmental_values[j].value) return society.environmental_values[j].value;
                    }
                }
            });
            var min_value = null; var max_value = null;
           extractedValues.forEach(function(val) {
            if (!min_value) min_value = val;
            if (!max_value) max_value = val;

            if (val < min_value) min_value = val;
            if (val > max_value) max_value = val;
           });
            var range = max_value - min_value;
            results.environmental_variables[i]['range'] = range;
            results.environmental_variables[i]['min'] = Math.round(min_value*10000)/10000;
            results.environmental_variables[i]['max'] = Math.round(max_value*10000)/10000;
        }
        return results;
    };

    //calculates number of codes selected for each variable and saves to coded_value
    //needed for coloring of markers
    $scope.getCodeIDs = function() {
        $scope.searchModel.results.code_ids = {};
        if ($scope.searchModel.query.l && !$scope.searchModel.query.c && !$scope.searchModel.query.e) {
            $scope.searchModel.results.classifications = [];
            added = [];
            for (var i = 0; i < $scope.searchModel.results.societies.length; i++) {
                for (var s = 0; s < $scope.searchModel.results.societies[i].languages.length; s++) {
                    language_family = $scope.searchModel.results.societies[i].languages[s].family;
                    if (added.indexOf(language_family.id) == -1) {
                        $scope.searchModel.results.classifications.push(language_family);
                        added.push(language_family.id);
                    }
                }
            }
        }

        for (var i = 0; i < $scope.searchModel.results.variable_descriptions.length; i++) {
            if ($scope.searchModel.results.variable_descriptions[i].variable.data_type.toUpperCase() == 'CONTINUOUS') {
                codes = $scope.searchModel.query.c.filter(function(code) { return code.variable == $scope.searchModel.results.variable_descriptions[i].variable.id; });
                var min;
                var max = 0;

                codes.forEach(function(c_var) {
                    if (!min) {
                        min = c_var.min;
                    } else {
                        if (c_var.min < min) min = c_var.min;
                    }
                    if (c_var.max > max) max = c_var.max;
                });

                $scope.searchModel.results.variable_descriptions[i].variable['min'] = min;
                $scope.searchModel.results.variable_descriptions[i].variable['max'] = max;
                $scope.searchModel.results.variable_descriptions[i].variable['units'] = $scope.searchModel.results.variable_descriptions[i].variable.name.substring($scope.searchModel.results.variable_descriptions[i].variable.name.indexOf('(')+1, $scope.searchModel.results.variable_descriptions[i].variable.name.indexOf(')'));
                $scope.searchModel.results.variable_descriptions[i].codes = codes;
            }

        }
    }

    $scope.assignColors = function() {
        results = $scope.searchModel.getResults();
        results = $scope.calculateRange(results);
        var colorMap = colorMapService.generateColorMap(results);
        $scope.searchModel.getSocieties().forEach(function(container) {
            container.society.style = {'background-color' : colorMap[container.society.id] };
        });
    };

    function addTreesToSocieties() {
        $scope.searchModel.results.language_trees.phylogenies = [];
        $scope.searchModel.results.language_trees.glotto_trees = [];
        $scope.searchModel.results.language_trees.forEach(function(tree) {
            if (tree.name.indexOf("global") != -1) $scope.searchModel.results.language_trees.global_tree = tree;
            else if (tree.name.indexOf("glotto") != -1) {
                $scope.searchModel.results.language_trees.glotto_trees.push(tree);
            }
            else {
                $scope.searchModel.results.language_trees.phylogenies.push(tree);
            }
        $scope.searchModel.results.language_trees.glotto_trees.sort(function(a, b) { return a.name > b.name; });
        $scope.searchModel.results.language_trees.phylogenies.sort(function(a, b) { return a.name > b.name; });
        });
        $scope.searchModel.getSocieties().forEach(function (container) {
            var language = container.society.name;
            if(language != null) {
                container.society.trees = $scope.searchModel.results.language_trees.filter(function (tree) {
                    return tree.taxa.some(function (item) {
                        return item.societies.some(function(label) {
                            return angular.equals(label.society.name, language);
                        });
                    });
                });
            } else {
                container.society.trees = [];
            }
        });
    }

    var errorCallBack = function() {
	$scope.errors = "Invalid input.";
	$scope.enableSearchButton();
    };

    var searchCompletedCallback = function() {
        $scope.enableSearchButton();
        $scope.getCodeIDs();
        $scope.assignColors();
        addTreesToSocieties();
        $scope.searchModel.results.searched = true;
        $scope.switchToResults();
    };

        // This method merges the current searchQuery object with the incoming searchQuery
    $scope.updateSearchQuery = function(searchQuery) {
        $scope.searchModel.query = {};
        for(var propertyName in searchQuery) {
            $scope.searchModel.query[propertyName] = searchQuery[propertyName];
        }
        console.log($scope.searchModel.query);
    };

    $scope.searchSocieties = function() {
        $scope.disableSearchButton();
        var query = $scope.searchModel.query;
        $scope.searchModel.results = FindSocieties.find(query, searchCompletedCallback, errorCallBack);
    };

    $scope.search = function() {
        var i, pruned;
        searchModel = searchModelService.getModel();
        searchParams = searchModel.params;
        searchQuery = {};
        for (var propertyName in searchParams) {
            //get selected cultural traits/codes
            if (propertyName == 'culturalTraits') {
                var codes = [];
                for (var variable in searchParams[propertyName].selected) {
                    searchParams[propertyName].selected[variable].forEach(function(code) { if (code.isSelected) codes.push(code); });
                };
                if (codes.length > 0) {
                    searchQuery['c'] = [];
                    for (i = 0; i < codes.length; i++) {
                        pruned = {variable: codes[i].variable};
                        if ('id' in codes[i]) {
                            pruned['id'] = codes[i].id;
                        }
                        if ('min' in codes[i]) {
                            pruned['min'] = codes[i].min;
                        }
                        if ('max' in codes[i]) {
                            pruned['max'] = codes[i].max;
                        }
                        searchQuery['c'].push(pruned);
                    }
                }
            }
            //get selected regions
            if (propertyName == 'geographicRegions') {
                var selectedRegions = searchParams[propertyName].selectedRegions;
                selectedRegions.forEach(function (selectedRegion) {
                    searchParams[propertyName].allRegions.forEach(function(region) {
                        if (region.tdwg_code == selectedRegion.code)
                            selectedRegion.id = region.id;
                    });
                });
                if (selectedRegions.length > 0) {
                    searchQuery['p'] = [];
                    for (i = 0; i < selectedRegions.length; i++) {
                        searchQuery['p'].push(selectedRegions[i].id);
                    }
                }
            }
            //get selected environmental variable and search parameters
            if (propertyName == 'environmentalData') {
                searchParams[propertyName].selectedVariables.forEach(function(variable) {
                    if (variable.selectedVariable) {
                        filters = [
                            variable.selectedVariable.id,
                            variable.selectedFilter.operator,
                            variable.vals
                        ];
                        if ('e' in searchQuery) {
                            searchQuery['e'].push(filters);
                        } else {
                            searchQuery['e'] = [filters];
                        }
                    }
                });
            }

            //get selected languages
            if (propertyName == 'languageClassifications') {
                var classifications = [];
                for (var family in searchParams[propertyName].selected) {
                    searchParams[propertyName].selected[family].forEach(function(language) { if (language.isSelected) classifications.push(language); });
                }
                if (classifications.length > 0) {
                    searchQuery['l'] = [];
                    for (i = 0; i < classifications.length; i++) {
                        searchQuery['l'].push(classifications[i].id);
                    }
                }
           }
        }
        $scope.updateSearchQuery(searchQuery);
        $scope.searchSocieties();
    };

    // resets this object state and the search query.
    $scope.resetSearch = function() {
		$scope.errors = "";
		$scope.enableSearchButton();
        $scope.searchModel.reset();
        // send a notification so that the individual controllers reload their state
        $scope.$broadcast('searchModelReset');
    };

}<commit_msg>show/hide button text<commit_after>/**
 * Controller for the search tab. pops in sub controllers for geographic/cultural/etc
 *
 * @param $scope
 * @param colorMapService
 * @param searchModelService
 * @param FindSocieties
 * @constructor
 */
function SearchCtrl($scope, colorMapService, searchModelService, FindSocieties) {
    $scope.setActive('search');
    $scope.searchModel = searchModelService.getModel();
    $scope.selectedButton = $scope.searchModel.selectedButton;
    var rP = 'radioPlaces';
    var rL = 'radioLanguage';
    var rC = 'radioCulture';
    var rE = 'radioEnv';
    // preserve active button style if any
    if($scope.selectedButton) {
        switch($scope.selectedButton.radioClass) {
        case 'radioPlaces':
            rP += ' active';
            break;
        case 'radioLanguage':
            rL += ' active';
            break;
        case 'radioCulture':
            rC += ' active';
            break;
        case 'radioEnv':
            rE += ' active';
            break;
        }
    }
    $scope.buttons = [
        {radioClass: rP, value:'geographic', name:'PLACES', badgeValue:
            function() { return $scope.searchModel.getGeographicRegions().badgeValue; }
        },
        {radioClass: rL, value:'language', name:'LANGUAGE', badgeValue:
            function() { return $scope.searchModel.getLanguageClassifications().badgeValue; }
        },
        {radioClass: rC, value:'cultural', name:'CULTURE', badgeValue:
            function() { return $scope.searchModel.getCulturalTraits().badgeValue; }
        },
        {radioClass: rE, value:'environmental', name:'ENVIRONMENT', badgeValue:
            function() { return $scope.searchModel.getEnvironmentalData().badgeValue; }
        }
    ];

    $scope.buttonChanged = function(selectedButton) {
        $scope.selectedButton = selectedButton;
        $scope.searchModel.selectedButton = selectedButton;
    };

    // All of this needs to move into model
    $scope.disableSearchButton = function () {
        $scope.searchButton.disabled = true;
        $scope.searchButton.text = 'Working...';
    };

    $scope.enableSearchButton = function () {
        $scope.searchButton.disabled = false;
        $scope.searchButton.text = 'Search';
    };

    $scope.isEmpty = function(object) {
        for (var key in object) {
            if (object[key].length > 0)
                return false;
        }
        return true;
    };
    $scope.searchCriteria = "View selected search criteria";

    $scope.showCriteria = function() {
        $("#selected-criteria").toggleClass('hidden');
        $("#search-panel").toggleClass('col-md-9', 'col-md-12');

        if (!$("#selected-criteria").hasClass('hidden')) $scope.searchCriteria = "Hide selected search criteria";
        else $scope.searchCriteria = "View selected search criteria";
    };

    $scope.checkIfSelected = function() {
        if ($scope.searchModel.getGeographicRegions().selectedRegions.length > 0) return true;
        if ($scope.searchModel.getEnvironmentalData().selectedVariables.length > 0) return true;
        if (!$scope.isEmpty($scope.searchModel.getCulturalTraits().selected)) return true;
        if (!$scope.isEmpty($scope.searchModel.getLanguageClassifications().selected)) return true;
        return false;
    }

    //removes a variable, language, or region from search parameters
    $scope.removeFromSearch = function(object, searchType) {
        var index = -1;
        switch(searchType) {
            case 'geographic':
                index = $scope.searchModel.getGeographicRegions().selectedRegions.indexOf(object);
                $scope.searchModel.getGeographicRegions().selectedRegions.splice(index, 1);
                $scope.searchModel.getGeographicRegions().badgeValue = $scope.searchModel.getGeographicRegions().selectedRegions.length;
                break;
            case 'environmental':
                index = $scope.searchModel.getEnvironmentalData().selectedVariables.indexOf(object);
                $scope.searchModel.getEnvironmentalData().selectedVariables.splice(index, 1);
                $scope.searchModel.getEnvironmentalData().badgeValue = $scope.searchModel.getEnvironmentalData().selectedVariables.length;
                break;
            case 'language':
                if (object.family.name in $scope.searchModel.getLanguageClassifications().selected) {
                    for (var i = 0; i < $scope.searchModel.getLanguageClassifications().selected[object.family.name].length; i++) {
                        if ($scope.searchModel.getLanguageClassifications().selected[object.family.name][i].id == object.id) {
                            $scope.searchModel.getLanguageClassifications().selected[object.family.name][i].isSelected = false;
                            index = i;
                            break;
                        }
                    }
                    if (index > -1) {
                        $scope.searchModel.getLanguageClassifications().selected[object.family.name].splice(index, 1);
                        $scope.searchModel.getLanguageClassifications().badgeValue--;
                    }
                }
                break;
            case 'culture':
                if (object.variable in $scope.searchModel.getCulturalTraits().selected) {
                    for (var i = 0; i < $scope.searchModel.getCulturalTraits().selected[object.variable].length; i++) {
                        if (($scope.searchModel.getCulturalTraits().selected[object.variable][i].id == object.id) || ($scope.searchModel.getCulturalTraits().selected[object.variable][i].description == object.description)) {
                            $scope.searchModel.getCulturalTraits().selected[object.variable][i].isSelected = false;
                            index = i;
                            break;
                        }
                    }
                    if (index > -1) {
                        $scope.searchModel.getCulturalTraits().selected[object.variable].splice(index, 1);
                        $scope.searchModel.getCulturalTraits().selected[object.variable].allSelected = false;
                        $scope.searchModel.getCulturalTraits().badgeValue--;
                        $scope.$broadcast('variableCheck');
                    }

                }
        }
        if (!$scope.checkIfSelected()) {
            d3.select("#selected-criteria").classed("hidden", true);
            d3.select("#search-panel").classed("col-md-12", true);
            d3.select("#search-panel").classed("col-md-9", false);
        }
    };

    //calculates the range for environmental variables
    //needed for coloring of markers
    $scope.calculateRange = function(results) {
        societies = results.societies;
        for (var i = 0; i < results.environmental_variables.length; i++) {
            extractedValues = societies.map(function(society) {
                for (var j = 0; j < society.environmental_values.length; j++) {
                    if (society.environmental_values[j].variable == results.environmental_variables[i].id) {
                        if (society.environmental_values[j].value) return society.environmental_values[j].value;
                    }
                }
            });
            var min_value = null; var max_value = null;
           extractedValues.forEach(function(val) {
            if (!min_value) min_value = val;
            if (!max_value) max_value = val;

            if (val < min_value) min_value = val;
            if (val > max_value) max_value = val;
           });
            var range = max_value - min_value;
            results.environmental_variables[i]['range'] = range;
            results.environmental_variables[i]['min'] = Math.round(min_value*10000)/10000;
            results.environmental_variables[i]['max'] = Math.round(max_value*10000)/10000;
        }
        return results;
    };

    //calculates number of codes selected for each variable and saves to coded_value
    //needed for coloring of markers
    $scope.getCodeIDs = function() {
        $scope.searchModel.results.code_ids = {};
        if ($scope.searchModel.query.l && !$scope.searchModel.query.c && !$scope.searchModel.query.e) {
            $scope.searchModel.results.classifications = [];
            added = [];
            for (var i = 0; i < $scope.searchModel.results.societies.length; i++) {
                for (var s = 0; s < $scope.searchModel.results.societies[i].languages.length; s++) {
                    language_family = $scope.searchModel.results.societies[i].languages[s].family;
                    if (added.indexOf(language_family.id) == -1) {
                        $scope.searchModel.results.classifications.push(language_family);
                        added.push(language_family.id);
                    }
                }
            }
        }

        for (var i = 0; i < $scope.searchModel.results.variable_descriptions.length; i++) {
            if ($scope.searchModel.results.variable_descriptions[i].variable.data_type.toUpperCase() == 'CONTINUOUS') {
                codes = $scope.searchModel.query.c.filter(function(code) { return code.variable == $scope.searchModel.results.variable_descriptions[i].variable.id; });
                var min;
                var max = 0;

                codes.forEach(function(c_var) {
                    if (!min) {
                        min = c_var.min;
                    } else {
                        if (c_var.min < min) min = c_var.min;
                    }
                    if (c_var.max > max) max = c_var.max;
                });

                $scope.searchModel.results.variable_descriptions[i].variable['min'] = min;
                $scope.searchModel.results.variable_descriptions[i].variable['max'] = max;
                $scope.searchModel.results.variable_descriptions[i].variable['units'] = $scope.searchModel.results.variable_descriptions[i].variable.name.substring($scope.searchModel.results.variable_descriptions[i].variable.name.indexOf('(')+1, $scope.searchModel.results.variable_descriptions[i].variable.name.indexOf(')'));
                $scope.searchModel.results.variable_descriptions[i].codes = codes;
            }

        }
    }

    $scope.assignColors = function() {
        results = $scope.searchModel.getResults();
        results = $scope.calculateRange(results);
        var colorMap = colorMapService.generateColorMap(results);
        $scope.searchModel.getSocieties().forEach(function(container) {
            container.society.style = {'background-color' : colorMap[container.society.id] };
        });
    };

    function addTreesToSocieties() {
        $scope.searchModel.results.language_trees.phylogenies = [];
        $scope.searchModel.results.language_trees.glotto_trees = [];
        $scope.searchModel.results.language_trees.forEach(function(tree) {
            if (tree.name.indexOf("global") != -1) $scope.searchModel.results.language_trees.global_tree = tree;
            else if (tree.name.indexOf("glotto") != -1) {
                $scope.searchModel.results.language_trees.glotto_trees.push(tree);
            }
            else {
                $scope.searchModel.results.language_trees.phylogenies.push(tree);
            }
        $scope.searchModel.results.language_trees.glotto_trees.sort(function(a, b) { return a.name > b.name; });
        $scope.searchModel.results.language_trees.phylogenies.sort(function(a, b) { return a.name > b.name; });
        });
        $scope.searchModel.getSocieties().forEach(function (container) {
            var language = container.society.name;
            if(language != null) {
                container.society.trees = $scope.searchModel.results.language_trees.filter(function (tree) {
                    return tree.taxa.some(function (item) {
                        return item.societies.some(function(label) {
                            return angular.equals(label.society.name, language);
                        });
                    });
                });
            } else {
                container.society.trees = [];
            }
        });
    }

    var errorCallBack = function() {
	$scope.errors = "Invalid input.";
	$scope.enableSearchButton();
    };

    var searchCompletedCallback = function() {
        $scope.enableSearchButton();
        $scope.getCodeIDs();
        $scope.assignColors();
        addTreesToSocieties();
        $scope.searchModel.results.searched = true;
        $scope.switchToResults();
    };

        // This method merges the current searchQuery object with the incoming searchQuery
    $scope.updateSearchQuery = function(searchQuery) {
        $scope.searchModel.query = {};
        for(var propertyName in searchQuery) {
            $scope.searchModel.query[propertyName] = searchQuery[propertyName];
        }
        console.log($scope.searchModel.query);
    };

    $scope.searchSocieties = function() {
        $scope.disableSearchButton();
        var query = $scope.searchModel.query;
        $scope.searchModel.results = FindSocieties.find(query, searchCompletedCallback, errorCallBack);
    };

    $scope.search = function() {
        var i, pruned;
        searchModel = searchModelService.getModel();
        searchParams = searchModel.params;
        searchQuery = {};
        for (var propertyName in searchParams) {
            //get selected cultural traits/codes
            if (propertyName == 'culturalTraits') {
                var codes = [];
                for (var variable in searchParams[propertyName].selected) {
                    searchParams[propertyName].selected[variable].forEach(function(code) { if (code.isSelected) codes.push(code); });
                };
                if (codes.length > 0) {
                    searchQuery['c'] = [];
                    for (i = 0; i < codes.length; i++) {
                        pruned = {variable: codes[i].variable};
                        if ('id' in codes[i]) {
                            pruned['id'] = codes[i].id;
                        }
                        if ('min' in codes[i]) {
                            pruned['min'] = codes[i].min;
                        }
                        if ('max' in codes[i]) {
                            pruned['max'] = codes[i].max;
                        }
                        searchQuery['c'].push(pruned);
                    }
                }
            }
            //get selected regions
            if (propertyName == 'geographicRegions') {
                var selectedRegions = searchParams[propertyName].selectedRegions;
                selectedRegions.forEach(function (selectedRegion) {
                    searchParams[propertyName].allRegions.forEach(function(region) {
                        if (region.tdwg_code == selectedRegion.code)
                            selectedRegion.id = region.id;
                    });
                });
                if (selectedRegions.length > 0) {
                    searchQuery['p'] = [];
                    for (i = 0; i < selectedRegions.length; i++) {
                        searchQuery['p'].push(selectedRegions[i].id);
                    }
                }
            }
            //get selected environmental variable and search parameters
            if (propertyName == 'environmentalData') {
                searchParams[propertyName].selectedVariables.forEach(function(variable) {
                    if (variable.selectedVariable) {
                        filters = [
                            variable.selectedVariable.id,
                            variable.selectedFilter.operator,
                            variable.vals
                        ];
                        if ('e' in searchQuery) {
                            searchQuery['e'].push(filters);
                        } else {
                            searchQuery['e'] = [filters];
                        }
                    }
                });
            }

            //get selected languages
            if (propertyName == 'languageClassifications') {
                var classifications = [];
                for (var family in searchParams[propertyName].selected) {
                    searchParams[propertyName].selected[family].forEach(function(language) { if (language.isSelected) classifications.push(language); });
                }
                if (classifications.length > 0) {
                    searchQuery['l'] = [];
                    for (i = 0; i < classifications.length; i++) {
                        searchQuery['l'].push(classifications[i].id);
                    }
                }
           }
        }
        $scope.updateSearchQuery(searchQuery);
        $scope.searchSocieties();
    };

    // resets this object state and the search query.
    $scope.resetSearch = function() {
		$scope.errors = "";
		$scope.enableSearchButton();
        $scope.searchModel.reset();
        // send a notification so that the individual controllers reload their state
        $scope.$broadcast('searchModelReset');
    };

}<|endoftext|>


<commit_before>Z.wrap('github/jillix/table/v0.0.1/table.js', function (require, module, exports) {

function createTemplates (schema) {

    // create headers and rows
    var columns = {
        headers: '
',
        rows: '
'
    };

    for (var i = 0; i < schema.length; ++i) {
        columns.headers += '' + schema[i].label + '	';
        columns.rows += '{' + schema[i].prop + '}	';
    }

    columns.headers += '
';
    columns.rows += '
';

    return columns;
}

// emit route on itme dom event
function itemAction (event) {
    var self = this;
    var item = self.model.data[event.index];

    if (self.view.item.config.route && item) {

        var match = self.view.item.config.route.match(/{([^}]+)}/g);
        var url = self.view.item.config.route;

        for (var i = 0, value; i < match.length; ++i) {

            // get value from object
            value = self._path(match[i].replace('{', '').replace('}', ''), item);

            url = url.replace(match[i], value);
        }

        self.route(url);
    }
}

function load (state, viewInfo) {
    var self = this;

    // reset current item
    self.currentItem = null;

    if (!self.view.item && !viewInfo) {
        return console.error('[table: ' + 'No item view.]');
    }

    // reset headers
    if (self.view.head.dom) {
        self.view.head.dom.innerHTML = '';
    }

    // TODO fetch view with view info or render direct on self.view.item
    // TODO handle title
    // self.view.title.render([{title: self.view.item.config.title}]);

    if (viewInfo) {
        // TODO fetch view from server
    } else {
        // mongodb model request
        self.model.req({m: 'find', d: self.view.item.config.req || {}}, function (err, data) {

            // create templates from view config
            var templates = createTemplates(self.view.item.config.columns);

            // set header template
            self.view.head.set(templates.headers, 'thead', self.view.layout.dom);

            self.view.head.render();
            self.view.item.render(data);
        });
    }
}

function init (config, ready) {
    var self = this;

    // append load handlers
    self.load = load;
    self.itemAction = itemAction;

    // render layout
    if (self.view && self.view.layout) {
        self.view.layout.render();
    }

    // a table can have only one model
    if (self.model) {
        for (var model in self.model) {
            self.model = self.model[model]
            break;
        }
    }

    // get an empty view instance for the table headers
    self._load('V', {}, function (err, view) {

        self.view.head = view;

        console.log('table:', self._name);
        ready();
    });
}

module.exports = init;

return module;

});
<commit_msg>added semicolon<commit_after>Z.wrap('github/jillix/table/v0.0.1/table.js', function (require, module, exports) {

function createTemplates (schema) {

    // create headers and rows
    var columns = {
        headers: '
',
        rows: '
'
    };

    for (var i = 0; i < schema.length; ++i) {
        columns.headers += '' + schema[i].label + '	';
        columns.rows += '{' + schema[i].prop + '}	';
    }

    columns.headers += '
';
    columns.rows += '
';

    return columns;
}

// emit route on itme dom event
function itemAction (event) {
    var self = this;
    var item = self.model.data[event.index];

    if (self.view.item.config.route && item) {

        var match = self.view.item.config.route.match(/{([^}]+)}/g);
        var url = self.view.item.config.route;

        for (var i = 0, value; i < match.length; ++i) {

            // get value from object
            value = self._path(match[i].replace('{', '').replace('}', ''), item);

            url = url.replace(match[i], value);
        }

        self.route(url);
    }
}

function load (state, viewInfo) {
    var self = this;

    // reset current item
    self.currentItem = null;

    if (!self.view.item && !viewInfo) {
        return console.error('[table: ' + 'No item view.]');
    }

    // reset headers
    if (self.view.head.dom) {
        self.view.head.dom.innerHTML = '';
    }

    // TODO fetch view with view info or render direct on self.view.item
    // TODO handle title
    // self.view.title.render([{title: self.view.item.config.title}]);

    if (viewInfo) {
        // TODO fetch view from server
    } else {
        // mongodb model request
        self.model.req({m: 'find', d: self.view.item.config.req || {}}, function (err, data) {

            // create templates from view config
            var templates = createTemplates(self.view.item.config.columns);

            // set header template
            self.view.head.set(templates.headers, 'thead', self.view.layout.dom);

            self.view.head.render();
            self.view.item.render(data);
        });
    }
}

function init (config, ready) {
    var self = this;

    // append load handlers
    self.load = load;
    self.itemAction = itemAction;

    // render layout
    if (self.view && self.view.layout) {
        self.view.layout.render();
    }

    // a table can have only one model
    if (self.model) {
        for (var model in self.model) {
            self.model = self.model[model];
            break;
        }
    }

    // get an empty view instance for the table headers
    self._load('V', {}, function (err, view) {

        self.view.head = view;

        console.log('table:', self._name);
        ready();
    });
}

module.exports = init;

return module;

});
<|endoftext|>


<commit_before>'use strict';

import { PENDING, FULFILLED, REJECTED, SETTLED, NEVER, HANDLED } from './state';

export function isPending(p) {
    return (p.state() & PENDING) > 0;
}

export function isFulfilled(p) {
    return (p.state() & FULFILLED) > 0;
}

export function isRejected(p) {
    return (p.state() & REJECTED) > 0;
}

export function isSettled(p) {
    return (p.state() & SETTLED) > 0;
}

export function isNever(p) {
    return (p.state() & NEVER) > 0;
}

export function isHandled(p) {
    return (p.state() & HANDLED) > 0;
}

export function getValue(p) {
    let n = p.near();
    if (!isFulfilled(n)) {
        throw new TypeError('getValue called on ' + p);
    }

    return n.value;
}

export function getReason(p) {
    let n = p.near();
    if (!isRejected(n)) {
        throw new TypeError('getReason called on ' + p);
    }

    setHandled(n);
    return n.value;
}

export function silenceError(p) {
    p._runAction(silencer);
}

const silencer = {
    fulfilled() {},
    rejected: setHandled
};

function setHandled(rejected) {
    rejected._state |= HANDLED;
}
<commit_msg>Ensure getReason emits rejectionHandled<commit_after>'use strict';

import { PENDING, FULFILLED, REJECTED, SETTLED, NEVER, HANDLED } from './state';

export function isPending(p) {
    return (p.state() & PENDING) > 0;
}

export function isFulfilled(p) {
    return (p.state() & FULFILLED) > 0;
}

export function isRejected(p) {
    return (p.state() & REJECTED) > 0;
}

export function isSettled(p) {
    return (p.state() & SETTLED) > 0;
}

export function isNever(p) {
    return (p.state() & NEVER) > 0;
}

export function isHandled(p) {
    return (p.state() & HANDLED) > 0;
}

export function getValue(p) {
    let n = p.near();
    if (!isFulfilled(n)) {
        throw new TypeError('getValue called on ' + p);
    }

    return n.value;
}

export function getReason(p) {
    let n = p.near();
    if (!isRejected(n)) {
        throw new TypeError('getReason called on ' + p);
    }

    silenceError(n);
    return n.value;
}

export function silenceError(p) {
    p._runAction(silencer);
}

const silencer = {
    fulfilled() {},
    rejected: setHandled
};

function setHandled(rejected) {
    rejected._state |= HANDLED;
}
<|endoftext|>