<commit_before>;
(function(mag, document, undefined) {

  'use strict';

  var module = mag.mod,
    render = mag.render,
    fill = mag.fill,
    type = {}.toString,
    FUNCTION = 'function',
    OBJECT = '[object Object]',
    redrawing = false,
    hookins = {
      attributes: [],
      elementMatcher: []
    }

  mag.redrawing = false
  mag.redraw = function(force) {
    if (mag.redrawing) {
      return
    }
    mag.redrawing = true
    render.redraw(module || render.module || {}, fill, force)
  }

  mag.withProp = function(prop, withAttrCallback) {
    return function(e) {
      e = e || event;
      var currentTarget = e.currentTarget || this;
      withAttrCallback(prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop))
    }
  }

  mag.prop = function(store, custom) {

    if (((store != null && type.call(store) === OBJECT) || typeof store === FUNCTION) && typeof store.then === FUNCTION) {
      return propify(store, custom)
    }

    return gettersetter(store, custom)
  }

  function gettersetter(store, custom) {
    var prop = function() {
      if (arguments.length) {
        store = arguments[0]
          // too much ?
        mag.redraw()
      }
      return store
    }

    // do we still need this?
    // TODO: value hookin?
    prop.type = 'fun'
      // extra custom data to pass - used by the unloader event
    prop.data = custom ? custom : null

    prop.toJSON = function() {
      // return a copy
      if (store && store.nodeType) {
        //make sure no circular references
        //return store.innerHTML
        return fill.elementToObject(store)
      }
      return store
    }

    return prop
  }

  function propify(promise, initialValue, custom) {
    var prop = mag.prop(initialValue, custom);
    promise.then(prop);
    //console.log(prop.data, prop()._html.data)
    prop.then = function(resolve, reject) {
      return propify(promise.then(resolve, reject), initialValue)
    };
    return prop
  }

  mag.hookin = function(name, key, handler) {
    hookins[name].push({
      context: {},
      handler: handler,
      key: key
    })
  }

  function callHook(key, name, i, data, before) {
    data.change = false
    if (hookins[name][i].key == key) {
      before = JSON.stringify({
        v: data.value,
        k: data.key
      })
      hookins[name][i].handler.call(hookins[name][i].context, data)
        //if any change
      if (before !== JSON.stringify({
          v: data.value,
          k: data.key
        })) {
        data.change = true
      }
    }
  }

  mag.hook = function(name, key, data) {
    for (var i = 0, size = hookins[name].length; i < size; i++) {
      callHook(key, name, i, data)
    }
  }
  var reloader = function(index, domElementId) {
    //console.log('reloaded', index, domElementId)
    // remove cache ?
    //delete render.cache[index]
    //console.log(render.cache[index] ? JSON.parse(render.cache[index]) : 'no cache')
    render.callLCEvent('onreload', module, index)
  }

  function runPromise(index, controller, clone) {

    if (controller.onunload) render.unloaders.push({
      controller: controller,
      handler: controller.onunload
    })

    module.promises[index] = new Promise(function(resolve, reject) {
      module.deferreds[index] = arguments
        // call onload if present in controller
        // if (controller.onload && !mag.running) render.callOnload(module)
    }.bind({}, clone))

    //INTERPOLATIONS
    mag.redraw()
    return propify(module.promises[index], {
      // _html: fill.cloneNodeWithEvents(module.elements[index])
      _html: mag.prop(module.elements[index])
        // _html: function() {
        // return module.elements[index]
        // }
    }, {
      type: 'module',
      id: index
    })
  }

  mag.count = []

  function getRendVal(domElementId, index, clone, props) {
    if (index > -1 && typeof props.key == 'undefined' && clone) {
      //console.log(domElementId, index)
      //props.key = index
    }

    //if parent then give info to current
    // TODO: removed until valid use case
    // if (mag.module.caller) {
    //   props._parentId = mag.module.caller._nodeId
    // }
    //var fid = domElementId + '.' + parentId;
    var fid = fill.count[domElementId]
    if (index < 0 && clone && typeof props.key == 'undefined' && fid) {

      if (!mag.count[domElementId]) mag.count[domElementId] = {}
      mag.count[domElementId].key++
        //count[domElementId].times++

        if (fid && mag.count[domElementId].size != fid[0]) {
          //console.log('AMOUNT', fill.count[fid])
          mag.count[domElementId].key = 0
        }
      mag.count[domElementId].size = fid && fid[0]
      props.key = mag.count[domElementId].key

      //console.log(domElementId, props.key, fid)

      /*
      // search children for first comment with
      var r = parent.querySelectorAll('[id^=__magnum__' + domElementId + ']')
      // remove items / length that don't have the same parentId at the end of the string
      var size=0
      for(var j in r){
        if(r[j].id && r[j].id.split('.').pop() == parentId){
          size++
        }
      }

      if (!count[domElementId]) count[domElementId] = {
        size: size,
        times: 0,
        keys: 0
      }
      count[domElementId].key++
        count[domElementId].times++
        if (typeof count[domElementId].size != 'undefined' && count[domElementId].size != r.length) {
          //console.log('AMOUNT', r.length)
          count[domElementId].key = 0
        }
      count[domElementId].size = r.length
      props.key = count[domElementId].key
      */
      //console.log(count[domElementId].times, domElementId, count[domElementId], props.key)

    }
    var nextIndex;

    // create new index on roots
    if (index < 0) {
      nextIndex = render.roots.length;
      props.key = typeof props.key != 'undefined' ? props.key : nextIndex
    }

    var rendVal = index > -1 && typeof props.key != 'undefined' ? domElementId + '.' + props.key : domElementId + '.' + props.key;
    return rendVal
  }

  // function findIndex(a, test) {
  //   var found = -1
  //   a.every(function(n, k) {
  //     var index = n.split('.')[0] == test ? 0 : -1
  //     index > -1 ? found = k : 0
  //     return index < 0;
  //   });
  //   return found;
  // }

  mag.module = function(domElementId, moduleObject, props, clone) {

    //MODULE
    if (!moduleObject.view) throw Error('Mag.JS module - requires a view: ' + domElementId + moduleObject)

    // generate / reuse key for each module call

    var props = props || {}

    /*
    var   parentMod;
    try {
      throw new Error();
    } catch (e) {
      var st = e.stack,
        lines = st.split("\n");
      for (var k in lines) {
        if (lines[k].indexOf && lines[k].indexOf('.view') > -1 && lines[k].indexOf(' ') > -1) {
          //console.log(lines[k].trim().split(' ')[1])
          parentMod = lines[k].trim().split(' ')[1].split('.')[1]
            //console.log(parentMod)
          break;
        }
      }
    }
    //get parentmod index
    var pindex, parentId;
    if (module.modules && parentMod) {
      pindex = findIndex(render.roots, parentMod)
        //console.log('PARENTMOD', domElementId, parentMod, pindex)
      parentId = module.modules[pindex] ? module.modules[pindex].id : 0
        // console.log(parentId)
        //var pid = document.getElementById(parentMod)
        //  if (pid) parent = pid
    }
*/

    var index = render.roots.indexOf(domElementId)

    //UNLOADERS that exist?
    if (index > -1 && reloader(index, domElementId)) return

    // clear cache if exists
    if (!props.retain) render.clear(index, domElementId, fill)

    var rendVal = getRendVal(domElementId, index, clone, props)

    //console.log(props.key, index, domElementId, rendVal,parentMod)

    // already exists
    if (render.roots.indexOf(rendVal) >= 0) {

      //console.log('REUSING EXISTING', rendVal)

      var index = render.roots.indexOf(rendVal)

      return runPromise(index, module.controllers[index], clone);

    }
    if (render.roots.indexOf(rendVal) < 0) {
      if (index < 0) {
        index = render.roots.length;
      } else {

        // console.log('CREATE NEW FROM EXISTING', index, props.key)

      }
      //console.log('CREATING', index, rendVal)
      // DOM
      var element = document.getElementById(domElementId)

      if (!element) throw Error('Mag.JS Module - invalid node id: ' + domElementId)

      render.roots[index] = rendVal

      // TODO: should props be frozen or changeable?
      var mod = module.submodule(moduleObject, [props])

      var controller = module.getController(index, mod, element, fill)

      module.controllers[index] = controller

      module.modules[index] = mod

      module.elements[index] = clone ? element.cloneNode(true) : element
      module.elements[index].cloner = clone

      return runPromise(index, controller, clone);
    }
  }

})(window.mag || {}, document)
<commit_msg>Update mag.js<commit_after>;
(function(mag, document, undefined) {

  'use strict';

  var module = mag.mod,
    render = mag.render,
    fill = mag.fill,
    type = {}.toString,
    FUNCTION = 'function',
    OBJECT = '[object Object]',
    redrawing = false,
    hookins = {
      attributes: [],
      elementMatcher: []
    }

  mag.redrawing = false
  mag.redraw = function(force) {
    if (mag.redrawing) {
      return
    }
    mag.redrawing = true
    render.redraw(module || render.module || {}, fill, force)
  }

  mag.withProp = function(prop, withAttrCallback) {
    return function(e) {
      e = e || event;
      var currentTarget = e.currentTarget || this;
      withAttrCallback(prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop))
    }
  }

  mag.prop = function(store, custom) {

    if (((store != null && type.call(store) === OBJECT) || typeof store === FUNCTION) && typeof store.then === FUNCTION) {
      return propify(store, custom)
    }

    return gettersetter(store, custom)
  }

  function gettersetter(store, custom) {
    var prop = function() {
      if (arguments.length) {
        store = arguments[0]
          // too much ?
        mag.redraw()
      }
      return store
    }

    // do we still need this?
    // TODO: value hookin?
    prop.type = 'fun'
      // extra custom data to pass - used by the unloader event
    prop.data = custom ? custom : null

    prop.toJSON = function() {
      // return a copy
      if (store && store.nodeType) {
        //make sure no circular references
        //return store.innerHTML
        return fill.elementToObject(store)
      }
      return store
    }

    return prop
  }

  function propify(promise, initialValue, custom) {
    var prop = mag.prop(initialValue, custom);
    promise.then(prop);
    //console.log(prop.data, prop()._html.data)
    prop.then = function(resolve, reject) {
      return propify(promise.then(resolve, reject), initialValue)
    };
    return prop
  }

  mag.hookin = function(name, key, handler) {
    hookins[name].push({
      context: {},
      handler: handler,
      key: key
    })
  }

  function callHook(key, name, i, data, before) {
    data.change = false
    if (hookins[name][i].key == key) {
      before = JSON.stringify({
        v: data.value,
        k: data.key
      })
      hookins[name][i].handler.call(hookins[name][i].context, data)
        //if any change
      if (before !== JSON.stringify({
          v: data.value,
          k: data.key
        })) {
        data.change = true
      }
    }
  }

  mag.hook = function(name, key, data) {
    for (var i = 0, size = hookins[name].length; i < size; i++) {
      callHook(key, name, i, data)
    }
  }
  var reloader = function(index, domElementId) {
    //console.log('reloaded', index, domElementId)
    // remove cache ?
    //delete render.cache[index]
    //console.log(render.cache[index] ? JSON.parse(render.cache[index]) : 'no cache')
    render.callLCEvent('onreload', module, index)
  }

  function runPromise(index, controller, clone) {

    if (controller.onunload) render.unloaders.push({
      controller: controller,
      handler: controller.onunload
    })

    module.promises[index] = new Promise(function(resolve, reject) {
      module.deferreds[index] = arguments
        // call onload if present in controller
        // if (controller.onload && !mag.running) render.callOnload(module)
    }.bind({}, clone))

    //INTERPOLATIONS
    mag.redraw()
    return propify(module.promises[index], {
      // _html: fill.cloneNodeWithEvents(module.elements[index])
      _html: mag.prop(module.elements[index])
        // _html: function() {
        // return module.elements[index]
        // }
    }, {
      type: 'module',
      id: index
    })
  }

  //mag.count = []

  function getRendVal(domElementId, index, clone, props) {
    if (index > -1 && typeof props.key == 'undefined' && clone) {
      //console.log(domElementId, index)
      //props.key = index
    }

    //if parent then give info to current
    // TODO: removed until valid use case
    // if (mag.module.caller) {
    //   props._parentId = mag.module.caller._nodeId
    // }
    //var fid = domElementId + '.' + parentId;
    /*
    var fid = fill.count[domElementId]
    if (index < 0 && clone && typeof props.key == 'undefined' && fid) {

      if (!mag.count[domElementId]) mag.count[domElementId] = {}
      mag.count[domElementId].key++
        //count[domElementId].times++

        if (fid && mag.count[domElementId].size != fid[0]) {
          console.log('AMOUNT', fid[0])
          mag.count[domElementId].key = 0
        }
      mag.count[domElementId].size = fid && fid[0]
      props.key = mag.count[domElementId].key

      console.log(domElementId, props.key, fid, mag.count[domElementId])

      /*
      // search children for first comment with
      var r = parent.querySelectorAll('[id^=__magnum__' + domElementId + ']')
      // remove items / length that don't have the same parentId at the end of the string
      var size=0
      for(var j in r){
        if(r[j].id && r[j].id.split('.').pop() == parentId){
          size++
        }
      }

      if (!count[domElementId]) count[domElementId] = {
        size: size,
        times: 0,
        keys: 0
      }
      count[domElementId].key++
        count[domElementId].times++
        if (typeof count[domElementId].size != 'undefined' && count[domElementId].size != r.length) {
          //console.log('AMOUNT', r.length)
          count[domElementId].key = 0
        }
      count[domElementId].size = r.length
      props.key = count[domElementId].key
      */
    //console.log(count[domElementId].times, domElementId, count[domElementId], props.key)

    // }

    var nextIndex;

    // create new index on roots
    if (index < 0) {
      nextIndex = render.roots.length;
      props.key = typeof props.key != 'undefined' ? props.key : nextIndex
    }

    var rendVal = index > -1 && typeof props.key != 'undefined' ? domElementId + '.' + props.key : domElementId + '.' + props.key;
    return rendVal
  }

  // function findIndex(a, test) {
  //   var found = -1
  //   a.every(function(n, k) {
  //     var index = n.split('.')[0] == test ? 0 : -1
  //     index > -1 ? found = k : 0
  //     return index < 0;
  //   });
  //   return found;
  // }

  mag.module = function(domElementId, moduleObject, props, clone) {

    //MODULE
    if (!moduleObject.view) throw Error('Mag.JS module - requires a view: ' + domElementId + moduleObject)

    // generate / reuse key for each module call

    var props = props || {}

    /*
    var   parentMod;
    try {
      throw new Error();
    } catch (e) {
      var st = e.stack,
        lines = st.split("\n");
      for (var k in lines) {
        if (lines[k].indexOf && lines[k].indexOf('.view') > -1 && lines[k].indexOf(' ') > -1) {
          //console.log(lines[k].trim().split(' ')[1])
          parentMod = lines[k].trim().split(' ')[1].split('.')[1]
            //console.log(parentMod)
          break;
        }
      }
    }
    //get parentmod index
    var pindex, parentId;
    if (module.modules && parentMod) {
      pindex = findIndex(render.roots, parentMod)
        //console.log('PARENTMOD', domElementId, parentMod, pindex)
      parentId = module.modules[pindex] ? module.modules[pindex].id : 0
        // console.log(parentId)
        //var pid = document.getElementById(parentMod)
        //  if (pid) parent = pid
    }
*/

    var index = render.roots.indexOf(domElementId)

    //UNLOADERS that exist?
    if (index > -1 && reloader(index, domElementId)) return

    // clear cache if exists
    if (!props.retain) render.clear(index, domElementId, fill)

    var rendVal = getRendVal(domElementId, index, clone, props)

    //console.log(props.key, index, domElementId, rendVal,parentMod)

    // already exists
    if (render.roots.indexOf(rendVal) >= 0) {

      //console.log('REUSING EXISTING', rendVal)

      var index = render.roots.indexOf(rendVal)

      return runPromise(index, module.controllers[index], clone);

    }
    if (render.roots.indexOf(rendVal) < 0) {
      if (index < 0) {
        index = render.roots.length;
      } else {

        // console.log('CREATE NEW FROM EXISTING', index, props.key)

      }
      //console.log('CREATING', index, rendVal)
      // DOM
      var element = document.getElementById(domElementId)

      if (!element) throw Error('Mag.JS Module - invalid node id: ' + domElementId)

      render.roots[index] = rendVal

      // TODO: should props be frozen or changeable?
      var mod = module.submodule(moduleObject, [props])

      var controller = module.getController(index, mod, element, fill)

      module.controllers[index] = controller

      module.modules[index] = mod

      module.elements[index] = clone ? element.cloneNode(true) : element
      module.elements[index].cloner = clone

      return runPromise(index, controller, clone);
    }
  }

})(window.mag || {}, document)
<|endoftext|>


