<commit_before>// Dependencies
var request = require('request');

// Includes
var login = require('./util/login.js'),
  getSession = require('./util/getSession.js'),
  getCurrentUser = require('./util/getCurrentUser.js'),
  setRank = require('./setRank.js'),
  getRoles = require('./util/getRoles.js'),
  getToken = require('./util/getToken.js'),
  message = require('./message.js');

// Vars
var _jar = request.jar(); // Default cookie jar

// Define
function makeCallbackArray(options,success,failure,always) {
  return {success: options.success || success, failure: options.failure || failure, always: options.always || options.callback || always};
}

exports.login = function(options,password,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return login((j ? j : _jar),options.username,options.password,callbacks);
  } else if (typeof options == 'string')
    return login((jar ? jar : _jar),options,password,callbacks);
};

exports.getSession = function(options) {
  if (options && options.hasOwnProperty('jar'))
    return getSession(options.jar);
  else
    return getSession(options || _jar);
};

exports.getCurrentUser = function(options,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return getCurrentUser((j ? j : _jar), options.option, callbacks);
  } else
    return getCurrentUser((jar ? jar : _jar), options, callbacks);
};

exports.getRoles = function(options,rank,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object')
    return getRoles(options.group, options.rank, callbacks);
  else
    return getRoles(options, rank, callbacks);
};

exports.getToken = function(options,jar,callback,failure) {
  var callbacks = {failure: options.failure || failure};
  if (typeof options == 'object') {
    var j = options.jar;
    return getToken((j ? j : _jar), options.url, callback, callbacks);
  } else
    return getToken((jar ? jar : _jar), options, callback, callbacks);
};

function setRankMain(options,target,roleset,token,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return setRank((j ? j : _jar), options.group, options.target, options.roleset, options.token, callbacks);
  } else
    return setRank((jar ? jar : _jar), options, target, roleset, token, callbacks);
}

exports.setRank = function(options) {
  if (options.rank) {
    getRoles(options.group,options.rank,function(role) {
      options.roleset = role;
      setRankMain(options);
    },options.failure,options.always);
  } else
    setRankMain.apply(undefined, arguments);
};

exports.message = function(options,subject,body,token,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return message((j ? j : _jar), options.recipient, options.subject, options.body, options.token, callbacks);
  } else
    return message((jar ? jar : _jar), options, subject, body, token, callbacks);
};

// Export
exports.getJar = function() {
    return _jar;
};
<commit_msg>Fix<commit_after>// Dependencies
var request = require('request');

// Includes
var login = require('./util/login.js'),
  getSession = require('./util/getSession.js'),
  getCurrentUser = require('./util/getCurrentUser.js'),
  setRank = require('./setRank.js'),
  getRoles = require('./util/getRoles.js'),
  getToken = require('./util/getToken.js'),
  message = require('./message.js');

// Vars
var _jar = request.jar(); // Default cookie jar

// Define
function makeCallbackArray(options,success,failure,always) {
  return {success: options.success || success, failure: options.failure || failure, always: options.always || options.callback || always};
}

exports.login = function(options,password,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return login((j ? j : _jar),options.username,options.password,callbacks);
  } else if (typeof options == 'string')
    return login((jar ? jar : _jar),options,password,callbacks);
};

exports.getSession = function(options) {
  if (options && options.hasOwnProperty('jar'))
    return getSession(options.jar);
  else
    return getSession(options || _jar);
};

exports.getCurrentUser = function(options,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return getCurrentUser((j ? j : _jar), options.option, callbacks);
  } else
    return getCurrentUser((jar ? jar : _jar), options, callbacks);
};

exports.getRoles = function(options,rank,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object')
    return getRoles(options.group, options.rank, callbacks);
  else
    return getRoles(options, rank, callbacks);
};

exports.getToken = function(options,jar,callback,failure) {
  var callbacks = {failure: options.failure || failure};
  if (typeof options == 'object') {
    var j = options.jar;
    return getToken((j ? j : _jar), options.url, callback, callbacks);
  } else
    return getToken((jar ? jar : _jar), options, callback, callbacks);
};

function setRankMain(options,target,roleset,token,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return setRank((j ? j : _jar), options.group, options.target, options.roleset, options.token, callbacks);
  } else
    return setRank((jar ? jar : _jar), options, target, roleset, token, callbacks);
}

exports.setRank = function(options) {
  if (options.rank) {
    getRoles(options.group,options.rank,{success: function(role) {
      options.roleset = role;
      setRankMain(options);
    }, failure: options.failure});
  } else
    setRankMain.apply(undefined, arguments);
};

exports.message = function(options,subject,body,token,jar,success,failure,always) {
  var callbacks = makeCallbackArray(options,success,failure,always);
  if (typeof options == 'object') {
    var j = options.jar;
    return message((j ? j : _jar), options.recipient, options.subject, options.body, options.token, callbacks);
  } else
    return message((jar ? jar : _jar), options, subject, body, token, callbacks);
};

// Export
exports.getJar = function() {
    return _jar;
};
<|endoftext|>


<commit_before>import Vue from 'vue'

import debounce from '../../utils/debounce.js'
import { height } from '../../utils/dom.js'
import { getScrollTarget, getScrollHeight, getScrollPosition } from '../../utils/scroll.js'
import { listenOpts } from '../../utils/event.js'
import { slot, uniqueSlot } from '../../utils/slot.js'

export default Vue.extend({
  name: 'QInfiniteScroll',

  props: {
    offset: {
      type: Number,
      default: 500
    },
    debounce: {
      type: [String, Number],
      default: 100
    },
    scrollTarget: {},
    disable: Boolean,
    reverse: Boolean
  },

  data () {
    return {
      index: 0,
      fetching: false,
      working: true
    }
  },

  watch: {
    disable (val) {
      if (val === true) {
        this.stop()
      }
      else {
        this.resume()
      }
    },

    scrollTarget () {
      this.updateScrollTarget()
    },

    debounce (val) {
      this.__setDebounce(val)
    }
  },

  methods: {
    poll () {
      if (this.disable === true || this.fetching === true || this.working === false) {
        return
      }

      const
        scrollHeight = getScrollHeight(this.scrollContainer),
        scrollPosition = getScrollPosition(this.scrollContainer),
        containerHeight = height(this.scrollContainer)

      if (this.reverse === false) {
        if (scrollPosition + containerHeight + this.offset >= scrollHeight) {
          this.trigger()
        }
      }
      else {
        if (scrollPosition < this.offset) {
          this.trigger()
        }
      }
    },

    trigger () {
      if (this.disable === true || this.fetching === true || this.working === false) {
        return
      }

      this.index++
      this.fetching = true

      const heightBefore = getScrollHeight(this.scrollContainer)

      this.$emit('load', this.index, stop => {
        if (this.working === true) {
          this.fetching = false
          this.$nextTick(() => {
            if (this.reverse === true) {
              const
                heightAfter = getScrollHeight(this.scrollContainer),
                scrollPosition = getScrollPosition(this.scrollContainer),
                heightDifference = heightAfter - heightBefore

              this.scrollContainer.scrollTop = scrollPosition + heightDifference
            }

            if (stop === true) {
              this.stop()
            }
            else {
              this.$el.closest('body') && this.poll()
            }
          })
        }
      })
    },

    reset () {
      this.index = 0
    },

    resume () {
      if (this.working === false) {
        this.working = true
        this.scrollContainer.addEventListener('scroll', this.poll, listenOpts.passive)
      }
      this.immediatePoll()
    },

    stop () {
      if (this.working === true) {
        this.working = false
        this.fetching = false
        this.scrollContainer.removeEventListener('scroll', this.poll, listenOpts.passive)
      }
    },

    updateScrollTarget () {
      if (this.scrollContainer && this.working === true) {
        this.scrollContainer.removeEventListener('scroll', this.poll, listenOpts.passive)
      }

      if (typeof this.scrollTarget === 'string') {
        this.scrollContainer = document.querySelector(this.scrollTarget)
        if (this.scrollContainer === null) {
          console.error(`InfiniteScroll: scroll target container "${this.scrollTarget}" not found`, this)
          return
        }
      }
      else {
        this.scrollContainer = this.scrollTarget === document.defaultView || this.scrollTarget instanceof Element
          ? this.scrollTarget
          : getScrollTarget(this.$el)
      }

      if (this.working === true) {
        this.scrollContainer.addEventListener('scroll', this.poll, listenOpts.passive)
      }
    },

    __setDebounce (val) {
      val = parseInt(val, 10)
      if (val <= 0) {
        this.poll = this.immediatePoll
      }
      else {
        this.poll = debounce(this.immediatePoll, isNaN(val) === true ? 100 : val)
      }
    }
  },

  mounted () {
    this.immediatePoll = this.poll
    this.__setDebounce(this.debounce)

    this.updateScrollTarget()
    this.immediatePoll()

    if (this.reverse === true) {
      const
        scrollHeight = getScrollHeight(this.scrollContainer),
        containerHeight = height(this.scrollContainer)

      this.scrollContainer.scrollTop = scrollHeight - containerHeight
    }
  },

  beforeDestroy () {
    if (this.working === true) {
      this.scrollContainer.removeEventListener('scroll', this.poll, listenOpts.passive)
    }
  },

  render (h) {
    const child = uniqueSlot(this, 'default', [])

    if (this.disable !== true && this.working === true) {
      child[this.reverse === false ? 'push' : 'unshift'](
        h('div', {
          staticClass: 'q-infinite-scroll__loading',
          class: this.fetching === true ? '' : 'invisible'
        }, slot(this, 'loading'))
      )
    }

    return h('div', { staticClass: 'q-infinite-scroll' }, child)
  }
})
<commit_msg>fix(QInfiniteScroll): Use setScrollPosition to keep scroll when in reverse mode #5906<commit_after>import Vue from 'vue'

import debounce from '../../utils/debounce.js'
import { height } from '../../utils/dom.js'
import { getScrollTarget, getScrollHeight, getScrollPosition, setScrollPosition } from '../../utils/scroll.js'
import { listenOpts } from '../../utils/event.js'
import { slot, uniqueSlot } from '../../utils/slot.js'