<commit_before>module.exports = {
    core: {
        Fabric: 'fabrics',
<<<<<<< HEAD
        Textile: 'textiles'
=======
        Textile: 'textiles',
        Accessories: 'accessories'
>>>>>>> b4f55d97f499289cf9ca76e86193451824b74d8a
    }
}<commit_msg>Fix conflict<commit_after>module.exports = {
    core: {
        Fabric: 'fabrics',
        Textile: 'textiles'
        Accessories: 'accessories'
    }
}
<|endoftext|>


<commit_before>'use strict';
// Listens to the microphone and prints something when it's loud.
// `npm run-script listen` to run this.

// I installed this manually rather than via package.json
let coreAudio = require('node-core-audio');

let engine = coreAudio.createNewAudioEngine();

let range = [];
for (let i = 0; i < 1024; i++) {
  range.push(i);
}

let zero = [range.map(x => 0)];
let soft = [range.map(x => 2)];
let loud = [range.map(x => 20)];

let i = -1;

function round(num) {
  let answer = Math.round(num);
  // Avoid annoying-looking negative zero
  if (answer === 0) {
    answer = 0;
  }
  return answer;
}

function get(buffer, i) {
  return round(buffer[0][i] * 100);
}

// Input seems to be a 1x24 matrix of numbers.
// Returns the output buffer to play.
function processAudio(input) {
  i++;
  console.log('----------------');
  console.log(get(input, 0), get(input, 1), get(input, 2));
  return zero;
}

engine.addAudioCallback(processAudio);
<commit_msg>blur over time to find loudness<commit_after>'use strict';
// Listens to the microphone and prints something when it's loud.
// `npm run-script listen` to run this.

// I installed this manually rather than via package.json
let coreAudio = require('node-core-audio');

let engine = coreAudio.createNewAudioEngine();

let range = [];
for (let i = 0; i < 1024; i++) {
  range.push(i);
}

let zero = [range.map(x => 0)];
let soft = [range.map(x => 2)];
let loud = [range.map(x => 20)];

function round(num) {
  let answer = Math.round(num);
  // Avoid annoying-looking negative zero
  if (answer === 0) {
    answer = 0;
  }
  return answer;
}

function get(buffer, i) {
  return round(buffer[0][i] * 100);
}

// Input seems to be a 1x24 matrix of numbers.
// Returns the output buffer to play.
let average = 0.0;
function processAudio(input) {
  let delta = Math.abs(get(input, 0) + get(input, 1) + get(input, 2)) / 3;
  average = 0.9 * average + 0.1 * delta;
  console.log(average);
  return zero;
}

engine.addAudioCallback(processAudio);
<|endoftext|>


<commit_before>(function(process, logger){
	const csv = require('csv'),
		fs = require('fs'),
		RedisDb = require('./lib/redis-db'),
		config = require('./config.json'),
		Entity = require('./lib/entity'),
		PostSchema = require('./lib/classes/post-schema');

	if (process.argv.length < 3){
		console.log("Missing arguments", process.argv[0], process.argv[1], "file");
		process.exit(-1);
	}

	let postType = new Entity(PostSchema);

	let parser = csv.parse({columns: true}),
		rs = fs.createReadStream(process.argv[2]),
		db = new RedisDb(config.redis);

	db.connect();

	rs.on('readable', function(){
		while(data = rs.read()){
			parser.write(data);
		}
	});

	parser.on('readable', function(){
		while(data = parser.read()){
			db
				.saveEntity(postType, data)
				.then(function(){
					logger.log(data.Id);
				});
			if (data.PostTypeId === "1"){
				db.addToSet(postType, 'PostTypeId1', data);
			}
		}
	});

	parser.on('end', function(){
		setTimeout(function(){
			db.disconnect();
		}, 1000);
	});

})(process, console);
<commit_msg>added capability to open gzip data files<commit_after>(function(process, logger){
	const csv = require('csv'),
		fs = require('fs'),
		zlib = require('zlib'),
		RedisDb = require('./lib/redis-db'),
		config = require('./config.json'),
		Entity = require('./lib/entity'),
		PostSchema = require('./lib/classes/post-schema');

	if (process.argv.length < 3){
		console.log("Missing arguments", process.argv[0], process.argv[1], "file");
		process.exit(-1);
	}

	let postType = new Entity(PostSchema),
		gunzip = zlib.createGunzip();;

	let parser = csv.parse({columns: true}),
		rs = fs.createReadStream(process.argv[2]),
		db = new RedisDb(config.redis);

	rs.pipe(gunzip).pipe(parser);
	db.connect();

	parser.on('readable', function(){
		while(data = parser.read()){
			db
				.saveEntity(postType, data)
				.then(function(){
					logger.log(data.Id);
				});
			if (data.PostTypeId === "1"){
				db.addToSet(postType, 'PostTypeId1', data);
			}
		}
	});

	parser.on('end', function(){
		setTimeout(function(){
			db.disconnect();
		}, 1000);
	});

})(process, console);
<|endoftext|>


<commit_before>var debug = new (require('./sdebug'))('oip')
var natural = require('natural')
var PriorityQ = require('priorityqueuejs')
var Trie = natural.Trie
var underscore = require('underscore')
var util = require('util')
var wreck = require('wreck')

var OIP = function (config) {
  if (!(this instanceof OIP)) { return new OIP(config) }

  this.config = config
  this.config.oip = underscore.defaults(config.oip || {},
                                       { server: 'http://brave-development.go.sonobi.com/oip.json',
                                         sizes:
                                         { '728x90': {},
                                           '320x50': {},
                                           '300x250': {},
                                           '160x600': {}

                                         },
                                         categories: require('../config/sonobi-codes.js')
                                       })
  this.config.oip.options = underscore.defaults(this.config.oip.options || {},
                                               { refillInterval: 2 * 1000,
                                                 retryInterval: 60 * 1000,
                                                 emptyInterval: 60 * 1000,
                                                 maxFlights: 8,
                                                 lowWater: 5,
                                                 highWater: 15
                                               })

  this.pqs = {}
  this.tokenizer = new natural.WordTokenizer()
  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var trie = new Trie()

    trie.addStrings(this.tokenizer.tokenize(this.config.oip.categories[category]))
    this.pqs[category] = { errors: 0, sizes: {}, trie: trie, intents: trie.keysWithPrefix('') }
    underscore.keys(this.config.oip.sizes).forEach(function (size) {
      this.pqs[category].sizes[size] = { queue: new PriorityQ(pqComparator),
                                        lowWater: this.config.oip.options.lowWater,
                                        highWater: this.config.oip.options.highWater,
                                        empties: 0,
                                        impressions: 0,
                                        retry: 0
                                       }
    }.bind(this))
  }.bind(this))

  this.refills = 0
  this.refill()
  setInterval(this.refill.bind(this), this.config.oip.options.refillInterval)
}

var pqComparator = function (a, b) {
  var diff = a.expires - b.expires

  return ((diff !== 0) ? diff : (b.impressions - a.impressions))
}
var isNum = function (s) {
  return (/^(\-|\+)?([0-9]+|Infinity)$/.test(s))
}

OIP.prototype.refill = function () {
  if (this.refills !== 0) { return }

  debug('refill')
  this.timestamp = new Date().getTime()
  this.reload()
}

OIP.prototype.reload = function () {
  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var payload =
        { elements:
          { 'content_types': [ 'image/gif', 'image/png', 'image/jpeg' ],
            tiles: []
          },
            cat: {},
            lir: { ip: 0, intent: 1, loc: 0, uid: 0 }
        }
    var sizes = []

    if (this.refills >= this.config.oip.options.maxFlights) { return }

    underscore.keys(this.pqs[category].sizes).forEach(function (size) {
      var pq = this.pqs[category].sizes[size]
      var depth = pq.impressions
      var tile = []

      this.trim(pq)
      if ((depth >= pq.lowWater) || (depth <= pq.highWater) || (this.timestamp <= pq.retry)) { return }
      pq.retry = this.timestamp + this.config.oip.options.retryInterval

      sizes.push(size)
      for (depth = pq.highWater - depth; depth > 0; depth--) { tile.push({ tsize: size }) }
      payload.elements.tiles.push(tile)
    }.bind(this))
    if (payload.elements.tiles.length === 0) { return }

    payload.cat[category] = ''

    this.refills++
    wreck.post(this.config.oip.server,
               { payload: JSON.stringify(payload),
                 headers: { 'Content-Type': 'application/json' }
               },
        function (err, response, body) {
          var offset, result
          var now = new Date().getTime()

          this.refills--

          try {
            if (err) { throw err }
            result = JSON.parse(body)
          } catch (ex) {
            this.pqs[category].errors++
            sizes.forEach(function (size) {
              this.pqs[category].sizes[size].retry = now + this.config.oip.options.retryInterval
            }.bind(this))

            if ((body) && (body.length !== 0)) {
              ex.payload = payload
              if (body) { ex.body = body.toString() }
            }
            return debug('error for OIP category ' + category, ex)
          }

          offset = 0
          sizes.forEach(function (size) {
            var parts
            var count = 0
            var frequency = util.isArray(result.elements.fcap) ? (result.elements.fcap[offset] || result.elements.fcap[0])
                                : { intent_type: '', intent_data: '', time_frame: 0, impression_limit: 0 }
            var pq = this.pqs[category].sizes[size]

            if (!util.isArray(result.elements.tiles[offset])) return

            parts = frequency.time_frame.toString().split(' ')
            if (parts.length === 2) {
              frequency.time_frame = parseInt(parts[0], 10) * { weeks: 7 * 24 * 60 * 60,
                                                                days: 24 * 60 * 60,
                                                                hours: 60 * 60,
                                                                minutes: 60,
                                                                seconds: 1 }[parts[1]]
            }
            if (isNum(frequency.time_frame)) {
              frequency.time_frame = parseInt(frequency.time_frame, 10)
            } else {
              debug('unknown time_frame in ' + JSON.stringify(frequency))
              frequency.time_frame = 0
            }
            if (frequency.time_frame <= 0) frequency.time_frame = 24 * 60 * 60

            if (isNum(frequency.impression_limit)) {
              frequency.impression_limit = parseInt(frequency.impression_limit, 10)
            } else {
              debug('unknown impression_limit in ' + JSON.stringify(frequency))
              frequency.impression_limit = 0
            }
            if (frequency.impression_limit <= 0) frequency.impression_limit = 1

            result.elements.tiles[offset].forEach(function (ad) {
              if (ad.url) {
                pq.queue.enq(underscore.extend(ad, { expires: now + (frequency.time_frame * 1000),
                                                     impressions: frequency.impression_limit
                                                   }))
                pq.impressions += frequency.impression_limit
                count++
              }

              if (count === 0) {
                this.pqs[category].sizes[size].empties++
                this.pqs[category].sizes[size].retry = now + this.config.oip.options.emptyInterval
              } else {
                this.pqs[category].sizes[size].empties = 0
              }
            }.bind(this))

            offset++
          }.bind(this))
          if (!util.isArray(result.elements.fcap)) return debug('frequency caps not an array')

          result.elements.fcap.forEach(function (frequency) {
            if (frequency.intent_data) {
              this.pqs[category].trie.addStrings(this.tokenizer.tokenize(frequency.intent_data))
              this.pqs[category].intents = this.pqs[category].trie.keysWithPrefix('')
            }
          }.bind(this))
        }.bind(this))
  }.bind(this))

  if (this.refills > 0) { setTimeout(this.reload.bind(this), 500) }
}

OIP.prototype.trim = function (pq) {
  var ad
  var now = new Date().getTime()

  while (!pq.queue.isEmpty()) {
    if (pq.queue.peek().expires >= now) return

    ad = pq.deq()
    pq.impressions -= ad.impressions
  }
}

OIP.prototype.adUnitForIntents = function (intents, width, height) {
  var ad, pq, result, suffix
  var score = -1
  var size = width + 'x' + height

  underscore.shuffle(underscore.keys(this.config.oip.categories)).forEach(function (category) {
    var ilength, pqs

    pqs = this.pqs[category]
    pq = pqs.sizes[size]
    if (!pq) return

    this.trim(pq)
    if (pq.queue.isEmpty()) return

    ilength = underscore.intersection(intents, pqs.intents)
    if (ilength <= score) return

    result = pqs
    score = ilength
    suffix = { category: category, name: this.config.oip.categories[category] }
  }.bind(this))

  if (!result) return

  pq = result.sizes[size]
  pq.impressions--
  ad = pq.queue.deq()
  if ((ad.impressions -= 1) > 0) pq.queue.enq(ad)

  return underscore.extend({}, ad, suffix)
}

OIP.prototype.categories = function () {
  var now = new Date().getTime()
  var result = {}

  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var pqs = this.pqs[category]

    result[category] = { name: this.config.oip.categories[category],
                         errors: pqs.errors,
                         intents: pqs.intents,
                         sizes: {}
                       }

    underscore.keys(pqs.sizes).forEach(function (size) {
      var datum, earliest, latest
      var pq = pqs.sizes[size]
      var retry = Math.max(pq.retry - now, 0)

      this.trim(pq)
      datum = { empties: pq.empties,
                queue: pq.queue.size(),
                retryIn: retry / 1000,
                impressions: pq.impressions
              }
      earliest = Number.MAX_SAFE_INTEGER
      latest = 0
      pq.queue.forEach(function (element) {
        if (earliest > element.expires) earliest = element.expires
        if (latest < element.expires) latest = element.expires
      })
      result[category].sizes[size] = underscore.extend(datum,
                                                       { earliest: Math.max(earliest - now, 0) / 1000,
                                                         latest: Math.max(latest - now, 0) / 1000
                                                       })
    }.bind(this))
  }.bind(this))

  return result
}

OIP.prototype.statistics = function () {
  var result = { categories: { active: 0, total: underscore.keys(this.config.oip.categories).length },
                 errors: 0,
                 options: this.config.oip.options,
                 sizes: {}
               }

  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var activeP = 0
    var pqs = this.pqs[category]

    result.errors += pqs.errors
    underscore.keys(pqs.sizes).forEach(function (size) {
      var pq = pqs.sizes[size]

      if (pq.impressions > 0) activeP = 0
      if (!result.sizes[size]) result.sizes[size] = { empties: 0, impressions: 0, queue: 0 }
      result.sizes[size].empties += pq.empties
      result.sizes[size].impressions += pq.impressions
      result.sizes[size].queue += pq.queue.size()
    })

    if (activeP) result.categories.active++
  }.bind(this))

  return result
}

module.exports = OIP
<commit_msg>[oip] refinements<commit_after>var debug = new (require('./sdebug'))('oip')
var natural = require('natural')
var PriorityQ = require('priorityqueuejs')
var Trie = natural.Trie
var underscore = require('underscore')
var util = require('util')
var wreck = require('wreck')

var OIP = function (config) {
  if (!(this instanceof OIP)) { return new OIP(config) }

  this.config = config
  this.config.oip = underscore.defaults(config.oip || {},
                                       { server: 'http://brave-development.go.sonobi.com/oip.json',
                                         sizes:
                                         { '728x90': {},
                                           '320x50': {},
                                           '300x250': {},
                                           '160x600': {}

                                         },
                                         categories: require('../config/sonobi-codes.js')
                                       })
  this.config.oip.options = underscore.defaults(this.config.oip.options || {},
                                               { refillInterval: 2 * 1000,
                                                 retryInterval: 60 * 1000,
                                                 emptyInterval: 60 * 1000,
                                                 maxFlights: 8,
                                                 lowWater: 5,
                                                 highWater: 15
                                               })

  this.pqs = {}
  this.tokenizer = new natural.WordTokenizer()
  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var trie = new Trie()

    trie.addStrings(this.tokenizer.tokenize(this.config.oip.categories[category]))
    this.pqs[category] = { errors: 0, sizes: {}, trie: trie, intents: trie.keysWithPrefix('') }
    underscore.keys(this.config.oip.sizes).forEach(function (size) {
      this.pqs[category].sizes[size] = { queue: new PriorityQ(pqComparator),
                                        lowWater: this.config.oip.options.lowWater,
                                        highWater: this.config.oip.options.highWater,
                                        empties: 0,
                                        impressions: 0,
                                        retry: 0
                                       }
    }.bind(this))
  }.bind(this))

  this.refills = 0
  this.refill()
  setInterval(this.refill.bind(this), this.config.oip.options.refillInterval)
}