export default Vue.extend({
  name: 'QInfiniteScroll',

  props: {
    offset: {
      type: Number,
      default: 500
    },
    debounce: {
      type: [String, Number],
      default: 100
    },
    scrollTarget: {},
    disable: Boolean,
    reverse: Boolean
  },

  data () {
    return {
      index: 0,
      fetching: false,
      working: true
    }
  },

  watch: {
    disable (val) {
      if (val === true) {
        this.stop()
      }
      else {
        this.resume()
      }
    },

    scrollTarget () {
      this.updateScrollTarget()
    },

    debounce (val) {
      this.__setDebounce(val)
    }
  },

  methods: {
    poll () {
      if (this.disable === true || this.fetching === true || this.working === false) {
        return
      }

      const
        scrollHeight = getScrollHeight(this.scrollContainer),
        scrollPosition = getScrollPosition(this.scrollContainer),
        containerHeight = height(this.scrollContainer)

      if (this.reverse === false) {
        if (scrollPosition + containerHeight + this.offset >= scrollHeight) {
          this.trigger()
        }
      }
      else {
        if (scrollPosition < this.offset) {
          this.trigger()
        }
      }
    },

    trigger () {
      if (this.disable === true || this.fetching === true || this.working === false) {
        return
      }

      this.index++
      this.fetching = true

      const heightBefore = getScrollHeight(this.scrollContainer)

      this.$emit('load', this.index, stop => {
        if (this.working === true) {
          this.fetching = false
          this.$nextTick(() => {
            if (this.reverse === true) {
              const
                heightAfter = getScrollHeight(this.scrollContainer),
                scrollPosition = getScrollPosition(this.scrollContainer),
                heightDifference = heightAfter - heightBefore

              setScrollPosition(this.scrollContainer, scrollPosition + heightDifference)
            }

            if (stop === true) {
              this.stop()
            }
            else {
              this.$el.closest('body') && this.poll()
            }
          })
        }
      })
    },

    reset () {
      this.index = 0
    },

    resume () {
      if (this.working === false) {
        this.working = true
        this.scrollContainer.addEventListener('scroll', this.poll, listenOpts.passive)
      }
      this.immediatePoll()
    },

    stop () {
      if (this.working === true) {
        this.working = false
        this.fetching = false
        this.scrollContainer.removeEventListener('scroll', this.poll, listenOpts.passive)
      }
    },

    updateScrollTarget () {
      if (this.scrollContainer && this.working === true) {
        this.scrollContainer.removeEventListener('scroll', this.poll, listenOpts.passive)
      }

      if (typeof this.scrollTarget === 'string') {
        this.scrollContainer = document.querySelector(this.scrollTarget)
        if (this.scrollContainer === null) {
          console.error(`InfiniteScroll: scroll target container "${this.scrollTarget}" not found`, this)
          return
        }
      }
      else {
        this.scrollContainer = this.scrollTarget === document.defaultView || this.scrollTarget instanceof Element
          ? this.scrollTarget
          : getScrollTarget(this.$el)
      }

      if (this.working === true) {
        this.scrollContainer.addEventListener('scroll', this.poll, listenOpts.passive)
      }
    },

    __setDebounce (val) {
      val = parseInt(val, 10)
      if (val <= 0) {
        this.poll = this.immediatePoll
      }
      else {
        this.poll = debounce(this.immediatePoll, isNaN(val) === true ? 100 : val)
      }
    }
  },

  mounted () {
    this.immediatePoll = this.poll
    this.__setDebounce(this.debounce)

    this.updateScrollTarget()
    this.immediatePoll()

    if (this.reverse === true) {
      const
        scrollHeight = getScrollHeight(this.scrollContainer),
        containerHeight = height(this.scrollContainer)

      setScrollPosition(this.scrollContainer.scrollTop, scrollHeight - containerHeight)
    }
  },

  beforeDestroy () {
    if (this.working === true) {
      this.scrollContainer.removeEventListener('scroll', this.poll, listenOpts.passive)
    }
  },

  render (h) {
    const child = uniqueSlot(this, 'default', [])

    if (this.disable !== true && this.working === true) {
      child[this.reverse === false ? 'push' : 'unshift'](
        h('div', {
          staticClass: 'q-infinite-scroll__loading',
          class: this.fetching === true ? '' : 'invisible'
        }, slot(this, 'loading'))
      )
    }

    return h('div', { staticClass: 'q-infinite-scroll' }, child)
  }
})
<|endoftext|>


<commit_before>'use strict'
// move to adapter much better
var Event = require('vigour-js/lib/event')
var Base = require('vigour-js/lib/base')

var merge = require('lodash/object/merge')
// var Hub = require('../')
var setWithPath = require('vigour-js/lib/util/setwithpath')

exports.define = {
  receiveSubscription (subscriptions, id, event) {
    var hub = this
    // if (this._scope) {
    //   console.log('----------------------------------------------------->', this._scope)
    // }
    var client = hub.clients[id]
    // more batching here!
    var ev = new Event('subscription')
    // 1. SCOPES/NORMAL NO DIFFERENCE
    // 2. MAKE A 'HUBSUBSCRIPTIONS THING' -- do $ -- when , true it does not add listeners only sends up
    // 3. use attach on clients -- empty remove the subs -- this is a special thing for the attach field it uses
    // 4. just add a listener on remove on the client -- make sure it fires there where some false fields
    // 5. run function -- a walker that walks your map from a certain point collects the data and sends it
    // console.log('incoming subscription', JSON.stringify(subscriptions, false, 2))
    var response = {}
    var hashes = {} // last stamp
    // this will be stored of course over all subs

    for (var i in subscriptions) {
      // if(i === '')
      for (var j in subscriptions[i]) {
        if (!j || !i) {
          console.log('fraudulent request old crap', j)
          return
        }
        let path = j.split('.')
        if (!path || path[0] === void 0) {
          console.log('fraudulent request old crap', j)
          return
        }
        // console.log
        console.log('hello!', 'dogin it', i, j, path, subscriptions[i][j])
        // also have thing here
        handleSubs(
          j === '$' ? hub : hub.get(path, {}),
          subscriptions[i][j],
          void 0,
          client,
          path[0] === '$' ? response : setWithPath(response, path, {}),
          ev,
          response,
          hub._scope,
          hub
        )
      }
      hashes[i] = true // replace with last stamp!
    }
    // make multi hash of all seperate subs?
    // console.log(JSON.stringify(response, false, 2))

    // if (this._scope) {
    //   console.log('----------------------------------------------------->????', this._scope,
    //     JSON.stringify(response, false, 2)
    //   )
    // }
    console.log('?!', response, ev.stamp)
    client.connection.origin.send({
      stamp: hub.adapter.id + '|' + ev.stamp, // + id
      set: response,
      hash: hashes
    })
    ev.trigger()
  }
}

// on initial -- send info back to client
function handleSubs (obs, map, key, client, returnobj, event, top, scope, hub) {
  if (key) {
    if (obs._input instanceof Base) {
      if (obs.lookUp('_scope') !== scope) {
        // console.error('WTF WTF', hub._scope, obs._path)
        obs = hub.get(obs.path, {})
      }
      // add ref listener!
      hub.subscribe(obs.path, [sendtoclient, client])
      // console.log('add ref listener!')
      returnobj[key] = obs._input.syncPath.concat()
      returnobj[key].unshift('$')
      var o = {}
      // if(!obs)
      setWithPath(o, obs._input.syncPath, {})
      merge(top, o)
      returnobj = top
      for (var n in obs._input.syncPath) {
        returnobj = returnobj[obs._input.syncPath[n]]
      }
      // have to remove previous ones nested do it in handle...
      var xxx = obs._input
      obs.on('reference', [ function (data, ev, client) {
        if ((this._input && this._input !== xxx && ev.stamp !== event.stamp) && (this.lookUp('_scope') === client.lookUp('_scope'))) {
          xxx = this._input
          var x = {}
          var t = {}
          handleSubs(this._input, map, void 0, client, t, ev, x, scope, hub)
          // sendtoclient (data, event, client, payload) {
          // sendtoclient.call(this, data, event, client, t)
          if (this._input) {
            setWithPath(x, this._input.syncPath, t)
            var y = {}
            setWithPath(y, this.syncPath, this._input.syncPath.concat([])).unshift('$')
            merge(x, y)
            // console.log('\n', JSON.stringify(x, false, 2))
            client.connection.origin.send({
              stamp: event.stamp,
              set: x
              // hash: hashes
            })
          }
        }
      }, client], client.val)

      handleSubs(obs._input, map, void 0, client, returnobj, event, top, scope, hub)
      return
    } else {
      returnobj = returnobj[key] = {}
    }
  }
  for (var field in map) {
    if (field === '$') {
      handleSubs(hub, map[field], void 0, client, returnobj, event, top, scope, hub)
    } else if (field === 'parent') {
      handleSubs(obs._parent, map[field], void 0, client, returnobj, event, top, scope, hub)
    } else if (field === 'val') {
      hub.subscribe(obs.path, [sendtoclient, client])
      returnobj.val = obs._input
    } else if (field === '*') {
      console.log('yo yo yo')
      let lorigin = obs.origin
      hub.subscribe(obs.path, 'property', [ function (data, event, client) {
        var payload = {}
        var origin = this.origin
        if (origin !== lorigin) {
          // remove all!
          obs.origin.each(function (p, key) {
            if (key) {
              payload[key] = null
            }
          })
        }
        lorigin = origin
        let payloadTop = {}
        // remove subs - of course this must be handled better...
        if (data) {
          if (data.added) {
            for (let i in data.added) {
              payload[data.added[i]] = {}
              handleSubs(origin[data.added[i]], map[field], key, client, payload[data.added[i]], event, payloadTop, scope, hub)
            }
          }
          if (data.removed) {
            for (let i in data.removed) {
              payload[data.removed[i]] = null
            }
          }
        }
        setWithPath(payloadTop, lorigin.path, payload)
        client.connection.origin.send({
          stamp: event.stamp,
          set: payloadTop
          // hash: hashes
        })
        // sendtoclient.call(this, data, event, client, payloadTop)
      }, client], client.val)
      // get your listener on
      // console.log('yoxxxxx yo yo', obs.path, obs._input, returnobj, obs.keys())

      obs.origin.each(function (p, key) {
        // console.log('----->', key)
        handleSubs(p, map[field], key, client, returnobj, event, top, scope, hub)
      })
    } else {
      var t = obs.get(field, {})
      handleSubs(t, map[field], field, client, returnobj, event, top, scope, hub)
    }
  }
}

// send (observable, hub, data, event, subscriptions) {
function sendtoclient (data, event, client, payload) {
  var hub = client._parent._parent
  // overwrites ofcourse need to verify -- does not work now for shizzle!
  if (this.lookUp('_scope') === client.lookUp('_scope')) {
    console.log('-------->', payload)
    client.send(this, hub, payload || this._input, event)
  }
}

// // temp fix this should work in the subscription prob
// function reflistener (data, event, client) {
//   var hub = client._parent._parent
//   // overwrites ofcourse need to verify -- does not work now for shizzle!
//   if (this.lookUp('_scope') === client.lookUp('_scope')) {
//     client.send(this, hub, this._input, event)
//   }
// }
<commit_msg>gaurd<commit_after>'use strict'
// move to adapter much better
var Event = require('vigour-js/lib/event')
var Base = require('vigour-js/lib/base')

var merge = require('lodash/object/merge')
// var Hub = require('../')
var setWithPath = require('vigour-js/lib/util/setwithpath')

exports.define = {
  receiveSubscription (subscriptions, id, event) {
    var hub = this
    // if (this._scope) {
    //   console.log('----------------------------------------------------->', this._scope)
    // }
    var client = hub.clients[id]
    // more batching here!
    var ev = new Event('subscription')
    // 1. SCOPES/NORMAL NO DIFFERENCE
    // 2. MAKE A 'HUBSUBSCRIPTIONS THING' -- do $ -- when , true it does not add listeners only sends up
    // 3. use attach on clients -- empty remove the subs -- this is a special thing for the attach field it uses
    // 4. just add a listener on remove on the client -- make sure it fires there where some false fields
    // 5. run function -- a walker that walks your map from a certain point collects the data and sends it
    // console.log('incoming subscription', JSON.stringify(subscriptions, false, 2))
    var response = {}
    var hashes = {} // last stamp
    // this will be stored of course over all subs

    for (var i in subscriptions) {
      // if(i === '')
      for (var j in subscriptions[i]) {
        if (!j || !i) {
          console.log('fraudulent request old crap', j)
          return
        }
        let path = j.split('.')
        if (!path || path[0] === void 0) {
          console.log('fraudulent request old crap', j)
          return
        }
        // console.log
        if (subscriptions[i][j].property || subscriptions[i][j].data) {
          console.log('probably old dont do!')
          return
        }
        console.log('hello!', 'dogin it', i, j, path, subscriptions[i][j], response, path)
        // also have thing here
        handleSubs(
          j === '$' ? hub : hub.get(path, {}),
          subscriptions[i][j],
          void 0,
          client,
          path[0] === '$' ? response : setWithPath(response, path, {}),
          ev,
          response,
          hub._scope,
          hub
        )
              console.log('\n ---xxxx-->')

      }
      hashes[i] = true // replace with last stamp!
    }
    // make multi hash of all seperate subs?
    // console.log(JSON.stringify(response, false, 2))

    // if (this._scope) {
    //   console.log('----------------------------------------------------->????', this._scope,
    //     JSON.stringify(response, false, 2)
    //   )
    // }
    console.log('?!', response, ev.stamp)
    client.connection.origin.send({
      stamp: hub.adapter.id + '|' + ev.stamp, // + id
      set: response,
      hash: hashes
    })
    ev.trigger()
  }
}

// on initial -- send info back to client
function handleSubs (obs, map, key, client, returnobj, event, top, scope, hub) {
  if (key) {
    if (obs._input instanceof Base) {
      if (obs.lookUp('_scope') !== scope) {
        // console.error('WTF WTF', hub._scope, obs._path)
        obs = hub.get(obs.path, {})
      }
      // add ref listener!
      hub.subscribe(obs.path, [sendtoclient, client])
      // console.log('add ref listener!')
      returnobj[key] = obs._input.syncPath.concat()
      returnobj[key].unshift('$')
      var o = {}
      // if(!obs)
      console.log('\n ----->',o, obs, obs._input && obs._input.syncPath, top)
      setWithPath(o, obs._input.syncPath, {})
      merge(top, o)
      returnobj = top
      for (var n in obs._input.syncPath) {
        returnobj = returnobj[obs._input.syncPath[n]]
      }
      // have to remove previous ones nested do it in handle...
      var xxx = obs._input
      obs.on('reference', [ function (data, ev, client) {
        if ((this._input && this._input !== xxx && ev.stamp !== event.stamp) && (this.lookUp('_scope') === client.lookUp('_scope'))) {
          xxx = this._input
          var x = {}
          var t = {}
          handleSubs(this._input, map, void 0, client, t, ev, x, scope, hub)
          // sendtoclient (data, event, client, payload) {
          // sendtoclient.call(this, data, event, client, t)
          if (this._input) {
            setWithPath(x, this._input.syncPath, t)
            var y = {}
            setWithPath(y, this.syncPath, this._input.syncPath.concat([])).unshift('$')
            merge(x, y)
            // console.log('\n', JSON.stringify(x, false, 2))
            client.connection.origin.send({
              stamp: event.stamp,
              set: x
              // hash: hashes
            })
          }
        }
      }, client], client.val)

      handleSubs(obs._input, map, void 0, client, returnobj, event, top, scope, hub)
      return
    } else {
      returnobj = returnobj[key] = {}
    }
  }
  for (var field in map) {
    if (field === '$') {
      handleSubs(hub, map[field], void 0, client, returnobj, event, top, scope, hub)
    } else if (field === 'parent') {
      handleSubs(obs._parent, map[field], void 0, client, returnobj, event, top, scope, hub)
    } else if (field === 'val') {
      hub.subscribe(obs.path, [sendtoclient, client])
      returnobj.val = obs._input
    } else if (field === '*') {
      console.log('yo yo yo')
      let lorigin = obs.origin
      hub.subscribe(obs.path, 'property', [ function (data, event, client) {
        var payload = {}
        var origin = this.origin
        if (origin !== lorigin) {
          // remove all!
          obs.origin.each(function (p, key) {
            if (key) {
              payload[key] = null
            }
          })
        }
        lorigin = origin
        let payloadTop = {}
        // remove subs - of course this must be handled better...
        if (data) {
          if (data.added) {
            for (let i in data.added) {
              payload[data.added[i]] = {}
              handleSubs(origin[data.added[i]], map[field], key, client, payload[data.added[i]], event, payloadTop, scope, hub)
            }
          }
          if (data.removed) {
            for (let i in data.removed) {
              payload[data.removed[i]] = null
            }
          }
        }
        setWithPath(payloadTop, lorigin.path, payload)
        client.connection.origin.send({
          stamp: event.stamp,
          set: payloadTop
          // hash: hashes
        })
        // sendtoclient.call(this, data, event, client, payloadTop)
      }, client], client.val)
      // get your listener on
      // console.log('yoxxxxx yo yo', obs.path, obs._input, returnobj, obs.keys())

      obs.origin.each(function (p, key) {
        // console.log('----->', key)
        handleSubs(p, map[field], key, client, returnobj, event, top, scope, hub)
      })
    } else {
      var t = obs.get(field, {})
      handleSubs(t, map[field], field, client, returnobj, event, top, scope, hub)
    }
  }
}

// send (observable, hub, data, event, subscriptions) {
function sendtoclient (data, event, client, payload) {
  var hub = client._parent._parent
  // overwrites ofcourse need to verify -- does not work now for shizzle!
  if (this.lookUp('_scope') === client.lookUp('_scope')) {
    console.log('-------->', payload)
    client.send(this, hub, payload || this._input, event)
  }
}

// // temp fix this should work in the subscription prob
// function reflistener (data, event, client) {
//   var hub = client._parent._parent
//   // overwrites ofcourse need to verify -- does not work now for shizzle!
//   if (this.lookUp('_scope') === client.lookUp('_scope')) {
//     client.send(this, hub, this._input, event)
//   }
// }
<|endoftext|>


<commit_before>// Karma configuration

// base path, that will be used to resolve files and exclude
basePath = '';

// list of files / patterns to load in the browser
files = [
  JASMINE,
  JASMINE_ADAPTER,
  'bower_components/angular/angular.js',
  'bower_components/angular-mocks/angular-mocks.js',
  'bower_components/i18next/i18next.min.js',
  'src/provider.js',
  'src/**/*.js',
  'test/**/*Spec.js'
];

// list of files to exclude
exclude = [];

// test results reporter to use
// possible values: 'dots', 'progress', 'junit'
reporters = ['progress'];

// web server port
port = 9876;

// cli runner port
runnerPort = 9100;

// enable / disable colors in the output (reporters and logs)
colors = true;

// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel = LOG_INFO;

// enable / disable watching file and executing tests whenever any file changes
autoWatch = true;

// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers = ['PhantomJS'];

// If browser does not capture in given timeout [ms], kill it
captureTimeout = 60000;

// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun = false;
<commit_msg>fix(test): new karma config<commit_after>// Karma configuration

'use strict';

module.exports = function(config) {

	config.set({

		// base path, that will be used to resolve files and exclude
		basePath: '',

		// testing framework to use (jasmine/mocha/qunit/...)
		frameworks: ['jasmine'],

		// list of files / patterns to load in the browser
		files: [
			'bower_components/angular/angular.js',
			'bower_components/angular-mocks/angular-mocks.js',
			'bower_components/i18next/i18next.min.js',
			'src/provider.js',
			'src/**/*.js',
			'test/**/*Spec.js'
		],

		// list of files to exclude
		exclude: [],

		// web server port
		port: 9876,

		// cli runner port
		runnerPort: 9100,

		// enable / disable colors in the output (reporters and logs)
		colors: true,

		// level of logging
		// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
		logLevel: config.LOG_INFO,

		// enable / disable watching file and executing tests whenever any file changes
		autoWatch: true,

		// Start these browsers, currently available:
		// - Chrome
		// - ChromeCanary
		// - Firefox
		// - Opera
		// - Safari (only Mac)
		// - PhantomJS
		// - IE (only Windows)
		browsers: ['PhantomJS'],

		// If browser does not capture in given timeout [ms], kill it
		captureTimeout: 60000

	});
};
<|endoftext|>