var pqComparator = function (a, b) {
  var diff = a.expires - b.expires

  return ((diff !== 0) ? diff : (b.impressions - a.impressions))
}
var isNum = function (s) {
  return (/^(\-|\+)?([0-9]+|Infinity)$/.test(s))
}

OIP.prototype.refill = function () {
  if (this.refills !== 0) { return }

  debug('refill')
  this.timestamp = new Date().getTime()
  this.reload()
}

OIP.prototype.reload = function () {
  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var payload =
        { elements:
          { 'content_types': [ 'image/gif', 'image/png', 'image/jpeg' ],
            tiles: []
          },
            cat: {},
            lir: { ip: 0, intent: 1, loc: 0, uid: 0 }
        }
    var sizes = []

    if (this.refills >= this.config.oip.options.maxFlights) { return }

    underscore.keys(this.pqs[category].sizes).forEach(function (size) {
      var pq = this.pqs[category].sizes[size]
      var depth = pq.impressions
      var tile = []

      this.trim(pq)
      if ((depth >= pq.lowWater) || (this.timestamp <= pq.retry)) { return }
      pq.retry = this.timestamp + this.config.oip.options.retryInterval

      sizes.push(size)
      for (depth = pq.highWater - depth; depth > 0; depth--) { tile.push({ tsize: size }) }
      payload.elements.tiles.push(tile)
    }.bind(this))
    if (payload.elements.tiles.length === 0) { return }

    payload.cat[category] = ''

    this.refills++
    wreck.post(this.config.oip.server,
               { payload: JSON.stringify(payload),
                 headers: { 'Content-Type': 'application/json' }
               },
        function (err, response, body) {
          var offset, result
          var now = new Date().getTime()

          this.refills--

          try {
            if (err) { throw err }
            result = JSON.parse(body)
          } catch (ex) {
            this.pqs[category].errors++
            sizes.forEach(function (size) {
              this.pqs[category].sizes[size].retry = now + this.config.oip.options.retryInterval
            }.bind(this))

            if ((body) && (body.length !== 0)) {
              ex.payload = payload
              if (body) { ex.body = body.toString() }
            }
            return debug('error for OIP category ' + category, ex)
          }

          offset = 0
          sizes.forEach(function (size) {
            var parts
            var count = 0
            var frequency = util.isArray(result.elements.fcap) ? (result.elements.fcap[offset] || result.elements.fcap[0])
                                : { intent_type: '', intent_data: '', time_frame: 0, impression_limit: 0 }
            var pq = this.pqs[category].sizes[size]

            if (!util.isArray(result.elements.tiles[offset])) return

            parts = frequency.time_frame.toString().split(' ')
            if (parts.length === 2) {
              frequency.time_frame = parseInt(parts[0], 10) * { weeks: 7 * 24 * 60 * 60,
                                                                days: 24 * 60 * 60,
                                                                hours: 60 * 60,
                                                                minutes: 60,
                                                                seconds: 1 }[parts[1]]
            }
            if (isNum(frequency.time_frame)) {
              frequency.time_frame = parseInt(frequency.time_frame, 10)
            } else {
              debug('unknown time_frame in ' + JSON.stringify(frequency))
              frequency.time_frame = 0
            }
            if (frequency.time_frame <= 0) frequency.time_frame = 24 * 60 * 60

            if (isNum(frequency.impression_limit)) {
              frequency.impression_limit = parseInt(frequency.impression_limit, 10)
            } else {
              debug('unknown impression_limit in ' + JSON.stringify(frequency))
              frequency.impression_limit = 0
            }
            if (frequency.impression_limit <= 0) frequency.impression_limit = 1

            result.elements.tiles[offset].forEach(function (ad) {
              if (ad.url) {
                pq.queue.enq(underscore.extend(ad, { expires: now + (frequency.time_frame * 1000),
                                                     impressions: frequency.impression_limit
                                                   }))
                pq.impressions += frequency.impression_limit
                count++
              }

              if (count === 0) {
                this.pqs[category].sizes[size].empties++
                this.pqs[category].sizes[size].retry = now + this.config.oip.options.emptyInterval
              } else {
                this.pqs[category].sizes[size].empties = 0
              }
            }.bind(this))

            offset++
          }.bind(this))
          if (!util.isArray(result.elements.fcap)) return debug('frequency caps not an array')

          result.elements.fcap.forEach(function (frequency) {
            if (frequency.intent_data) {
              this.pqs[category].trie.addStrings(this.tokenizer.tokenize(frequency.intent_data))
              this.pqs[category].intents = this.pqs[category].trie.keysWithPrefix('')
            }
          }.bind(this))
        }.bind(this))
  }.bind(this))

  if (this.refills > 0) { setTimeout(this.reload.bind(this), 500) }
}

OIP.prototype.trim = function (pq) {
  var ad
  var now = new Date().getTime()

  while (!pq.queue.isEmpty()) {
    if (pq.queue.peek().expires >= now) return

    ad = pq.deq()
    pq.impressions -= ad.impressions
  }
}

OIP.prototype.adUnitForIntents = function (intents, width, height) {
  var ad, pq, result, suffix
  var score = -1
  var size = width + 'x' + height

  underscore.shuffle(underscore.keys(this.config.oip.categories)).forEach(function (category) {
    var ilength, pqs

    pqs = this.pqs[category]
    pq = pqs.sizes[size]
    if (!pq) return

    this.trim(pq)
    if (pq.queue.isEmpty()) return

    ilength = underscore.intersection(intents, pqs.intents)
    if (ilength <= score) return

    result = pqs
    score = ilength
    suffix = { category: category, name: this.config.oip.categories[category] }
  }.bind(this))

  if (!result) return

  pq = result.sizes[size]
  pq.impressions--
  ad = pq.queue.deq()
  if ((ad.impressions -= 1) > 0) pq.queue.enq(ad)

  return underscore.extend({}, ad, suffix)
}

OIP.prototype.categories = function () {
  var now = new Date().getTime()
  var result = {}

  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var pqs = this.pqs[category]

    result[category] = { name: this.config.oip.categories[category],
                         errors: pqs.errors,
                         intents: pqs.intents,
                         sizes: {}
                       }

    underscore.keys(pqs.sizes).forEach(function (size) {
      var datum, earliest, latest
      var pq = pqs.sizes[size]
      var retry = Math.max(pq.retry - now, 0)

      this.trim(pq)
      datum = { empties: pq.empties,
                queue: pq.queue.size(),
                retryIn: retry / 1000,
                impressions: pq.impressions
              }
      earliest = Number.MAX_SAFE_INTEGER
      latest = 0
      pq.queue.forEach(function (element) {
        if (earliest > element.expires) earliest = element.expires
        if (latest < element.expires) latest = element.expires
      })
      if (latest === 0) earliest = 0
      result[category].sizes[size] = underscore.extend(datum,
                                                       { earliest: Math.max(earliest - now, 0) / 1000,
                                                         latest: Math.max(latest - now, 0) / 1000
                                                       })
    }.bind(this))
  }.bind(this))

  return result
}

OIP.prototype.statistics = function () {
  var result = { categories: { active: 0, total: underscore.keys(this.config.oip.categories).length },
                 errors: 0,
                 options: this.config.oip.options,
                 sizes: {}
               }

  underscore.keys(this.config.oip.categories).forEach(function (category) {
    var activeP = 0
    var pqs = this.pqs[category]

    result.errors += pqs.errors
    underscore.keys(pqs.sizes).forEach(function (size) {
      var pq = pqs.sizes[size]

      if (pq.impressions > 0) activeP = 1
      if (!result.sizes[size]) result.sizes[size] = { empties: 0, impressions: 0, queue: 0 }
      result.sizes[size].empties += pq.empties
      result.sizes[size].impressions += pq.impressions
      result.sizes[size].queue += pq.queue.size()
    })

    if (activeP) result.categories.active++
  }.bind(this))

  return result
}

module.exports = OIP
<|endoftext|>


<commit_before>Snake.VQL = {
  EQUAL: "=",
  NOT_EQUAL: "<>",
  GREATER_THAN: ">",
  LESS_THAN: "<",
  GREATER_EQUAL: ">=",
  LESS_EQUAL: "<=",
  ISNULL: "IS NULL",
  ISNOTNULL: "IS NOT NULL",
  LIKE: "LIKE",
  NOTLIKE: "NOT LIKE",
  "IN": "IN",
  NOTIN: "NOT IN",
  LEFT_JOIN: "LEFT JOIN",

  _venom: function (table, schema) {

    var Model = {

      find: function () {
        var field = null,
            value = null,
            selector = null;

        if (arguments.length > 1) {
          field = arguments[0];
          value = arguments[1];

          if (value in Snake.VQL) {
            selector = Snake.VQL[value];
          } else {
            selector = Snake.VQL[arguments[2]] || Snake.VQL.EQUAL;
          }

          if (field in schema.columns) {
            field = table + "." + field;
          }

          if (selector === Snake.VQL.ISNULL || selector === Snake.VQL.ISNOTNULL) {
            this.sql.where.push(field + " " + selector);
          } else {
            this.sql.where.push(field + " " + selector + " ?");
          }

        } else {
          for (field in arguments[0]) {
            if (arguments.hasOwnProperty(field)) {
              value = arguments[0][field];

              switch (Object.prototype.toString.call(value)) {
              case "[object Array]":
                selector = Snake.VQL.IN;
                break;
              case "[object RegExp]":
                selector = Snake.VQL.LIKE;
                //console.log(value.toString()); // TODO
                break;
              case "[object Object]":
                // need to loop through each item and set it
                //console.log(value[0]); // TODO
                break;
              default:
                selector = Snake.VQL.EQUAL;
              }

              // IN || NOT IN
              if (selector === Snake.VQL.IN || selector === Snake.VQL.NOTIN) {
                var q = [];

                for (var i = 0; i < value.length; i = i + 1) {
                  q.push("?");
                }

                if (field in schema.columns) {
                  field = table + "." + field;
                }

                this.sql.where.push(field + " " + selector + " (" + q.join(", ") + ")");
              } else {

                if (field in schema.columns) { // TODO refactor
                  field = table + "." + field;
                }

                this.sql.where.push(field + " " + selector + " ?");
              }
            }
          }
        }

        return this;
      },

      orderBy: function (obj) {
        var column = null;
        for (column in obj) {
          if (obj.hasOwnProperty(column)) {
            this.sql.orderBy.push(column + " " + obj[column].toUpperCase());
          }
        }

        return this;
      },

      offset: function (offset) {
        this.sql.offset = offset;
        return this;
      },

      limit: function (limit) {
        this.sql.limit = limit;
        return this;
      },

      toSQL: function () { // TODO - pass onSuccess, onFailure
        var sql = "SELECT #{select} FROM #{from}",
            query = {};

        // SELECT
        query.select = "*";

        if (this.sql.select.length === 0) {
          query.select = "*";
/*
// this adds all the columns
          query.select = [];
          for (var column in schema.columns) {
            query.select.push(table + "." + column);
          }
        } else {
*/
        } else {
          query.select = this.sql.select;
        }

        // FROM
        query.from = table;

        // WHERE
        if (this.sql.where.length > 0) {
          sql = sql + " WHERE #{where}";
          query.where = this.sql.where.join(" AND ");
        }

        // ORDER BY
        if (this.sql.orderBy.length > 0) {
          sql = sql + " ORDER BY #{orderBy}";
          query.orderBy = this.sql.orderBy;
        }

        // LIMIT && OFFSET
        if (this.sql.limit) {
          if (this.sql.offset) {
            sql = sql + " LIMIT #{offset}, #{limit}";
            query.offset = this.sql.offset;
          } else {
            sql = sql + " LIMIT #{limit}";
          }

          query.limit = this.sql.limit;
        }

        this.resetQuery();

        return sql.interpose(query); // TODO return query and params
      },

      resetQuery: function () {
        this.sql = {
          select: [],
          from: table,
          where: [],
          orderBy: [],
          limit: false
        };
      }

    };

    Model.resetQuery();

    return Model;
  },

  _createPeer: function (schema, onSuccess) {
    var table = null;

    for (table in schema) {
      if (schema.hasOwnProperty(table)) {
        this[schema[table].jsName] = new this._venom(table, schema[table]);
      }
    }

    if (onSuccess) {
      onSuccess();
    }
  }
};

var Venom = Snake.VQL,
    vql = Venom;
<commit_msg>bug fix<commit_after>Snake.VQL = {
  EQUAL: "=",
  NOT_EQUAL: "<>",
  GREATER_THAN: ">",
  LESS_THAN: "<",
  GREATER_EQUAL: ">=",
  LESS_EQUAL: "<=",
  ISNULL: "IS NULL",
  ISNOTNULL: "IS NOT NULL",
  LIKE: "LIKE",
  NOTLIKE: "NOT LIKE",
  "IN": "IN",
  NOTIN: "NOT IN",
  LEFT_JOIN: "LEFT JOIN",

  _venom: function (table, schema) {

    var Model = {

      find: function () {
        var field = null,
            value = null,
            selector = null;

        if (arguments.length > 1) {
          field = arguments[0];
          value = arguments[1];

          if (value in Snake.VQL) {
            selector = Snake.VQL[value];
          } else {
            selector = Snake.VQL[arguments[2]] || Snake.VQL.EQUAL;
          }

          if (field in schema.columns) {
            field = table + "." + field;
          }

          if (selector === Snake.VQL.ISNULL || selector === Snake.VQL.ISNOTNULL) {
            this.sql.where.push(field + " " + selector);
          } else {
            this.sql.where.push(field + " " + selector + " ?");
          }

        } else {
          for (field in arguments[0]) {
            if (arguments[0].hasOwnProperty(field)) {
              value = arguments[0][field];

              switch (Object.prototype.toString.call(value)) {
              case "[object Array]":
                selector = Snake.VQL.IN;
                break;
              case "[object RegExp]":
                selector = Snake.VQL.LIKE;
                //console.log(value.toString()); // TODO
                break;
              case "[object Object]":
                // need to loop through each item and set it
                //console.log(value[0]); // TODO
                break;
              default:
                selector = Snake.VQL.EQUAL;
              }

              // IN || NOT IN
              if (selector === Snake.VQL.IN || selector === Snake.VQL.NOTIN) {
                var q = [];

                for (var i = 0; i < value.length; i = i + 1) {
                  q.push("?");
                }

                if (field in schema.columns) {
                  field = table + "." + field;
                }

                this.sql.where.push(field + " " + selector + " (" + q.join(", ") + ")");
              } else {

                if (field in schema.columns) { // TODO refactor
                  field = table + "." + field;
                }

                this.sql.where.push(field + " " + selector + " ?");
              }
            }
          }
        }

        return this;
      },

      orderBy: function (obj) {
        var column = null;
        for (column in obj) {
          if (obj.hasOwnProperty(column)) {
            this.sql.orderBy.push(column + " " + obj[column].toUpperCase());
          }
        }

        return this;
      },

      offset: function (offset) {
        this.sql.offset = offset;
        return this;
      },

      limit: function (limit) {
        this.sql.limit = limit;
        return this;
      },

      toSQL: function () { // TODO - pass onSuccess, onFailure
        var sql = "SELECT #{select} FROM #{from}",
            query = {};

        // SELECT
        query.select = "*";

        if (this.sql.select.length === 0) {
          query.select = "*";
/*
// this adds all the columns
          query.select = [];
          for (var column in schema.columns) {
            query.select.push(table + "." + column);
          }
        } else {
*/
        } else {
          query.select = this.sql.select;
        }

        // FROM
        query.from = table;

        // WHERE
        if (this.sql.where.length > 0) {
          sql = sql + " WHERE #{where}";
          query.where = this.sql.where.join(" AND ");
        }

        // ORDER BY
        if (this.sql.orderBy.length > 0) {
          sql = sql + " ORDER BY #{orderBy}";
          query.orderBy = this.sql.orderBy;
        }

        // LIMIT && OFFSET
        if (this.sql.limit) {
          if (this.sql.offset) {
            sql = sql + " LIMIT #{offset}, #{limit}";
            query.offset = this.sql.offset;
          } else {
            sql = sql + " LIMIT #{limit}";
          }

          query.limit = this.sql.limit;
        }

        this.resetQuery();

        return sql.interpose(query); // TODO return query and params
      },

      resetQuery: function () {
        this.sql = {
          select: [],
          from: table,
          where: [],
          orderBy: [],
          limit: false
        };
      }

    };

    Model.resetQuery();

    return Model;
  },

  _createPeer: function (schema, onSuccess) {
    var table = null;

    for (table in schema) {
      if (schema.hasOwnProperty(table)) {
        this[schema[table].jsName] = new this._venom(table, schema[table]);
      }
    }

    if (onSuccess) {
      onSuccess();
    }
  }
};

var Venom = Snake.VQL,
    vql = Venom;
<|endoftext|>