<commit_before>var d3 = require('d3');
var _ = require('underscore');
var svg = require('./svg.js');

function Layer() {
  this._data = null;
  this._width = 1000;
  this._height = 800;
  this.x = d3.scale.linear();
  this.y = d3.scale.linear();
  this._geoms = [];

  this.__call__ = function(selection) {
    _.each(this.geom(), function(layer) {
      layer(selection);
    }, this);
  }
}

Layer.prototype.xview = function(domain) {
  if (!arguments.length) return this.x.domain();
  this.x.domain(domain);

  // set xview on all geoms
  _.each(this.geom(), function(geom) {
    geom.xview(domain);
  });
  return this;
}

Layer.prototype.yview = function(domain) {
  if (!arguments.length) return this.y.domain();
  this.y.domain(domain);

  // set yview on all geoms
  _.each(this.geom(), function(geom) {
    geom.yview(domain);
  });
  return this;
}

Layer.prototype.height = function(height) {
  if (!arguments.length) return this._height;
  this._height = height;
  this.y.range([height, 0]);

  // set height on all geoms
  _.each(this.geom(), function(geom) {
    geom.height(height);
  });
  return this;
}

Layer.prototype.width = function(width) {
  if (!arguments.length) return this._width;
  this._width = width;
  this.x.range([0, width]);

  // set width on all geoms
  _.each(this.geom(), function(geom) {
    geom.width(width);
  });
  return this;
}

Layer.prototype.data = function(data) {
  if (!arguments.length) return this._data;
  this._data = data;
  //this.x.domain([0, data.length-1]);
  //this.y.domain(d3.extent(data));
  return this;
}

Layer.prototype.data_length = function() {
  var data = this.data();
  if (data instanceof Array) {
    return this.data().length;
  }
  for(var key in data) {
    var series = data[key];
    if (Array.isArray(series)) {
      return series.length;
    }
  }
}

Layer.prototype.update = function() {
  var domain = this.x.domain();
  var data = this.data();
  // Reset the internal y-domain
  if (data instanceof Array) {
    this.y.domain(d3.extent(data.slice(domain[0], domain[1])));
  }
  if ('y' in data) {
    this.y.domain(d3.extent(data.y.slice(domain[0], domain[1])));
  }
  if (!this.geom()) {
    return this;
  }

  // call update on all geoms
  _.each(this.geom(), function(geom) {
    geom.update(domain);
  });
  // taken form figure.js. grab consolidated yview
  y_domains = _.invoke(this.geom(), 'yview');
  //merged y-domains
  y_min = d3.min(y_domains, function(d) { return d[0] });
  y_max = d3.max(y_domains, function(d) { return d[1] });
  this.yview([y_min, y_max]);
  return this;
}

Layer.prototype.geom = function(layer) {
  if (!arguments.length) return this._geoms;
  if(layer.data()) {
    throw new Error("Cannot composite a layer that has already bound data");
  }
  layer.data(this.data());
  layer.x = this.x.copy();
  layer.y = this.y.copy();
  this._geoms.push(layer);
  return this;
}

// shortcut for creating svg elements
Layer.prototype.createElement = svg.createElement;

module.exports = Layer;

var View = require('./view.js');
Layer.prototype.view = function() {
  return new View().layer(this);
}
<commit_msg>added default legend_icon<commit_after>var d3 = require('d3');
var _ = require('underscore');
var svg = require('./svg.js');

function Layer() {
  this._data = null;
  this._width = 1000;
  this._height = 800;
  this.x = d3.scale.linear();
  this.y = d3.scale.linear();
  this._geoms = [];

  this.__call__ = function(selection) {
    _.each(this.geom(), function(layer) {
      layer(selection);
    }, this);
  }
}

Layer.prototype.xview = function(domain) {
  if (!arguments.length) return this.x.domain();
  this.x.domain(domain);

  // set xview on all geoms
  _.each(this.geom(), function(geom) {
    geom.xview(domain);
  });
  return this;
}

Layer.prototype.yview = function(domain) {
  if (!arguments.length) return this.y.domain();
  this.y.domain(domain);

  // set yview on all geoms
  _.each(this.geom(), function(geom) {
    geom.yview(domain);
  });
  return this;
}

Layer.prototype.height = function(height) {
  if (!arguments.length) return this._height;
  this._height = height;
  this.y.range([height, 0]);

  // set height on all geoms
  _.each(this.geom(), function(geom) {
    geom.height(height);
  });
  return this;
}

Layer.prototype.width = function(width) {
  if (!arguments.length) return this._width;
  this._width = width;
  this.x.range([0, width]);

  // set width on all geoms
  _.each(this.geom(), function(geom) {
    geom.width(width);
  });
  return this;
}

Layer.prototype.data = function(data) {
  if (!arguments.length) return this._data;
  this._data = data;
  //this.x.domain([0, data.length-1]);
  //this.y.domain(d3.extent(data));
  return this;
}

Layer.prototype.data_length = function() {
  var data = this.data();
  if (data instanceof Array) {
    return this.data().length;
  }
  for(var key in data) {
    var series = data[key];
    if (Array.isArray(series)) {
      return series.length;
    }
  }
}

Layer.prototype.update = function() {
  var domain = this.x.domain();
  var data = this.data();
  // Reset the internal y-domain
  if (data instanceof Array) {
    this.y.domain(d3.extent(data.slice(domain[0], domain[1])));
  }
  if ('y' in data) {
    this.y.domain(d3.extent(data.y.slice(domain[0], domain[1])));
  }
  if (!this.geom()) {
    return this;
  }

  // call update on all geoms
  _.each(this.geom(), function(geom) {
    geom.update(domain);
  });
  // taken form figure.js. grab consolidated yview
  y_domains = _.invoke(this.geom(), 'yview');
  //merged y-domains
  y_min = d3.min(y_domains, function(d) { return d[0] });
  y_max = d3.max(y_domains, function(d) { return d[1] });
  this.yview([y_min, y_max]);
  return this;
}

Layer.prototype.geom = function(layer) {
  if (!arguments.length) return this._geoms;
  if(layer.data()) {
    throw new Error("Cannot composite a layer that has already bound data");
  }
  layer.data(this.data());
  layer.x = this.x.copy();
  layer.y = this.y.copy();
  this._geoms.push(layer);
  return this;
}

// shortcut for creating svg elements
Layer.prototype.createElement = svg.createElement;

Layer.prototype.legend_icon = function() {
  return null;
}

module.exports = Layer;

var View = require('./view.js');
Layer.prototype.view = function() {
  return new View().layer(this);
}
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var expect = require('chai').expect;
var sinon = require('sinon');
var moment = require('moment');
var _ = require('lodash');
var Qs = require('qs');
var TestHelpers = require('../../support/TestHelpers');
var ExplorerActions = require('../../../client/js/app/actions/ExplorerActions');
var FilterUtils = require('../../../client/js/app/utils/FilterUtils');
var ValidationUtils = require('../../../client/js/app/utils/ValidationUtils');
var ExplorerValidations = require('../../../client/js/app/validations/ExplorerValidations');
var ExplorerUtils = require('../../../client/js/app/utils/ExplorerUtils');