<commit_before>/*
 * Fluster2 0.1.1
 * Copyright (C) 2009 Fusonic GmbH
 *
 * This file is part of Fluster2.
 *
 * Fluster2 is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * Fluster2 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

function Fluster2(_map,_debug){var map=_map;var projection=new Fluster2ProjectionOverlay(map);var me=this;var clusters=new Object();var markersLeft=new Object();this.debugEnabled=_debug;this.gridSize=60;this.markers=new Array();this.currentZoomLevel=-1;this.styles={0:{image:'http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m1.png',textColor:'#FFFFFF',width:53,height:52},10:{image:'http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m2.png',textColor:'#FFFFFF',width:56,height:55},20:{image:'http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m3.png',textColor:'#FFFFFF',width:66,height:65}};var zoomChangedTimeout=null;function createClusters(){var zoom=map.getZoom();if(clusters[zoom]){me.debug('Clusters for zoom level '+zoom+' already initialized.')}else{var clustersThisZoomLevel=new Array();var clusterCount=0;var markerCount=me.markers.length;for(var i=0;i<markerCount;i++){var marker=me.markers[i];var markerPosition=marker.getPosition();var done=false;for(var j=clusterCount-1;j>=0;j--){var cluster=clustersThisZoomLevel[j];if(cluster.contains(markerPosition)){cluster.addMarker(marker);done=true;break}}if(!done){var cluster=new Fluster2Cluster(me,marker);clustersThisZoomLevel.push(cluster);clusterCount++}}clusters[zoom]=clustersThisZoomLevel;me.debug('Initialized '+clusters[zoom].length+' clusters for zoom level '+zoom+'.')}if(clusters[me.currentZoomLevel]){for(var i=0;i<clusters[me.currentZoomLevel].length;i++){clusters[me.currentZoomLevel][i].hide()}}me.currentZoomLevel=zoom;showClustersInBounds()}function showClustersInBounds(){var mapBounds=map.getBounds();for(var i=0;i<clusters[me.currentZoomLevel].length;i++){var cluster=clusters[me.currentZoomLevel][i];if(mapBounds.contains(cluster.getPosition())){cluster.show()}}}this.zoomChanged=function(){window.clearInterval(zoomChangedTimeout);zoomChangedTimeout=window.setTimeout(createClusters,500)};this.getMap=function(){return map};this.getProjection=function(){return projection.getP()};this.debug=function(message){if(me.debugEnabled){console.log('Fluster2: '+message)}};this.addMarker=function(_marker){me.markers.push(_marker)};this.getStyles=function(){return me.styles};this.initialize=function(){google.maps.event.addListener(map,'zoom_changed',this.zoomChanged);google.maps.event.addListener(map,'dragend',showClustersInBounds);window.setTimeout(createClusters,1000)}}
function Fluster2Cluster(_fluster,_marker){var markerPosition=_marker.getPosition();this.fluster=_fluster;this.markers=[];this.bounds=null;this.marker=null;this.lngSum=0;this.latSum=0;this.center=markerPosition;this.map=this.fluster.getMap();var me=this;var projection=_fluster.getProjection();var gridSize=_fluster.gridSize;var position=projection.fromLatLngToDivPixel(markerPosition);var positionSW=new google.maps.Point(position.x-gridSize,position.y+gridSize);var positionNE=new google.maps.Point(position.x+gridSize,position.y-gridSize);this.bounds=new google.maps.LatLngBounds(projection.fromDivPixelToLatLng(positionSW),projection.fromDivPixelToLatLng(positionNE));this.addMarker=function(_marker){this.markers.push(_marker)};this.show=function(){if(this.markers.length==1){this.markers[0].setMap(me.map)}else if(this.markers.length>1){for(var i=0;i<this.markers.length;i++){this.markers[i].setMap(null)}if(this.marker==null){this.marker=new Fluster2ClusterMarker(this.fluster,this);if(this.fluster.debugEnabled){google.maps.event.addListener(this.marker,'mouseover',me.debugShowMarkers);google.maps.event.addListener(this.marker,'mouseout',me.debugHideMarkers)}}this.marker.show()}};this.hide=function(){if(this.marker!=null){this.marker.hide()}};this.debugShowMarkers=function(){for(var i=0;i<me.markers.length;i++){me.markers[i].setVisible(true)}};this.debugHideMarkers=function(){for(var i=0;i<me.markers.length;i++){me.markers[i].setVisible(false)}};this.getMarkerCount=function(){return this.markers.length};this.contains=function(_position){return me.bounds.contains(_position)};this.getPosition=function(){return this.center};this.getBounds=function(){return this.bounds};this.getMarkerBounds=function(){var bounds=new google.maps.LatLngBounds(me.markers[0].getPosition(),me.markers[0].getPosition());for(var i=1;i<me.markers.length;i++){bounds.extend(me.markers[i].getPosition())}return bounds};this.addMarker(_marker)}
function Fluster2ClusterMarker(_fluster,_cluster){this.fluster=_fluster;this.cluster=_cluster;this.position=this.cluster.getPosition();this.markerCount=this.cluster.getMarkerCount();this.map=this.fluster.getMap();this.style=null;this.div=null;var styles=this.fluster.getStyles();for(var i in styles){if(this.markerCount>i){this.style=styles[i]}else{break}}google.maps.OverlayView.call(this);this.setMap(this.map);this.draw()};Fluster2ClusterMarker.prototype=new google.maps.OverlayView();Fluster2ClusterMarker.prototype.draw=function(){if(this.div==null){var me=this;this.div=document.createElement('div');this.div.style.position='absolute';this.div.style.width=this.style.width+'px';this.div.style.height=this.style.height+'px';this.div.style.lineHeight=this.style.height+'px';this.div.style.background='transparent url("'+this.style.image+'") 50% 50% no-repeat';this.div.style.color=this.style.textColor;this.div.style.textAlign='center';this.div.style.fontFamily='Arial, Helvetica';this.div.style.fontSize='11px';this.div.style.fontWeight='bold';this.div.innerHTML=this.markerCount;this.div.style.cursor='pointer';google.maps.event.addDomListener(this.div,'click',function(){me.map.fitBounds(me.cluster.getMarkerBounds())});this.getPanes().overlayLayer.appendChild(this.div)}var position=this.getProjection().fromLatLngToDivPixel(this.position);this.div.style.left=(position.x-parseInt(this.style.width/2))+'px';this.div.style.top=(position.y-parseInt(this.style.height/2))+'px'};Fluster2ClusterMarker.prototype.hide=function(){this.div.style.display='none'};Fluster2ClusterMarker.prototype.show=function(){this.div.style.display='block'};
function Fluster2ProjectionOverlay(map){google.maps.OverlayView.call(this);this.setMap(map);this.getP=function(){return this.getProjection()}}Fluster2ProjectionOverlay.prototype=new google.maps.OverlayView();Fluster2ProjectionOverlay.prototype.draw=function(){};<commit_msg>FIX: Use protocol agnostic URL so that both http and https function with error warnings or just fail completely<commit_after>/*
 * Fluster2 0.1.1
 * Copyright (C) 2009 Fusonic GmbH
 *
 * This file is part of Fluster2.
 *
 * Fluster2 is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * Fluster2 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

function Fluster2(_map,_debug){var map=_map;var projection=new Fluster2ProjectionOverlay(map);var me=this;var clusters=new Object();var markersLeft=new Object();this.debugEnabled=_debug;this.gridSize=60;this.markers=new Array();this.currentZoomLevel=-1;this.styles={0:{image:'//gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m1.png',textColor:'#FFFFFF',width:53,height:52},10:{image:'//gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m2.png',textColor:'#FFFFFF',width:56,height:55},20:{image:'//gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m3.png',textColor:'#FFFFFF',width:66,height:65}};var zoomChangedTimeout=null;function createClusters(){var zoom=map.getZoom();if(clusters[zoom]){me.debug('Clusters for zoom level '+zoom+' already initialized.')}else{var clustersThisZoomLevel=new Array();var clusterCount=0;var markerCount=me.markers.length;for(var i=0;i<markerCount;i++){var marker=me.markers[i];var markerPosition=marker.getPosition();var done=false;for(var j=clusterCount-1;j>=0;j--){var cluster=clustersThisZoomLevel[j];if(cluster.contains(markerPosition)){cluster.addMarker(marker);done=true;break}}if(!done){var cluster=new Fluster2Cluster(me,marker);clustersThisZoomLevel.push(cluster);clusterCount++}}clusters[zoom]=clustersThisZoomLevel;me.debug('Initialized '+clusters[zoom].length+' clusters for zoom level '+zoom+'.')}if(clusters[me.currentZoomLevel]){for(var i=0;i<clusters[me.currentZoomLevel].length;i++){clusters[me.currentZoomLevel][i].hide()}}me.currentZoomLevel=zoom;showClustersInBounds()}function showClustersInBounds(){var mapBounds=map.getBounds();for(var i=0;i<clusters[me.currentZoomLevel].length;i++){var cluster=clusters[me.currentZoomLevel][i];if(mapBounds.contains(cluster.getPosition())){cluster.show()}}}this.zoomChanged=function(){window.clearInterval(zoomChangedTimeout);zoomChangedTimeout=window.setTimeout(createClusters,500)};this.getMap=function(){return map};this.getProjection=function(){return projection.getP()};this.debug=function(message){if(me.debugEnabled){console.log('Fluster2: '+message)}};this.addMarker=function(_marker){me.markers.push(_marker)};this.getStyles=function(){return me.styles};this.initialize=function(){google.maps.event.addListener(map,'zoom_changed',this.zoomChanged);google.maps.event.addListener(map,'dragend',showClustersInBounds);window.setTimeout(createClusters,1000)}}
function Fluster2Cluster(_fluster,_marker){var markerPosition=_marker.getPosition();this.fluster=_fluster;this.markers=[];this.bounds=null;this.marker=null;this.lngSum=0;this.latSum=0;this.center=markerPosition;this.map=this.fluster.getMap();var me=this;var projection=_fluster.getProjection();var gridSize=_fluster.gridSize;var position=projection.fromLatLngToDivPixel(markerPosition);var positionSW=new google.maps.Point(position.x-gridSize,position.y+gridSize);var positionNE=new google.maps.Point(position.x+gridSize,position.y-gridSize);this.bounds=new google.maps.LatLngBounds(projection.fromDivPixelToLatLng(positionSW),projection.fromDivPixelToLatLng(positionNE));this.addMarker=function(_marker){this.markers.push(_marker)};this.show=function(){if(this.markers.length==1){this.markers[0].setMap(me.map)}else if(this.markers.length>1){for(var i=0;i<this.markers.length;i++){this.markers[i].setMap(null)}if(this.marker==null){this.marker=new Fluster2ClusterMarker(this.fluster,this);if(this.fluster.debugEnabled){google.maps.event.addListener(this.marker,'mouseover',me.debugShowMarkers);google.maps.event.addListener(this.marker,'mouseout',me.debugHideMarkers)}}this.marker.show()}};this.hide=function(){if(this.marker!=null){this.marker.hide()}};this.debugShowMarkers=function(){for(var i=0;i<me.markers.length;i++){me.markers[i].setVisible(true)}};this.debugHideMarkers=function(){for(var i=0;i<me.markers.length;i++){me.markers[i].setVisible(false)}};this.getMarkerCount=function(){return this.markers.length};this.contains=function(_position){return me.bounds.contains(_position)};this.getPosition=function(){return this.center};this.getBounds=function(){return this.bounds};this.getMarkerBounds=function(){var bounds=new google.maps.LatLngBounds(me.markers[0].getPosition(),me.markers[0].getPosition());for(var i=1;i<me.markers.length;i++){bounds.extend(me.markers[i].getPosition())}return bounds};this.addMarker(_marker)}
function Fluster2ClusterMarker(_fluster,_cluster){this.fluster=_fluster;this.cluster=_cluster;this.position=this.cluster.getPosition();this.markerCount=this.cluster.getMarkerCount();this.map=this.fluster.getMap();this.style=null;this.div=null;var styles=this.fluster.getStyles();for(var i in styles){if(this.markerCount>i){this.style=styles[i]}else{break}}google.maps.OverlayView.call(this);this.setMap(this.map);this.draw()};Fluster2ClusterMarker.prototype=new google.maps.OverlayView();Fluster2ClusterMarker.prototype.draw=function(){if(this.div==null){var me=this;this.div=document.createElement('div');this.div.style.position='absolute';this.div.style.width=this.style.width+'px';this.div.style.height=this.style.height+'px';this.div.style.lineHeight=this.style.height+'px';this.div.style.background='transparent url("'+this.style.image+'") 50% 50% no-repeat';this.div.style.color=this.style.textColor;this.div.style.textAlign='center';this.div.style.fontFamily='Arial, Helvetica';this.div.style.fontSize='11px';this.div.style.fontWeight='bold';this.div.innerHTML=this.markerCount;this.div.style.cursor='pointer';google.maps.event.addDomListener(this.div,'click',function(){me.map.fitBounds(me.cluster.getMarkerBounds())});this.getPanes().overlayLayer.appendChild(this.div)}var position=this.getProjection().fromLatLngToDivPixel(this.position);this.div.style.left=(position.x-parseInt(this.style.width/2))+'px';this.div.style.top=(position.y-parseInt(this.style.height/2))+'px'};Fluster2ClusterMarker.prototype.hide=function(){this.div.style.display='none'};Fluster2ClusterMarker.prototype.show=function(){this.div.style.display='block'};
function Fluster2ProjectionOverlay(map){google.maps.OverlayView.call(this);this.setMap(map);this.getP=function(){return this.getProjection()}}Fluster2ProjectionOverlay.prototype=new google.maps.OverlayView();Fluster2ProjectionOverlay.prototype.draw=function(){};<|endoftext|>


<commit_before>const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const sheetrock = require('sheetrock');

const app = express();

app.set('port', (process.env.PORT || 3000));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

app.get('/', function(req, res) {
    // GET where ssl_check set to 1 from Slack
    if (req.query.ssl_check == 1) {
        return res.sendStatus(200);
    }
    return res.sendStatus(403);
});

app.get('/slack-auth', function(req, res) {
    let data = {form: {
        client_id: process.env.SLACK_CLIENT_ID,
        client_secret: process.env.SLACK_CLIENT_SECRET,
        code: req.query.code
    }};

    request.post('https://slack.com/api/oauth.access', data, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            res.redirect(process.env.THANK_YOU_REDIRECT);
        }
    });
});

app.post('/', function(req, res) {
    if (!req.body) {
        return res.sendStatus(400);
    }

    if (req.body.token == process.env.SLACK_AUTH_TOKEN) {

        let text = req.body.text ? req.body.text : 'excuseme';

        sheetrock({
            // url: "https://docs.google.com/spreadsheets/d/1QO5dyK6EgIP81SGZMlHMk8xn88u_budzF2Td3OoOZzY/edit#gid=0",
            // url: `https://docs.google.com/spreadsheets/d/${process.env.GOOGLE_SPREADSHEET_ID}/edit?usp=sharing`,
            url: `https://docs.google.com/spreadsheets/d/${process.env.GOOGLE_SPREADSHEET_ID}/edit#gid=0`,
            query: `Select B where A = "${text}"`,
            reset: true,
            callback: function (error, options, response) {
                console.log('>>', response.rows);
                console.log('attributes', attributes.labels[0]);

                // let donger = response.rows.cellsArray[0] ? response.rows.cellsArray[0] : 'no donger';
                let donger = 'no donger';
                var response = {
                    "response_type": "in_channel",
                    "text": donger,
                }
                res.json(response);
            }
        });
    }
});

app.listen(app.get('port'), function() {
    console.log('Node app is running on port', app.get('port'));
});
<commit_msg>debug<commit_after>const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const sheetrock = require('sheetrock');

const app = express();

app.set('port', (process.env.PORT || 3000));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

app.get('/', function(req, res) {
    // GET where ssl_check set to 1 from Slack
    if (req.query.ssl_check == 1) {
        return res.sendStatus(200);
    }
    return res.sendStatus(403);
});

app.get('/slack-auth', function(req, res) {
    let data = {form: {
        client_id: process.env.SLACK_CLIENT_ID,
        client_secret: process.env.SLACK_CLIENT_SECRET,
        code: req.query.code
    }};

    request.post('https://slack.com/api/oauth.access', data, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            res.redirect(process.env.THANK_YOU_REDIRECT);
        }
    });
});

app.post('/', function(req, res) {
    if (!req.body) {
        return res.sendStatus(400);
    }

    if (req.body.token == process.env.SLACK_AUTH_TOKEN) {

        let text = req.body.text ? req.body.text : 'excuseme';

        sheetrock({
            // url: "https://docs.google.com/spreadsheets/d/1QO5dyK6EgIP81SGZMlHMk8xn88u_budzF2Td3OoOZzY/edit#gid=0",
            // url: `https://docs.google.com/spreadsheets/d/${process.env.GOOGLE_SPREADSHEET_ID}/edit?usp=sharing`,
            url: `https://docs.google.com/spreadsheets/d/${process.env.GOOGLE_SPREADSHEET_ID}/edit#gid=0`,
            query: `Select B where A = "${text}"`,
            reset: true,
            callback: function (error, options, response) {
                console.log('>>', response.rows);
                console.log('attributes', response.attributes.labels[0]);

                // let donger = response.rows.cellsArray[0] ? response.rows.cellsArray[0] : 'no donger';
                let donger = 'no donger';
                var response = {
                    "response_type": "in_channel",
                    "text": donger,
                }
                res.json(response);
            }
        });
    }
});

app.listen(app.get('port'), function() {
    console.log('Node app is running on port', app.get('port'));
});
<|endoftext|>


<commit_before>"use strict";

/*global module, require*/