describe('utils/ExplorerUtils', function() {
  describe('extraction event limit', function () {
    it('should be 100', function () {
      assert.strictEqual(ExplorerUtils.EXRACTION_EVENT_LIMIT, 100);
    });
  });

  describe('queryJSON', function () {
    it('should remove values that are not part of the query params that get sent to Keen', function () {
      var explorer = {
        query: {
          someVal: 'shouldBeRemoved',
          someOtherVal: 'shouldAlsoBeRemoved',
          event_collection: 'sholdRemain',
          analysis_type: 'shouldRemain'
        }
      };
      assert.deepEqual(ExplorerUtils.queryJSON(explorer), {
        event_collection: 'sholdRemain',
        analysis_type: 'shouldRemain'
      });
    });
    it('should remove the timezone if the timeframe_type is absolute', function () {
      var explorer = {
        timeframe_type: 'absolute',
        query: {
          timezone: 'US/Mountain',
          time: {
            start: new Date("Jan 1, 2015 1:00 PM"),
            end: new Date("Jan 2, 2015 1:00 PM")
          }
        }
      };
      assert.notDeepProperty(ExplorerUtils.queryJSON(explorer), 'timezone');
    });
    it('should remove values that are not valid query values', function () {
      var explorer = {
        query: {
          event_collection: undefined,
          analysis_type: 'shouldRemain',
          filters: []
        }
      };
      assert.deepEqual(ExplorerUtils.queryJSON(explorer), {
        analysis_type: 'shouldRemain'
      });
    });
    it('should call FilterUtils.queryJSON for every filter', function () {
      var explorer = { query: { filters: [{}, {}, {}] } };
      var stub = sinon.stub(FilterUtils, 'queryJSON');
      ExplorerUtils.queryJSON(explorer);
      assert.lengthOf(stub.getCalls(), 3);
      FilterUtils.queryJSON.restore();
    });
    it('should remove empty filters', function () {
      var explorer = {
        query: {
          filters: [
            {
              property_name: 'click',
              operator: 'eq',
              property_value: 'button',
              coercion_type: 'String'
            },
            {},
            {}
          ]
        }
      };
      var json = ExplorerUtils.queryJSON(explorer);
      assert.lengthOf(json.filters, 1);
    });
    it('should remove the fitlers key if it is empty after getting their queryJSON verisons', function () {
      var explorer = {
        query: {
          event_collection: 'click',
          analysis_type: 'count',
          filters: [
            {  property_name: 'click' },
            {},
            {}
          ]
        }
      };
      var json = ExplorerUtils.queryJSON(explorer);
      assert.isUndefined(json.filters);
    });
    it('should set the timeframe if there is one', function () {
      var explorer = {
        timeframe_type: 'relative',
        query: {
          event_collection: 'click',
          analysis_type: 'count',
          time: {
            relativity: 'this',
            amount: '1',
            sub_timeframe: 'days'
          }
        }
      };
      var json = ExplorerUtils.queryJSON(explorer);
      assert.deepEqual(json, {
        event_collection: 'click',
        analysis_type: 'count',
        timeframe: 'this_1_days'
      });
    });
  });

  describe('runQuery', function () {
    it('should create a Keen.Query', function () {
      var client = { run: sinon.spy() };
      var query = {
        analysis_type: 'count',
        event_collection: 'click'
      };
      ExplorerUtils.runQuery({
        client: client,
        query: query,
        success: function(){},
        error: function(){},
        complete: function(){}
      });
      assert.strictEqual(client.run.getCall(0).args[0].analysis, 'count');
      assert.deepEqual(client.run.getCall(0).args[0].params, {
        event_collection: 'click',
        timezone: (((new Date().getTimezoneOffset())/60)*60*60)*-1
      });
    });
  });

  describe('mergeResponseWithExplorer', function () {
    it('should keep all explorer attributes', function () {
      var explorer = {
        id: 'TEMP-ABC',
        name: 'SOME NAME',
        active: false,
        saving: false,
        error: null,
        result: null,
        loading: false,
        isValid: true,
        timeframe_type: 'relative',
        query: {
          event_collection: null,
          analysis_type: null,
          target_property: null,
          percentile: null,
          group_by: null,
          interval: null,
          timezone: 'UTC',
          filters: null,
          email: null,
          latest: null,
          filters: [],
          time: {
            relativity: 'this',
            amount: 1,
            sub_timeframe: 'weeks'
          }
        },
        visualization: {
          chart_type: null
        }
      };
      var response = {
        id: 'ACTUAL-ID',
        project_id: '10',
        query: {
          event_collection: 'clicks',
          analysis_type: 'count',
        },
        visualization: {
          chart_type: 'metric'
        }
      };
      assert.deepEqual(ExplorerUtils.mergeResponseWithExplorer(explorer, response), {
        id: 'ACTUAL-ID',
        project_id: '10',
        name: 'SOME NAME',
        active: false,
        saving: false,
        error: null,
        result: null,
        loading: false,
        isValid: true,
        timeframe_type: 'relative',
        query: {
          event_collection: 'clicks',
          analysis_type: 'count',
          target_property: null,
          percentile: null,
          group_by: null,
          interval: null,
          timezone: 'UTC',
          filters: null,
          email: null,
          latest: null,
          filters: [],
          time: {
            relativity: 'this',
            amount: 1,
            sub_timeframe: 'weeks'
          }
        },
        visualization: {
          chart_type: 'metric'
        }
      });
    });
  });

  describe('getTimeframe', function () {
    it('should call the right timeframe builder for absolute timeframes', function () {
      var explorer = {
        timeframe_type: 'absolute'
      };
      var stub = sinon.stub(ExplorerUtils.timeframeBuilders, 'absolute_timeframe');
      ExplorerUtils.getTimeframe(explorer);
      assert.isTrue(stub.calledOnce);
      ExplorerUtils.timeframeBuilders.absolute_timeframe.restore();
    });
    it('should call the right timeframe builder for relative timeframes', function () {
      var explorer = {
        timeframe_type: 'relative'
      };
      var stub = sinon.stub(ExplorerUtils.timeframeBuilders, 'relative_timeframe');
      ExplorerUtils.getTimeframe(explorer);
      assert.isTrue(stub.calledOnce);
      ExplorerUtils.timeframeBuilders.relative_timeframe.restore();
    });
  });

  describe('timeframeBuilders', function () {
    describe('absolute_timeframe', function () {
      it('should properly build a timeframe object', function () {
        var explorer = {
          timeframe_type: 'absolute',
          query: {
            timezone: 'US/Hawaii',
            time: {
              start: new Date(moment().subtract(1, 'days').startOf('day').format()),
              end: new Date(moment().startOf('day').format())
            }
          }
        };
        var timeframe = ExplorerUtils.getTimeframe(explorer);
        var expectedFormat = 'YYYY-MM-DDTHH:mm:ss.SSS';
        var expectedTimezone = '-10:00'
        var expectedStart = moment(new Date(explorer.query.time.start)).format(expectedFormat) + expectedTimezone;
        var expectedEnd = moment(new Date(explorer.query.time.end)).format(expectedFormat) + expectedTimezone;

        assert.deepEqual(timeframe, {
          start: expectedStart,
          end: expectedEnd
        });
      });
    });
    describe('relative_timeframe', function () {
      var explorer = {
        timeframe_type: 'relative',
        query: {
          time: {
            relativity: 'this',
            amount: '1',
            sub_timeframe: 'days'
          }
        }
      };
      var timeframe = ExplorerUtils.getTimeframe(explorer);
      assert.deepEqual(timeframe, 'this_1_days');
    });
  });

  describe('unpackTimeframeParam', function () {
    it('properly unpacks an absolute timeframe', function () {
      var query = {
        timeframe: {
          start: moment(new Date("June 7, 2015 1:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS')+"-10:00",
          end: moment(new Date("June 8, 2015 2:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS')+"-10:00"
        }
      };
      assert.deepEqual(ExplorerUtils.unpackTimeframeParam(query), {
        timeframe_type: 'absolute',
        timezone: 'US/Hawaii',
        time: {
          start: ExplorerUtils.convertDateToUTC(new Date(moment(new Date("June 7, 2015 1:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS'))),
          end: ExplorerUtils.convertDateToUTC(new Date(moment(new Date("June 8, 2015 2:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS')))
        }
      });
    });
    it('properly unpacks a relative timeframe', function () {
      var query = { timeframe: 'this_8_days' };
      var unpacked = ExplorerUtils.unpackTimeframeParam(query);
      assert.deepEqual(unpacked, {
        timeframe_type: 'relative',
        time: {
          relativity: 'this',
          amount: '8',
          sub_timeframe: 'days'
        }
      });
    });
  });
  describe('formatQueryParams', function () {
    it('should call unpackTimeframeParam if there is a timeframe', function () {
      var params = {
        query: {
          timeframe: 'this_1_days'
        }
      };
      var stub = sinon.stub(ExplorerUtils, 'unpackTimeframeParam').returns({
        time: {
          relativity: 'this',
          amount: '1',
          sub_timeframe: 'days'
        },
        timeframe_type: 'relative'
      });
      var formatted = ExplorerUtils.formatQueryParams(params);
      assert.isTrue(stub.calledOnce);
      ExplorerUtils.unpackTimeframeParam.restore();
    });
    it('should call FilterUtils.initList for list filters', function () {
      var stub = sinon.stub(FilterUtils, 'initList');
      var params = {
        query: {
          filters: [
            {
              coercion_type: 'List',
              property_name: 'items',
              operator: 'eq',
              property_value: 'a list of items'
            }
          ]
        }
      };
      ExplorerUtils.formatQueryParams(params);
      assert.isTrue(stub.calledOnce);
      FilterUtils.initList.restore();
    });
    it('should call FilterUtils.getCoercedValue for every filter', function () {
      var stub = sinon.stub(FilterUtils, 'getCoercedValue');
      var params = {
        query: {
          filters: [{}, {}, {}]
        }
      };
      ExplorerUtils.formatQueryParams(params);
      assert.strictEqual(stub.callCount, 3);
      FilterUtils.getCoercedValue.restore();
    });
  });

  describe('getApiQueryUrl', function(){
    beforeEach(function(){
      this.explorer = _.assign({}, TestHelpers.createExplorerModel(), {
        timeframe_type: 'relative',
        query: {
          analysis_type: 'count',
          event_collection: 'clicks',
          filters: [
            {
              property_name: 'author.id',
              operator: 'eq',
              property_value: 'abc123',
              coercion_type: 'String'
            },
            {
              property_name: 'org_project_count',
              operator: 'gte',
              property_value: 10,
              coercion_type: 'Number'
            },
          ],
          time: {
            relativity: 'this',
            amount: '1',
            sub_timeframe: 'days'
          }
        },
        visualization: {
          chart_type: 'metric'
        }
      });
      this.client = TestHelpers.createClient();
    });

    describe('removes unneeded attributes from the URL string', function(){
      it('analysis_type', function(){
        var found = ExplorerUtils.getApiQueryUrl(this.client, this.explorer).match('analysis_type=');
        assert.isNull(found);
      });
      it('chart_type', function(){
        var found = ExplorerUtils.getApiQueryUrl(this.client, this.explorer).match('chart_type=');
        assert.isNull(found);
      });
    });

    describe('it constructs the URL correctly', function(){
      it('has the timeframe attribute', function(){
        var found = ExplorerUtils.getApiQueryUrl(this.client, this.explorer).match('timeframe=this_1_days');
        assert.lengthOf(found, 1);
      });

      describe('filters', function () {
        it('has the expected filters attribute', function () {
          assert.include(ExplorerUtils.getApiQueryUrl(this.client, this.explorer), "filters=%5B%7B%22property_name%22%3A%22author.id%22%2C%22operator%22%3A%22eq%22%2C%22property_value%22%3A%22abc123%22%7D%2C%7B%22property_name%22%3A%22org_project_count%22%2C%22operator%22%3A%22gte%22%2C%22property_value%22%3A10%7D%5D");
        });
        it('does not have the coercion_type property', function () {
          assert.notInclude(ExplorerUtils.getApiQueryUrl(this.client, this.explorer), "coercion_type");
        });
      });
    });
  });

  describe('getSdkExample', function(){

    beforeEach(function () {
      this.explorer = TestHelpers.createExplorerModel();
      this.client = TestHelpers.createClient();
    });

    describe('removes unneeded attributes from the URL string', function(){
      beforeEach(function(){
        this.explorer.query = {
          analysis_type: 'count',
          event_collection: 'clicks',
          timeframe: 'this_1_days',
          visualization: {
            chart_type: 'metric'
          }
        };
      });

      it('analysis_type', function(){
        var found = ExplorerUtils.getSdkExample(this.explorer, this.client).match('analysis_type');
        assert.isNull(found)
      });

      it('chart_type', function(){
        var found = ExplorerUtils.getSdkExample(this.explorer, this.client).match('chart_type');
        assert.isNull(found)
      });

    });

    describe('it constructs the example correctly', function(){

      it('has the timeframe attribute', function(){
        this.explorer = {
          timeframe_type: 'relative',
          query: {
            analysis_type: 'count',
            event_collection: 'clicks',
            timeframe: 'this_1_days',
            time: {
              relativity: 'this',
              amount: '1',
              sub_timeframe: 'days'
            }
          },
          visualization: {
            chart_type: 'metric'
          }
        };
        var found = ExplorerUtils.getSdkExample(this.explorer, this.client).match('timeframe: "this_1_days"');
        assert.lengthOf(found, 1);
      });

    })

  });
});<commit_msg>Fixing tests.<commit_after>var assert = require('chai').assert;
var expect = require('chai').expect;
var sinon = require('sinon');
var moment = require('moment');
var _ = require('lodash');
var Qs = require('qs');
var TestHelpers = require('../../support/TestHelpers');
var ExplorerActions = require('../../../client/js/app/actions/ExplorerActions');
var FilterUtils = require('../../../client/js/app/utils/FilterUtils');
var ValidationUtils = require('../../../client/js/app/utils/ValidationUtils');
var ExplorerValidations = require('../../../client/js/app/validations/ExplorerValidations');
var ExplorerUtils = require('../../../client/js/app/utils/ExplorerUtils');

describe('utils/ExplorerUtils', function() {
  describe('extraction event limit', function () {
    it('should be 100', function () {
      assert.strictEqual(ExplorerUtils.EXRACTION_EVENT_LIMIT, 100);
    });
  });

  describe('queryJSON', function () {
    it('should remove values that are not part of the query params that get sent to Keen', function () {
      var explorer = {
        query: {
          someVal: 'shouldBeRemoved',
          someOtherVal: 'shouldAlsoBeRemoved',
          event_collection: 'sholdRemain',
          analysis_type: 'shouldRemain'
        }
      };
      assert.deepEqual(ExplorerUtils.queryJSON(explorer), {
        event_collection: 'sholdRemain',
        analysis_type: 'shouldRemain'
      });
    });
    it('should remove the timezone if the timeframe_type is absolute', function () {
      var explorer = {
        timeframe_type: 'absolute',
        query: {
          timezone: 'US/Mountain',
          time: {
            start: new Date("Jan 1, 2015 1:00 PM"),
            end: new Date("Jan 2, 2015 1:00 PM")
          }
        }
      };
      assert.notDeepProperty(ExplorerUtils.queryJSON(explorer), 'timezone');
    });
    it('should remove values that are not valid query values', function () {
      var explorer = {
        query: {
          event_collection: undefined,
          analysis_type: 'shouldRemain',
          filters: []
        }
      };
      assert.deepEqual(ExplorerUtils.queryJSON(explorer), {
        analysis_type: 'shouldRemain'
      });
    });
    it('should call FilterUtils.queryJSON for every filter', function () {
      var explorer = { query: { filters: [{}, {}, {}] } };
      var stub = sinon.stub(FilterUtils, 'queryJSON');
      ExplorerUtils.queryJSON(explorer);
      assert.lengthOf(stub.getCalls(), 3);
      FilterUtils.queryJSON.restore();
    });
    it('should remove empty filters', function () {
      var explorer = {
        query: {
          filters: [
            {
              property_name: 'click',
              operator: 'eq',
              property_value: 'button',
              coercion_type: 'String'
            },
            {},
            {}
          ]
        }
      };
      var json = ExplorerUtils.queryJSON(explorer);
      assert.lengthOf(json.filters, 1);
    });
    it('should remove the fitlers key if it is empty after getting their queryJSON verisons', function () {
      var explorer = {
        query: {
          event_collection: 'click',
          analysis_type: 'count',
          filters: [
            {  property_name: 'click' },
            {},
            {}
          ]
        }
      };
      var json = ExplorerUtils.queryJSON(explorer);
      assert.isUndefined(json.filters);
    });
    it('should set the timeframe if there is one', function () {
      var explorer = {
        timeframe_type: 'relative',
        query: {
          event_collection: 'click',
          analysis_type: 'count',
          time: {
            relativity: 'this',
            amount: '1',
            sub_timeframe: 'days'
          }
        }
      };
      var json = ExplorerUtils.queryJSON(explorer);
      assert.deepEqual(json, {
        event_collection: 'click',
        analysis_type: 'count',
        timeframe: 'this_1_days'
      });
    });
  });

  describe('runQuery', function () {
    it('should create a Keen.Query', function () {
      var client = { run: sinon.spy() };
      var query = {
        analysis_type: 'count',
        event_collection: 'click'
      };
      ExplorerUtils.runQuery({
        client: client,
        query: query,
        success: function(){},
        error: function(){},
        complete: function(){}
      });
      assert.strictEqual(client.run.getCall(0).args[0].analysis, 'count');
      assert.deepEqual(client.run.getCall(0).args[0].params, {
        event_collection: 'click',
        timezone: (((new Date().getTimezoneOffset())/60)*60*60)*-1
      });
    });
  });

  describe('mergeResponseWithExplorer', function () {
    it('should keep all explorer attributes', function () {
      var explorer = {
        id: 'TEMP-ABC',
        name: 'SOME NAME',
        active: false,
        saving: false,
        error: null,
        result: null,
        loading: false,
        isValid: true,
        timeframe_type: 'relative',
        query: {
          event_collection: null,
          analysis_type: null,
          target_property: null,
          percentile: null,
          group_by: null,
          interval: null,
          timezone: 'UTC',
          filters: null,
          email: null,
          latest: null,
          filters: [],
          time: {
            relativity: 'this',
            amount: 1,
            sub_timeframe: 'weeks'
          }
        },
        visualization: {
          chart_type: null
        }
      };
      var response = {
        id: 'ACTUAL-ID',
        project_id: '10',
        query: {
          event_collection: 'clicks',
          analysis_type: 'count',
        },
        visualization: {
          chart_type: 'metric'
        }
      };
      var expectedExplorer = {
        id: 'ACTUAL-ID',
        project_id: '10',
        name: 'SOME NAME',
        active: false,
        saving: false,
        error: null,
        result: null,
        loading: false,
        isValid: true,
        timeframe_type: 'relative',
        query: {
          event_collection: 'clicks',
          analysis_type: 'count',
          target_property: null,
          percentile: null,
          group_by: null,
          interval: null,
          timezone: 'UTC',
          filters: null,
          email: null,
          latest: null,
          filters: [],
          time: {
            relativity: 'this',
            amount: 1,
            sub_timeframe: 'weeks'
          }
        },
        visualization: {
          chart_type: 'metric'
        }
      };
      expectedExplorer.originalModel = _.cloneDeep(expectedExplorer);
      assert.deepEqual(ExplorerUtils.mergeResponseWithExplorer(explorer, response), expectedExplorer);
    });
  });

  describe('getTimeframe', function () {
    it('should call the right timeframe builder for absolute timeframes', function () {
      var explorer = {
        timeframe_type: 'absolute'
      };
      var stub = sinon.stub(ExplorerUtils.timeframeBuilders, 'absolute_timeframe');
      ExplorerUtils.getTimeframe(explorer);
      assert.isTrue(stub.calledOnce);
      ExplorerUtils.timeframeBuilders.absolute_timeframe.restore();
    });
    it('should call the right timeframe builder for relative timeframes', function () {
      var explorer = {
        timeframe_type: 'relative'
      };
      var stub = sinon.stub(ExplorerUtils.timeframeBuilders, 'relative_timeframe');
      ExplorerUtils.getTimeframe(explorer);
      assert.isTrue(stub.calledOnce);
      ExplorerUtils.timeframeBuilders.relative_timeframe.restore();
    });
  });

  describe('timeframeBuilders', function () {
    describe('absolute_timeframe', function () {
      it('should properly build a timeframe object', function () {
        var explorer = {
          timeframe_type: 'absolute',
          query: {
            timezone: 'US/Hawaii',
            time: {
              start: new Date(moment().subtract(1, 'days').startOf('day').format()),
              end: new Date(moment().startOf('day').format())
            }
          }
        };
        var timeframe = ExplorerUtils.getTimeframe(explorer);
        var expectedFormat = 'YYYY-MM-DDTHH:mm:ss.SSS';
        var expectedTimezone = '-10:00'
        var expectedStart = moment(new Date(explorer.query.time.start)).format(expectedFormat) + expectedTimezone;
        var expectedEnd = moment(new Date(explorer.query.time.end)).format(expectedFormat) + expectedTimezone;

        assert.deepEqual(timeframe, {
          start: expectedStart,
          end: expectedEnd
        });
      });
    });
    describe('relative_timeframe', function () {
      var explorer = {
        timeframe_type: 'relative',
        query: {
          time: {
            relativity: 'this',
            amount: '1',
            sub_timeframe: 'days'
          }
        }
      };
      var timeframe = ExplorerUtils.getTimeframe(explorer);
      assert.deepEqual(timeframe, 'this_1_days');
    });
  });

  describe('unpackTimeframeParam', function () {
    it('properly unpacks an absolute timeframe', function () {
      var query = {
        timeframe: {
          start: moment(new Date("June 7, 2015 1:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS')+"-10:00",
          end: moment(new Date("June 8, 2015 2:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS')+"-10:00"
        }
      };
      assert.deepEqual(ExplorerUtils.unpackTimeframeParam(query), {
        timeframe_type: 'absolute',
        timezone: 'US/Hawaii',
        time: {
          start: ExplorerUtils.convertDateToUTC(new Date(moment(new Date("June 7, 2015 1:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS'))),
          end: ExplorerUtils.convertDateToUTC(new Date(moment(new Date("June 8, 2015 2:00 PM")).format('YYYY-MM-DDTHH:mm:ss.SSS')))
        }
      });
    });
    it('properly unpacks a relative timeframe', function () {
      var query = { timeframe: 'this_8_days' };
      var unpacked = ExplorerUtils.unpackTimeframeParam(query);
      assert.deepEqual(unpacked, {
        timeframe_type: 'relative',
        time: {
          relativity: 'this',
          amount: '8',
          sub_timeframe: 'days'
        }
      });
    });
  });
  describe('formatQueryParams', function () {
    it('should call unpackTimeframeParam if there is a timeframe', function () {
      var params = {
        query: {
          timeframe: 'this_1_days'
        }
      };
      var stub = sinon.stub(ExplorerUtils, 'unpackTimeframeParam').returns({
        time: {
          relativity: 'this',
          amount: '1',
          sub_timeframe: 'days'
        },
        timeframe_type: 'relative'
      });
      var formatted = ExplorerUtils.formatQueryParams(params);
      assert.isTrue(stub.calledOnce);
      ExplorerUtils.unpackTimeframeParam.restore();
    });
    it('should call FilterUtils.initList for list filters', function () {
      var stub = sinon.stub(FilterUtils, 'initList');
      var params = {
        query: {
          filters: [
            {
              coercion_type: 'List',
              property_name: 'items',
              operator: 'eq',
              property_value: 'a list of items'
            }
          ]
        }
      };
      ExplorerUtils.formatQueryParams(params);
      assert.isTrue(stub.calledOnce);
      FilterUtils.initList.restore();
    });
    it('should call FilterUtils.getCoercedValue for every filter', function () {
      var stub = sinon.stub(FilterUtils, 'getCoercedValue');
      var params = {
        query: {
          filters: [{}, {}, {}]
        }
      };
      ExplorerUtils.formatQueryParams(params);
      assert.strictEqual(stub.callCount, 3);
      FilterUtils.getCoercedValue.restore();
    });
  });

  describe('getApiQueryUrl', function(){
    beforeEach(function(){
      this.explorer = _.assign({}, TestHelpers.createExplorerModel(), {
        timeframe_type: 'relative',
        query: {
          analysis_type: 'count',
          event_collection: 'clicks',
          filters: [
            {
              property_name: 'author.id',
              operator: 'eq',
              property_value: 'abc123',
              coercion_type: 'String'
            },
            {
              property_name: 'org_project_count',
              operator: 'gte',
              property_value: 10,
              coercion_type: 'Number'
            },
          ],
          time: {
            relativity: 'this',
            amount: '1',
            sub_timeframe: 'days'
          }
        },
        visualization: {
          chart_type: 'metric'
        }
      });
      this.client = TestHelpers.createClient();
    });

    describe('removes unneeded attributes from the URL string', function(){
      it('analysis_type', function(){
        var found = ExplorerUtils.getApiQueryUrl(this.client, this.explorer).match('analysis_type=');
        assert.isNull(found);
      });
      it('chart_type', function(){
        var found = ExplorerUtils.getApiQueryUrl(this.client, this.explorer).match('chart_type=');
        assert.isNull(found);
      });
    });

    describe('it constructs the URL correctly', function(){
      it('has the timeframe attribute', function(){
        var found = ExplorerUtils.getApiQueryUrl(this.client, this.explorer).match('timeframe=this_1_days');
        assert.lengthOf(found, 1);
      });

      describe('filters', function () {
        it('has the expected filters attribute', function () {
          assert.include(ExplorerUtils.getApiQueryUrl(this.client, this.explorer), "filters=%5B%7B%22property_name%22%3A%22author.id%22%2C%22operator%22%3A%22eq%22%2C%22property_value%22%3A%22abc123%22%7D%2C%7B%22property_name%22%3A%22org_project_count%22%2C%22operator%22%3A%22gte%22%2C%22property_value%22%3A10%7D%5D");
        });
        it('does not have the coercion_type property', function () {
          assert.notInclude(ExplorerUtils.getApiQueryUrl(this.client, this.explorer), "coercion_type");
        });
      });
    });
  });

  describe('getSdkExample', function(){

    beforeEach(function () {
      this.explorer = TestHelpers.createExplorerModel();
      this.client = TestHelpers.createClient();
    });

    describe('removes unneeded attributes from the URL string', function(){
      beforeEach(function(){
        this.explorer.query = {
          analysis_type: 'count',
          event_collection: 'clicks',
          timeframe: 'this_1_days',
          visualization: {
            chart_type: 'metric'
          }
        };
      });

      it('analysis_type', function(){
        var found = ExplorerUtils.getSdkExample(this.explorer, this.client).match('analysis_type');
        assert.isNull(found)
      });

      it('chart_type', function(){
        var found = ExplorerUtils.getSdkExample(this.explorer, this.client).match('chart_type');
        assert.isNull(found)
      });

    });

    describe('it constructs the example correctly', function(){

      it('has the timeframe attribute', function(){
        this.explorer = {
          timeframe_type: 'relative',
          query: {
            analysis_type: 'count',
            event_collection: 'clicks',
            timeframe: 'this_1_days',
            time: {
              relativity: 'this',
              amount: '1',
              sub_timeframe: 'days'
            }
          },
          visualization: {
            chart_type: 'metric'
          }
        };
        var found = ExplorerUtils.getSdkExample(this.explorer, this.client).match('timeframe: "this_1_days"');
        assert.lengthOf(found, 1);
      });

    })

  });
});<|endoftext|>


<commit_before>import React, { Component } from "react"
import PropTypes from "prop-types"
import ReactTooltip from "react-tooltip"

class MetaPayload extends Component {
  render() {
    const metaBag = this.props.metaBag || {}
    const dtWithClass = this.props.dtWithClass
    const sortKeys = this.props.sortKeys
    const asTooltip = this.props.asTooltip
    const identifier = this.props.identifier

    let keys = Object.keys(metaBag || {})
    if (keys.length === 0) {
      return
- No data found -

    }

    const meta = []
    let metaTag = null

    if (sortKeys) {
      keys = keys.sort()
    }

    keys.forEach(key => {
      meta.push(
        <dt className={dtWithClass} key={`${key}dt`}>
          {key}

      )

      let v = metaBag[key]
      switch (typeof v) {
        case "boolean":
          v = v ? "true" : "false"
      }

      meta.push(
        <dd key={`${key}dd`}>
          {v}

      )
    })

    if (meta.length > 0) {
      metaTag = (

          {meta}

      )
    }

    if (asTooltip) {
      return (

          <ReactTooltip id={`tooltip-${identifier}`}>
            {metaTag}
          </ReactTooltip>
          <span data-tip data-for={`tooltip-${identifier}`} className="dotted">
            {keys.length} keys

      )
    }

    return metaTag
  }
}

MetaPayload.defaultProps = {
  metaBag: {},
  dtWithClass: "default",
  sortKeys: true,
  asTooltip: false
}

MetaPayload.propTypes = {
  metaBag: PropTypes.object,
  dtWithClass: PropTypes.string.isRequired,
  identifier: PropTypes.string.isRequired,
  sortKeys: PropTypes.bool.isRequired,
  asTooltip: PropTypes.bool.isRequired
}

export default MetaPayload
<commit_msg>prevent overflow of meta payloads<commit_after>import React, { Component } from "react"
import PropTypes from "prop-types"
import ReactTooltip from "react-tooltip"

class MetaPayload extends Component {
  render() {
    const metaBag = this.props.metaBag || {}
    const dtWithClass = this.props.dtWithClass
    const sortKeys = this.props.sortKeys
    const asTooltip = this.props.asTooltip
    const identifier = this.props.identifier

    let keys = Object.keys(metaBag || {})
    if (keys.length === 0) {
      return
- No data found -

    }

    const meta = []
    let metaTag = null

    if (sortKeys) {
      keys = keys.sort()
    }

    keys.forEach(key => {
      meta.push(
        <dt className={dtWithClass} key={`${key}dt`}>
          {key}

      )

      let v = metaBag[key]
      switch (typeof v) {
        case "boolean":
          v = v ? "true" : "false"
      }

      meta.push(
        <dd key={`${key}dd`} style={{ overflow: "scroll" }}>
          {v}

      )
    })

    if (meta.length > 0) {
      metaTag = (

          {meta}

      )
    }

    if (asTooltip) {
      return (

          <ReactTooltip id={`tooltip-${identifier}`}>
            {metaTag}
          </ReactTooltip>
          <span data-tip data-for={`tooltip-${identifier}`} className="dotted">
            {keys.length} keys

      )
    }

    return metaTag
  }
}

MetaPayload.defaultProps = {
  metaBag: {},
  dtWithClass: "default",
  sortKeys: true,
  asTooltip: false
}

MetaPayload.propTypes = {
  metaBag: PropTypes.object,
  dtWithClass: PropTypes.string.isRequired,
  identifier: PropTypes.string.isRequired,
  sortKeys: PropTypes.bool.isRequired,
  asTooltip: PropTypes.bool.isRequired
}

export default MetaPayload
<|endoftext|>


<commit_before>'use strict';

var log = require('../modules/log');

exports.command = function(errorText, callback) {
  var client = this;
  errorText = errorText || 'This form has errors.\nPlease see below for the errors you need to correct.';

  this.perform(function() {
    log.command('Checking form validation…');

    client
      .submitForm('form', function() {
        console.log('     ⟡ Form submitted');
      })
      .waitForElementPresent('.alert-error', 3000, function() {
        console.log('    - Form has errors summary');
      })
      .assert.containsText('.alert-error', errorText)
    ;
  });

  if (typeof callback === 'function') {
    callback.call(client);
  }

  return client;
};
<commit_msg>TEST: Fix Nightwatch test<commit_after>'use strict';

var log = require('../modules/log');
var util = require('util');

exports.command = function(errorText, callback) {
  var client = this;
  errorText = errorText || 'This form has errors';

  this.perform(function() {
    log.command('Checking form validation…');

    client
      .submitForm('form', function() {
        console.log('     ⟡ Form submitted');
      })
      .waitForElementPresent('.alert-error', 3000, function() {
        console.log('    - Form has errors summary');
      })
      .assert.containsText('.alert-error', errorText)
    ;
  });

  if (typeof callback === 'function') {
    callback.call(client);
  }

  return client;
};
<|endoftext|>


<commit_before>// Modules
var log = require('./log'),
    fs = require('fs'),
    path = require('path'),
    // Shortcuts
    toString = Object.prototype.toString,
    exists = fs.exists || path.exists,
    normalize = path.normalize,
    join = path.join;

/**
 * Given a path, check if the dir exists and create if it doesn't
 * This function will recursevily create folders.
 *
 * @function
 * @param {String} dirPath '/Users/Couto/destinationFolder'
 * @param {String} mode '0644' fallsback to '0777'
 * @param {Function} [callback]
 */
exports.mkdir = function (dirPath, mode, callback) {
    var dest = normalize(dirPath).split('/'),
        callback = (toString.call(mode) === '[object Function]') ? mode : callback;
        mode = (toString.call(mode) === '[object String]') ? mode : '0777';

    log.info('creating folder at: %s', dest.join('/'));

    (function walk(path) {
        exists(path, function (exist) {
            if (!exist) {
                fs.mkdir(path, mode, function (err) {
                    if (!err) {
                        log.success('created folder at: %s', path);
                        if (dest.length) {
                            walk(normalize(path + '/' + dest.shift()));
                        } else if (!dest.length && callback) {
                            return callback(err, path);
                        }
                    } else {
                        return log.error('failed to create folder: %s because: %s', path, err);
                    }
                });

            } else if (exists && dest.length) {
                walk(normalize(path + '/' + dest.shift()));
            } else {
                if (callback) {
                    callback(undefined, path);
                }
            }
        });

    }(dest.shift()));
};

/**
 * Given a path, it will call a callback function for each folder and file
 * that it finds. That function will receive the file/folder path and the
 * respective Fs.Stats object
 *
 * @function
 * @public
 * @param    {String}   dirPath  folder to read
 * @param    {Function} callback function that will be called at each file and folder
 *
 *
 * @TODO find a way to call a callback when the reading process ends
 */
exports.readDirRecursive = function (dirPath, callback) {
    dirPath = normalize(dirPath);

    fs.readdir(dirPath, function (err, files) {
        if (err) { return log.error('could not read: %s, because: %s', dirPath, err); }

        (function walk(file) {
            if (file) {
                log.info('reading file: %s', join(dirPath, file));
                fs.stat(join(dirPath, file), function (err, stats) {

                    if (callback) { callback(join(dirPath, file), stats); }
                    if (stats.isDirectory()) {
                        exports.readDirRecursive(join(dirPath, file), callback);
                    }

                    if (files.length) { walk(files.shift()); }

                });
            }
        }(files.shift()));
    });
};

/**
 * Given a folder, it will read all it's files and folders and replicate
 * its structure on the given output folder
 * The callback is called at each file/folder created
 * Note that files contents are not copied.
 *
 * @function
 * @public
 * @param    {String}   dirPath    Folder that will be copied
 * @param    {String}   outputPath Folder that will receive the structure
 * @param    {Function} callback   function that will be called at each file and folder
 *
 * @TODO find a way to call a callback when the mirroring process ends
 */
exports.mirror = function (dirPath, outputPath, callback) {
    dirPath = normalize(dirPath);
    outputPath = normalize(outputPath);

    exports.mkdir(outputPath, function (err, path) {
        exports.readDirRecursive(dirPath, function (file, stat) {

            if (file && stat.isDirectory()) {
                exports.mkdir(file.replace(dirPath, outputPath));
            } else if (file && stat.isFile()) {
                exports.touch(file.replace(dirPath, outputPath));
            }

            if (callback) { callback(file, file.replace(dirPath, outputPath)); }
        });
    });

};

/**
 * Remove a file or a directory
 *
 * @function
 * @param {String} dirPath '/Users/Couto/example.js'
 * @param {Function} [callback]
 */
exports.rm = function (dirPath, callback) {
    var rmCallback = function (err) {
        if (err) { return log.error('could not remove: %s, because: %s', dirPath, err); }
        log.success('removed: %s', dirPath);
        if (callback) { callback(dirPath); }
    };

    fs.stat(dirPath, function (err, stat) {
        if (err) { return log.error('could not remove: %s, because: %s', dirPath, err); }

        if (stat.isDirectory()) { fs.rmdir(dirPath, rmCallback); }
        else { fs.unlink(dirPath, rmCallback); }
    });
};

/**
 * Create file if doesn't exist
 * Update file's timestamp if exists
 *
 * @function
 * @param {String} filePath '/Users/Couto/.vimrc'
 * @param {Function} [callback]
 */
exports.touch = function (filePath, callback) {
    var touchCallback = function (err) {
        if (err) { return log.error('failed to touch file: $s because: %s', filePath, err); }
        log.success('touched file: %s', filePath);
        if (callback) { callback(filePath); }
    };

    exists(filePath, function (exist) {
        if (exist) {
            fs.utimes(filePath, new Date(), new Date(), touchCallback);
        } else { fs.writeFile(filePath, '', 'utf-8', touchCallback); }
    });
};

/**
 * Insert data into file
 * if file doesn't exist, uses touch() to create the file and then inserts
 * the data
 *
 * @function
 * @param {String} filePath
 * @param {String} data
 * @param {Function} [callback]
 */
exports.tee = function (filePath, data, callback) {
    exists(filePath, function (exist) {
        if (exist) {
            fs.writeFile(filePath, data, 'utf-8', function (err) {
                if (err) { return log.error('failed to write to file: %s because: %s', filePath, err); }
                log.success('wrote file %s', filePath);
                if (callback) { callback(filePath); }
            });
        } else {
            exports.touch(filePath, exports.tee.bind(null, filePath, data, callback));
        }
    });
};
<commit_msg>[fix] fs.exists was moved to fs.exists<commit_after>// Modules
var log = require('./log'),
    fs = require('fs'),
    path = require('path'),
    // Shortcuts
    toString = Object.prototype.toString,
    exists = fs.exists || fs.exists,
    normalize = path.normalize,
    join = path.join;

/**
 * Given a path, check if the dir exists and create if it doesn't
 * This function will recursevily create folders.
 *
 * @function
 * @param {String} dirPath '/Users/Couto/destinationFolder'
 * @param {String} mode '0644' fallsback to '0777'
 * @param {Function} [callback]
 */
exports.mkdir = function (dirPath, mode, callback) {
    var dest = normalize(dirPath).split('/'),
        callback = (toString.call(mode) === '[object Function]') ? mode : callback;
        mode = (toString.call(mode) === '[object String]') ? mode : '0777';

    log.info('creating folder at: %s', dest.join('/'));

    (function walk(path) {
        exists(path, function (exist) {
            if (!exist) {
                fs.mkdir(path, mode, function (err) {
                    if (!err) {
                        log.success('created folder at: %s', path);
                        if (dest.length) {
                            walk(normalize(path + '/' + dest.shift()));
                        } else if (!dest.length && callback) {
                            return callback(err, path);
                        }
                    } else {
                        return log.error('failed to create folder: %s because: %s', path, err);
                    }
                });

            } else if (exists && dest.length) {
                walk(normalize(path + '/' + dest.shift()));
            } else {
                if (callback) {
                    callback(undefined, path);
                }
            }
        });

    }(dest.shift()));
};

/**
 * Given a path, it will call a callback function for each folder and file
 * that it finds. That function will receive the file/folder path and the
 * respective Fs.Stats object
 *
 * @function
 * @public
 * @param    {String}   dirPath  folder to read
 * @param    {Function} callback function that will be called at each file and folder
 *
 *
 * @TODO find a way to call a callback when the reading process ends
 */
exports.readDirRecursive = function (dirPath, callback) {
    dirPath = normalize(dirPath);

    fs.readdir(dirPath, function (err, files) {
        if (err) { return log.error('could not read: %s, because: %s', dirPath, err); }

        (function walk(file) {
            if (file) {
                log.info('reading file: %s', join(dirPath, file));
                fs.stat(join(dirPath, file), function (err, stats) {

                    if (callback) { callback(join(dirPath, file), stats); }
                    if (stats.isDirectory()) {
                        exports.readDirRecursive(join(dirPath, file), callback);
                    }

                    if (files.length) { walk(files.shift()); }

                });
            }
        }(files.shift()));
    });
};

/**
 * Given a folder, it will read all it's files and folders and replicate
 * its structure on the given output folder
 * The callback is called at each file/folder created
 * Note that files contents are not copied.
 *
 * @function
 * @public
 * @param    {String}   dirPath    Folder that will be copied
 * @param    {String}   outputPath Folder that will receive the structure
 * @param    {Function} callback   function that will be called at each file and folder
 *
 * @TODO find a way to call a callback when the mirroring process ends
 */
exports.mirror = function (dirPath, outputPath, callback) {
    dirPath = normalize(dirPath);
    outputPath = normalize(outputPath);

    exports.mkdir(outputPath, function (err, path) {
        exports.readDirRecursive(dirPath, function (file, stat) {

            if (file && stat.isDirectory()) {
                exports.mkdir(file.replace(dirPath, outputPath));
            } else if (file && stat.isFile()) {
                exports.touch(file.replace(dirPath, outputPath));
            }

            if (callback) { callback(file, file.replace(dirPath, outputPath)); }
        });
    });

};

/**
 * Remove a file or a directory
 *
 * @function
 * @param {String} dirPath '/Users/Couto/example.js'
 * @param {Function} [callback]
 */
exports.rm = function (dirPath, callback) {
    var rmCallback = function (err) {
        if (err) { return log.error('could not remove: %s, because: %s', dirPath, err); }
        log.success('removed: %s', dirPath);
        if (callback) { callback(dirPath); }
    };

    fs.stat(dirPath, function (err, stat) {
        if (err) { return log.error('could not remove: %s, because: %s', dirPath, err); }

        if (stat.isDirectory()) { fs.rmdir(dirPath, rmCallback); }
        else { fs.unlink(dirPath, rmCallback); }
    });
};

/**
 * Create file if doesn't exist
 * Update file's timestamp if exists
 *
 * @function
 * @param {String} filePath '/Users/Couto/.vimrc'
 * @param {Function} [callback]
 */
exports.touch = function (filePath, callback) {
    var touchCallback = function (err) {
        if (err) { return log.error('failed to touch file: $s because: %s', filePath, err); }
        log.success('touched file: %s', filePath);
        if (callback) { callback(filePath); }
    };

    exists(filePath, function (exist) {
        if (exist) {
            fs.utimes(filePath, new Date(), new Date(), touchCallback);
        } else { fs.writeFile(filePath, '', 'utf-8', touchCallback); }
    });
};

/**
 * Insert data into file
 * if file doesn't exist, uses touch() to create the file and then inserts
 * the data
 *
 * @function
 * @param {String} filePath
 * @param {String} data
 * @param {Function} [callback]
 */
exports.tee = function (filePath, data, callback) {
    exists(filePath, function (exist) {
        if (exist) {
            fs.writeFile(filePath, data, 'utf-8', function (err) {
                if (err) { return log.error('failed to write to file: %s because: %s', filePath, err); }
                log.success('wrote file %s', filePath);
                if (callback) { callback(filePath); }
            });
        } else {
            exports.touch(filePath, exports.tee.bind(null, filePath, data, callback));
        }
    });
};
<|endoftext|>