var matchNone = /(?!)/,
    matchEmpty = /$^/,

    /*
     Disabled means the button is not clickable.
     Ready means the button may be cliced.
     Active means the button has been clicked. It may be showing a search, a dialogue, or a sub-menu.
     */
    disabled = "disabled",
    ready = 'ready',
    active = "active";

/*
 Helper functions for producing valid button specifications. We pass these to the menu object, which display them for us.

 The reason for these functions is to provide defaults for the optional arguments, and to check the types of things supplied by the user.
 */
module.exports = function(defaultCollection) {
    var checkState = function(o, props) {
	props.forEach(function(p) {
	    if (o[p] === undefined) {
		throw new Error("Missing property " + p + " had " + Object.keys(o));
	    }

	    if (typeof(o[p]) !== 'boolean') {
		throw new Error("Property " + p + " should be a boolean, was: " + o[p]);
	    }
	});
    };

    /*
     states should be an object.

     We are checking for 3 properties: onlineOffline, readWriteSync and embeddedStandalone. Each of these represents a dimension of the state-space of the menu. If any are missing, the button will be displayed regardless of the state of the dimension.

     Each of these should be a subobject containing true/false sub-properties detailing which states the button should display in.
     */
    var checkStates = function(states) {
	if (!states.onlineOffline) {
	    states.onlineOffline = {
		online: true,
		offline: true
	    };
	} else {
	    checkState(states.onlineOffline, ['online', 'offline']);
	}

	if (!states.readWriteSync) {
	    states.readWriteSync = {
		untitled: true,
		read: true,
		write: true,
		sync: true
	    };
	} else {
	    checkState(states.readWriteSync, ['read', 'write', 'sync']);
	}

	if (!states.embeddedStandalone) {
	    states.embeddedStandalone = {
		embedded: true,
		standalone: true
	    };
	} else {
	    checkState(states.embeddedStandalone, ['embedded', 'standalone']);
	}
    };

    var m =  {
	matchEmpty: matchEmpty,

	/*
	 text is required, and should be a string. It's the text which will be displayed on the button.

	 f is required, and should be a function. If search is specified, then f will be called once a search result is clicked and will get the text of the search result as an argument. Otherwise, it will be called with no arguments as soon as the button is clicked.

	 options is required, and may contain the following optional properties, plus those listed in the checkStates function above:

	 options.extraDisplayCondition is a function which must return true in order for the button to be displayed.

	 options.element is a string which represents the type of HTML element to be used for this button.

	 options.hooks is a function which takes a d3 selection. The d3 selection will be the button. Hooks can be used to modify the button. If not specified, it will default to a noop function.
	 */
	button: function(text, isActive, f, options) {
	    if (typeof(text) !== 'string') {
		throw new Error("Text should be a string, was: " + text);
	    }

	    if (typeof(f) !== 'function') {
		throw new Error('f should be a function, was: ' + f);
	    }

	    checkStates(options);

	    if (options.extraDisplayCondition === undefined) {
		options.extraDisplayCondition = function() {
		    return true;
		};
	    } else if (typeof(options.extraDisplayCondition) !== 'function') {
		throw new Error("If extraDisplayCondition is specified, it must be a function which returns true or false, was " + options.extraDisplayCondition);
	    }

	    if (options.element === undefined) {
		options.element = "div";
	    } else if (typeof(options.element) !== 'string') {
		throw new Error("If element is specified, it must be a string which is the name of an HTML element, was " + options.element);
	    }

	    if (options.hooks === undefined) {
		options.hooks = function() {
		    // no-op
		};

	    } else if (typeof(options.hooks) !== 'function') {
		throw new Error("If hooks is specified, it must be a function, was: " + options.hooks);
	    }

	    return {
		text: text,
		f: f,
		hover: options.hover,
		element: options.element,
		getState: function(menuState, ownsCurrentProcess) {
		    if (
			options.onlineOffline[menuState.online() ? "online" : "offline"]
			    && options.readWriteSync[menuState.readWriteSync()]
			    && options.embeddedStandalone[menuState.embedded() ? "embedded" : "standalone"]
			    && options.extraDisplayCondition()
		    ) {
			if (isActive && isActive(menuState, ownsCurrentProcess)) {
			    return active;
			} else {
			    return ready;
			}

		    } else {
			return disabled;
		    }
		},
		hooks: options.hooks
	    };
	}
    };

    return m;
};
<commit_msg>Removed some unused constants.<commit_after>"use strict";

/*global module, require*/

/*
 Disabled means the button is not clickable.
 Ready means the button may be cliced.
 Active means the button has been clicked. It may be showing a search, a dialogue, or a sub-menu.
 */
var disabled = "disabled",
    ready = 'ready',
    active = "active";

/*
 Helper functions for producing valid button specifications. We pass these to the menu object, which display them for us.

 The reason for these functions is to provide defaults for the optional arguments, and to check the types of things supplied by the user.
 */
module.exports = function(defaultCollection) {
    var checkState = function(o, props) {
	props.forEach(function(p) {
	    if (o[p] === undefined) {
		throw new Error("Missing property " + p + " had " + Object.keys(o));
	    }

	    if (typeof(o[p]) !== 'boolean') {
		throw new Error("Property " + p + " should be a boolean, was: " + o[p]);
	    }
	});
    };

    /*
     states should be an object.

     We are checking for 3 properties: onlineOffline, readWriteSync and embeddedStandalone. Each of these represents a dimension of the state-space of the menu. If any are missing, the button will be displayed regardless of the state of the dimension.

     Each of these should be a subobject containing true/false sub-properties detailing which states the button should display in.
     */
    var checkStates = function(states) {
	if (!states.onlineOffline) {
	    states.onlineOffline = {
		online: true,
		offline: true
	    };
	} else {
	    checkState(states.onlineOffline, ['online', 'offline']);
	}

	if (!states.readWriteSync) {
	    states.readWriteSync = {
		untitled: true,
		read: true,
		write: true,
		sync: true
	    };
	} else {
	    checkState(states.readWriteSync, ['read', 'write', 'sync']);
	}

	if (!states.embeddedStandalone) {
	    states.embeddedStandalone = {
		embedded: true,
		standalone: true
	    };
	} else {
	    checkState(states.embeddedStandalone, ['embedded', 'standalone']);
	}
    };

    var m =  {
	matchEmpty: matchEmpty,

	/*
	 text is required, and should be a string. It's the text which will be displayed on the button.

	 f is required, and should be a function. If search is specified, then f will be called once a search result is clicked and will get the text of the search result as an argument. Otherwise, it will be called with no arguments as soon as the button is clicked.

	 options is required, and may contain the following optional properties, plus those listed in the checkStates function above:

	 options.extraDisplayCondition is a function which must return true in order for the button to be displayed.

	 options.element is a string which represents the type of HTML element to be used for this button.

	 options.hooks is a function which takes a d3 selection. The d3 selection will be the button. Hooks can be used to modify the button. If not specified, it will default to a noop function.
	 */
	button: function(text, isActive, f, options) {
	    if (typeof(text) !== 'string') {
		throw new Error("Text should be a string, was: " + text);
	    }

	    if (typeof(f) !== 'function') {
		throw new Error('f should be a function, was: ' + f);
	    }

	    checkStates(options);

	    if (options.extraDisplayCondition === undefined) {
		options.extraDisplayCondition = function() {
		    return true;
		};
	    } else if (typeof(options.extraDisplayCondition) !== 'function') {
		throw new Error("If extraDisplayCondition is specified, it must be a function which returns true or false, was " + options.extraDisplayCondition);
	    }

	    if (options.element === undefined) {
		options.element = "div";
	    } else if (typeof(options.element) !== 'string') {
		throw new Error("If element is specified, it must be a string which is the name of an HTML element, was " + options.element);
	    }

	    if (options.hooks === undefined) {
		options.hooks = function() {
		    // no-op
		};

	    } else if (typeof(options.hooks) !== 'function') {
		throw new Error("If hooks is specified, it must be a function, was: " + options.hooks);
	    }

	    return {
		text: text,
		f: f,
		hover: options.hover,
		element: options.element,
		getState: function(menuState, ownsCurrentProcess) {
		    if (
			options.onlineOffline[menuState.online() ? "online" : "offline"]
			    && options.readWriteSync[menuState.readWriteSync()]
			    && options.embeddedStandalone[menuState.embedded() ? "embedded" : "standalone"]
			    && options.extraDisplayCondition()
		    ) {
			if (isActive && isActive(menuState, ownsCurrentProcess)) {
			    return active;
			} else {
			    return ready;
			}

		    } else {
			return disabled;
		    }
		},
		hooks: options.hooks
	    };
	}
    };

    return m;
};
<|endoftext|>


<commit_before>webpackJsonp([22],{138:function(e,t,n){"use strict";function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i,a,l,u=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),c=function(e,t){return Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}(['\n      <x-layout title="Using Storybook">\n        <x-marked\n          src="','"\n        ></x-marked>\n      </x-layout>\n    '],['\n      <x-layout title="Using Storybook">\n        <x-marked\n          src="','"\n        ></x-marked>\n      </x-layout>\n    ']);n(25),n(28);var h=n(8),m=n(22),p=(0,h.define)((l=a=function(e){function t(){return o(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return s(t,e),u(t,[{key:"render",value:function(){return this.$(c,"\n            If you're building UI components, it's likely you want to have a development environment to test different permutations of your components by actually using them. The React ecosystem came up with a fantastic tool called [Storybook](https://storybook.js.org). If you haven't heard of it, you should check it out. However, if you're here, it's likely you have.\n\n            ### Getting set up\n\n            You'll want to install React (or one of the other supported frameworks) first so that the `getstorybook` command works.\n\n            ```\n            npm i react react-dom\n            ```\n\n            Then you can follow their instructions [here](https://storybook.js.org/basics/quick-start-guide/) to set up Storybook.\n\n            ### Boilerplate\n\n            Once you're all set up, you'll end up with a file called `stories/index.stories.js`. When you open it you'll probably see a bunch of boilerplate. Blow it all away and replace it with this:\n\n            ```js\n            import React from 'react';\n            import { storiesOf } from '@storybook/react';\n            ```\n\n            ### Initial configuration\n\n            Before we start coding in this file, we're going to set up our environment assuming that the browser we're testing in has native support for Custom Elements and Shadow DOM. Since Storybook transpiles everything to ES5 by default, we need to add the [Custom Elements ES5 adapter](https://github.com/webcomponents/webcomponentsjs#custom-elements-es5-adapterjs). To do this, we create a file called [`.storybook/preview-head.html`](https://storybook.js.org/configurations/add-custom-head-tags/) and put the following in it:\n\n            ```html\n            <script src=\"https://unpkg.com/@webcomponents/webcomponentsjs@1.0.22/custom-elements-es5-adapter.js\"><\/script>\n            ```\n\n            This ensures that the adapter is loaded in your UI frame before your application code. If you don't do this, you'll get an error that says something like:\n\n            > Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.\n\n            ### Our test component\n\n            Now that our environment is all set up, we can start coding a test component that's pretty simple. The goal here is to show how to set up Storybook, not necessarily build a complex component.\n\n            Before we start writing our component we need to install a few things:\n\n            1. SkateJS - _duh!_\n            2. [LitHTML](https://github.com/PolymerLabs/lit-html) - we want to show how to use something besides React, inside of a React dev tool.\n            3. The [SkateJS renderer for LitHTML](/renderers/with-lit-html) - just ties LitHTML into Skate.\n\n            ```js\n            npm i skatejs @skatejs/renderer-lit-html lit-html\n            ```\n\n            Once those are installed, we can start writing out component. For the sake of simplicity, we'll just put this in the story file that was created for us. If you were setting up a dev environment for yourself, you'd probably be putting this in a separate directory and importing it.\n\n            ```js\n            import { define, withComponent } from 'skatejs';\n            import withLitHtml from '@skatejs/renderer-lit-html';\n            import { html } from 'lit-html/lib/lit-extended';\n\n            const Hello = define(\n              class extends withComponent(withLitHtml()) {\n                render() {\n                  return html`Hello, <strong><slot>World</slot></strong>!`;\n                }\n              }\n            );\n            ```\n\n            If you're not familiar with how renderers work, see the [docs on renderers](/renderers).\n\n            ### Writing the stories\n\n            Before we write our stories, let's enable a few things in React:\n\n            1. Prefer setting properties (React sets attributes).\n            2. Make custom events work.\n            3. Make passing the custom element constructor as the JSX element tag name\n               just work. Using this along with Skate's [`define()`](http://localhost:8080/utils/define) utility makes HMR\n               work out of the box.\n\n            To do this, we can use [`@skatjes/val`](https://github.com/skatejs/val). First install it:\n\n            ```\n            npm i @skatejs/val\n            ```\n\n            And then all you have to do is import it and patch `React.createElement`:\n\n            ```js\n            // @jsx h\n\n            import val from '@skatejs/val';\n\n            const h = val(React.createElement);\n            ```\n\n            This now makes writing our stories easier:\n\n            ```js\n            storiesOf('Hello', module)\n              .add('with no name', () => <Hello />)\n              .add('with a name', () => <Hello>You</Hello>);\n            ```\n\n            ### Summing up\n\n            Your story file should now look something like:\n\n            ```js\n            // @jsx h\n\n            import React from 'react';\n            import { storiesOf } from '@storybook/react';\n\n            import { define, withComponent } from 'skatejs';\n            import withLitHtml from '@skatejs/renderer-lit-html';\n            import { html } from 'lit-html/lib/lit-extended';\n\n            import val from '@skatejs/val';\n\n            const h = val(React.createElement);\n\n            const Hello = define(\n              class extends withComponent(withLitHtml()) {\n                render() {\n                  return html`Hello, <strong><slot>World</slot></strong>!`;\n                }\n              }\n            );\n\n            storiesOf('Hello', module)\n              .add('with no name', () => <Hello />)\n              .add('with a name', () => <Hello>You</Hello>);\n            ```\n\n            You should now have a fully functional Storybook dev environment that you can use to develop your custom elements.\n          ")}}]),t}(m.Component),a.is="x-pages-guides-storybook",i=l))||i;t.default=p}});<commit_msg>Update site.<commit_after>webpackJsonp([22],{138:function(e,t,n){"use strict";function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i,a,l,u=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),c=function(e,t){return Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}(['\n      <x-layout title="Using Storybook">\n        <x-marked\n          src="','"\n        ></x-marked>\n      </x-layout>\n    '],['\n      <x-layout title="Using Storybook">\n        <x-marked\n          src="','"\n        ></x-marked>\n      </x-layout>\n    ']);n(25),n(28);var h=n(8),m=n(22),p=(0,h.define)((l=a=function(e){function t(){return o(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return s(t,e),u(t,[{key:"render",value:function(){return this.$(c,"\n            If you're building UI components, it's likely you want to have a development environment to test different permutations of your components by actually using them. The React ecosystem came up with a fantastic tool called [Storybook](https://storybook.js.org). If you haven't heard of it, you should check it out. However, if you're here, it's likely you have.\n\n            ### Getting set up\n\n            You'll want to install React (or one of the other supported frameworks) first so that the `getstorybook` command works.\n\n            ```\n            npm i react react-dom\n            ```\n\n            Then you can follow their instructions [here](https://storybook.js.org/basics/quick-start-guide/) to set up Storybook.\n\n            ### Boilerplate\n\n            Once you're all set up, you'll end up with a file called `stories/index.stories.js`. When you open it you'll probably see a bunch of boilerplate. Blow it all away and replace it with this:\n\n            ```js\n            import React from 'react';\n            import { storiesOf } from '@storybook/react';\n            ```\n\n            ### Initial configuration\n\n            Before we start coding in this file, we're going to set up our environment assuming that the browser we're testing in has native support for Custom Elements and Shadow DOM. Since Storybook transpiles everything to ES5 by default, we need to add the [Custom Elements ES5 adapter](https://github.com/webcomponents/webcomponentsjs#custom-elements-es5-adapterjs). To do this, we create a file called [`.storybook/preview-head.html`](https://storybook.js.org/configurations/add-custom-head-tags/) and put the following in it:\n\n            ```html\n            <script src=\"https://unpkg.com/@webcomponents/webcomponentsjs@1.0.22/custom-elements-es5-adapter.js\"><\/script>\n            ```\n\n            This ensures that the adapter is loaded in your UI frame before your application code. If you don't do this, you'll get an error that says something like:\n\n            > Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.\n\n            ### Our test component\n\n            Now that our environment is all set up, we can start coding a test component that's pretty simple. The goal here is to show how to set up Storybook, not necessarily build a complex component.\n\n            Before we start writing our component we need to install a few things:\n\n            1. SkateJS - _duh!_\n            2. [LitHTML](https://github.com/PolymerLabs/lit-html) - we want to show how to use something besides React, inside of a React dev tool.\n            3. The [SkateJS renderer for LitHTML](/renderers/with-lit-html) - just ties LitHTML into Skate.\n\n            ```js\n            npm i skatejs @skatejs/renderer-lit-html lit-html\n            ```\n\n            Once those are installed, we can start writing out component. For the sake of simplicity, we'll just put this in the story file that was created for us. If you were setting up a dev environment for yourself, you'd probably be putting this in a separate directory and importing it.\n\n            ```js\n            import { define, withComponent } from 'skatejs';\n            import withLitHtml from '@skatejs/renderer-lit-html';\n            import { html } from 'lit-html/lib/lit-extended';\n\n            const Hello = define(\n              class extends withComponent(withLitHtml()) {\n                render() {\n                  return html`Hello, <strong><slot>World</slot></strong>!`;\n                }\n              }\n            );\n            ```\n\n            If you're not familiar with how renderers work, see the [docs on renderers](/renderers).\n\n            ### Writing the stories\n\n            Before we write our stories, let's enable a few things in React:\n\n            1. Prefer setting properties (React sets attributes).\n            2. Make custom events work.\n            3. Make passing the custom element constructor as the JSX element tag name\n               just work. Using this along with Skate's [`define()`](http://localhost:8080/utils/define) utility makes HMR\n               work out of the box.\n\n            To do this, we can use [`@skatejs/val`](https://github.com/skatejs/val). First install it:\n\n            ```\n            npm i @skatejs/val\n            ```\n\n            And then all you have to do is import it and patch `React.createElement`:\n\n            ```js\n            // @jsx h\n\n            import val from '@skatejs/val';\n\n            const h = val(React.createElement);\n            ```\n\n            This now makes writing our stories easier:\n\n            ```js\n            storiesOf('Hello', module)\n              .add('with no name', () => <Hello />)\n              .add('with a name', () => <Hello>You</Hello>);\n            ```\n\n            ### Summing up\n\n            Your story file should now look something like:\n\n            ```js\n            // @jsx h\n\n            import React from 'react';\n            import { storiesOf } from '@storybook/react';\n\n            import { define, withComponent } from 'skatejs';\n            import withLitHtml from '@skatejs/renderer-lit-html';\n            import { html } from 'lit-html/lib/lit-extended';\n\n            import val from '@skatejs/val';\n\n            const h = val(React.createElement);\n\n            const Hello = define(\n              class extends withComponent(withLitHtml()) {\n                render() {\n                  return html`Hello, <strong><slot>World</slot></strong>!`;\n                }\n              }\n            );\n\n            storiesOf('Hello', module)\n              .add('with no name', () => <Hello />)\n              .add('with a name', () => <Hello>You</Hello>);\n            ```\n\n            You should now have a fully functional Storybook dev environment that you can use to develop your custom elements.\n          ")}}]),t}(m.Component),a.is="x-pages-guides-storybook",i=l))||i;t.default=p}});<|endoftext|>