<commit_before>var mongoose = require('mongoose')
var schema = require('../server/schema')
var utils = require('../shared/utils')
var _ = require('lodash')
var xlsx = require('xlsx')
var xls = require('xlsjs')
var async = require('async')
var enums = require('../shared/enums')

// NOTE: field order matters
var providerFieldMap = [
  'name',
  'yTunnus',
  'address.street',
  'address.zip',
  'address.city',
  'language',
  'contactName',
  'emailAddresses',
  'phoneNumber',
  'address.country'
]

// NOTE: field order matters
var billingFieldMap = [
  'billing.address.street',
  'billing.address.zip',
  'billing.address.city',
  'billing.invoiceText'
]

// NOTE: field order matters
var eInvoiceFieldMap = [
  'eInvoice.address',
  'eInvoice.operator'
]

// NOTE: field order matters
var locationFieldMap = [
  'name',
  'address.street',
  'address.zip',
  'address.city',
  'isPayer',
  'contactName',
  'emailAddresses',
  'phoneNumber',
  'Recordings_provide',
  'Public_presentation',
  'National_TV',
  'Regional_TV',
  'Transmitted_abroad_program',
  'Subscription_of_program',
  'url',
  'adultContent'
]

var fieldNames = {
  'name': 'Nimi',
  'yTunnus': 'Y-tunnus',
  'address.street': 'lähiosoite',
  'address.zip': 'postinro',
  'address.city': 'postitoimipaikka',
  'language': 'asiointikieli',
  'contactName': 'yhteyshenkilö',
  'emailAddresses': 'sähköposti',
  'phoneNumber': 'puhelinnumero'
}

// These need to match exactly with the labels in the provider Excel file
var i18n = {
  sv: {
    'Tarjoaja': 'Leverantör',
    'Lasku eri osoitteeseen kuin Tarjoajan osoite': 'Faktura till annan adress än Leverantörens',
    'TAI verkkolasku': 'ELLER nätfaktura',
    'Tarjoamispaikkojen tiedot ja tarjoamistavat': 'Information om ställen och sätt för tillhandahållning'
  }
}

function sv(txt) {
  return i18n.sv[txt] || txt
}

exports.import = function(file, callback) {
  var parser = false

  if (file.originalname.search(/.xls$/) > 1) parser = xls
  else if (file.originalname.search(/.xlsx$/) > 1) parser = xlsx
  else return callback({ message: '.xlsx or .xls required' })

  var allSheets = parser.readFile(file.path)
  var sheetFi = allSheets.Sheets['Tarjoajaksi ilmoittautuminen']
  var sheetSv = allSheets.Sheets['Leverantörsanmälan'] || allSheets.Sheets['Leverantörsanmälan']
  var useFi = isEmptySheet(sheetSv, i18n.sv['Tarjoaja'])

  getProviderAndLocationsFromSpreadSheet(useFi ? sheetFi : sheetSv, useFi ? identity : sv, function(err, providerAndLocations) {
    if (err) return callback(err)
    var provider = createProvider(providerAndLocations.provider, providerAndLocations.billing)
    provider.locations = createLocations(providerAndLocations.locations)
    return callback(null, provider)
  })

  function createProvider(providerData, billingData) {
    var provider = createObjectAndSetValuesWithMap(providerData, providerFieldMap)
    provider.deleted = false
    provider.active = false
    provider.creationDate = new Date()
    provider.language = (provider.language && provider.language.toLowerCase() == 'svenska') ? 'SV' : 'FI'
    provider.address.country = enums.getCountryCode(provider.address.country) || 'FI'

    var billing = createObjectAndSetValuesWithMap(billingData, billingFieldMap)

    provider = utils.merge(provider, billing)

    if (provider.billing && provider.billing.address) {
      var address = provider.billing.address
      provider.billingPreference = 'address'
    }

    if (provider.eInvoice) {
      provider.billingPreference = 'eInvoice'
    }

    return provider
  }

  function createLocations(locationsData) {
    return _.map(locationsData, function(location) {
      var location = createObjectAndSetValuesWithMap(location, locationFieldMap, { providingType: _.keys(enums.providingType) })

      return utils.merge(location, {
        deleted: false,
        active: true,
        isPayer: stringXToBoolean(location.isPayer),
        adultContent: stringXToBoolean(location.adultContent),
      })
    })
  }
  function stringXToBoolean(x) { return _.isString(x) ? x.toLowerCase() === 'x' : false }
}

function getProviderAndLocationsFromSpreadSheet(providerSheet, text, callback) {
  var requiredProviderFields = {
    name: 'Tarjoajan tiedot:',
    values: ['name', 'yTunnus', 'contactName', 'address.street', 'address.zip', 'address.city', 'address.country', 'phoneNumber', 'language']
  }

  var requiredLocationFields = {
    name: 'Tarjoamispaikan tiedot:',
    values: ['name', 'contactName', 'address.street', 'address.zip', 'address.city', 'phoneNumber']
  }

  var noRequiredFields = { name: '', values: [] }

  var errors = []

  var providerData = parseFieldRowAndValueRowAfterColumn(text('Tarjoaja'), providerFieldMap, requiredProviderFields)
  var billingData = parseFieldRowAndValueRowAfterColumn(text('Lasku eri osoitteeseen kuin Tarjoajan osoite'), billingFieldMap, noRequiredFields)
  var eInvoiceData = parseFieldRowAndValueRowAfterColumn(text('TAI verkkolasku'), eInvoiceFieldMap, noRequiredFields)
  var locationsData = parseFieldRowAndValueRowsAfterColumn(text('Tarjoamispaikkojen tiedot ja tarjoamistavat'), locationFieldMap, requiredLocationFields)

  if (locationsData.length === 0) errors.push('Tarjoamispaikkojen tiedot puuttuvat')

  if (errors.length > 0) {
    return callback({ messages: errors })
  } else {
    return callback(null, {
      provider: providerData,
      billing: utils.merge(billingData, eInvoiceData),
      locations: locationsData
    })
  }

  function parseFieldRowAndValueRowAfterColumn(column, fieldMap, requiredFields) {
    var rowNumber = findColumnRowByValue(providerSheet, column)
    var row = toObject(providerSheet, rowNumber + 2, fieldMap)
    var errorMessages = validate(row, requiredFields, rowNumber + 2, fieldMap)
    errorMessages.forEach(function(msg) {
      errors.push(msg)
    })

    return row
  }

  function parseFieldRowAndValueRowsAfterColumn(column, fieldMap, requiredFields) {
    var rowNumber = findColumnRowByValue(providerSheet, column)

    var rows = values([], rowNumber + 2)

    var errorMessages = _.reduce(rows, function(acc, val) {
      var index = acc[0], errors = acc[1]
      var fieldErrors = validate(val, requiredFields, index, fieldMap)
      return [index + 1, errors.concat(fieldErrors)
        .concat(validateProvidingType(val, index))
        .concat(validateRequiredEmail(val, index))]
    }, [rowNumber + 2, []])[1]

    errorMessages.forEach(function(msg) {
      errors.push(msg)
    })

    return rows

    function values(xs, row) {
      var currentValues = toObject(providerSheet, row, fieldMap)
      if (_.every(currentValues, function(x) { return x === null})) {
        return xs
      } else {
        return values(xs.concat([currentValues]), row + 1)
      }
    }

    function validateProvidingType(val, index) {
      var providingTypeFields = _.keys(enums.providingType)
      var present = _.keys(val)
      var hasAtLeastOneProvidingType = _(providingTypeFields).map(function(name) {
        return _.indexOf(present, name) > 0
      }).some()

      if (!hasAtLeastOneProvidingType) {
        return ['Tarjoamispaikan tiedot rivillä ' + index + ': tarjoamispaikalla täytyy olla ainakin yksi tajoamistapa.']
      } else {
        return []
      }
    }

    function validateRequiredEmail(val, row) {
      var msg = 'Tarjoamispaikan tiedot rivillä ' + row + ': sähköpostiosoite on pakollinen jos lasku lähetetään tarjoamispaikalle.'
      if (val.isPayer && !val.emailAddresses) return [msg]
      else return []
    }
  }

  function validate(values, requiredFields, index, fieldMap) {
    var present = _.keys(values)
    var missing = _.reduce(requiredFields.values, function(acc, r) {
      if (_.indexOf(present, r) === -1) return acc.concat(r)
      else return acc
    }, [])

    return _.map(missing, function (field) {
      var errorString = 'Rivillä <%- row %>. <%- name %> pakollinen kenttä "<%- field %>" puuttuu'
      return _.template(errorString)({
        name: requiredFields.name,
        field: fieldNames[field],
        row: index
      })
    })
  }

}

function findColumnRowByValue(from, value) {
  var columnRowNumber = undefined

  _.find(from, function(field, key) {
    if (field.v && (field.v.trim().toLowerCase() == value.toLowerCase())) {
      columnRowNumber = parseRowNumber(key)
      return true
    }
  })

  return columnRowNumber

  function parseRowNumber(key) { return parseInt(key.substring(key.search(/\d/))) }
}

function toObject(from, row, fields) {
  var fst = function(x) { return x[0] }
  var snd = function(x) { return x[1] }

  var ob = _.reduce(from, function(result, field, key) {
    if (key.match(new RegExp('.' + row))) {
      return utils.merge(result, utils.keyValue(key.substr(0, 1), field.v))
    }
    else return result
  }, emptyRow(fields.length))

  var values = _(ob).toPairs().sortBy(fst).map(snd).value()

  return _(_.toPairs(_.zipObject(fields, values))).filter(function(x) {
    return x[1] !== null
  }).object().value()

  function parseColumnKey(key) { return key.substring(0, key.search(/\d/)) }
}

function emptyRow(count) {
  return _('BCDEFGHIJKLMNOPQRSTU'.split('')).take(count).reduce(function(ob, c) {
    return utils.merge(ob, utils.keyValue(c, null))
  }, {})
}

function isEmptySheet(s, heading) {
  var rowNumber = findColumnRowByValue(s, heading)
  var row = toObject(s, rowNumber + 2, providerFieldMap)
  return _.isEmpty(row)
}

function identity(x) { return x }

function createObjectAndSetValuesWithMap(object, map, enumProperties) {
  var enumProps = _.reduce(_.toPairs(enumProperties), function(ob, x) {
    var propName = x[0], fields = x[1]
    return utils.merge(ob, utils.keyValue(propName, toArray(fields)))

    function toArray(fields) {
      return _.reduce(fields, function(acc, field) {
        if (object[field]) return acc.concat(field)
        else return acc
      }, [])
    }
  }, {})

  var props = _.reduce(_.toPairs(utils.flattenObject(object)), function(ob, pair) {
    var key = pair[0], val = pair[1], prop = {}
    utils.setValueForPath(key.split('.'), prop, val)
    return utils.merge(ob, prop)
  }, {})

  return utils.merge(enumProps, omitEnumProps(props))

  function omitEnumProps(props) {
    var enumPropNames = _(enumProperties).toPairs().map(function (x) { return x[1] }).flatten().value()
    return _.omit(props, enumPropNames)
  }
}
<commit_msg>Fix provider import<commit_after>var mongoose = require('mongoose')
var schema = require('../server/schema')
var utils = require('../shared/utils')
var _ = require('lodash')
var xlsx = require('xlsx')
var xls = require('xlsjs')
var async = require('async')
var enums = require('../shared/enums')

// NOTE: field order matters
var providerFieldMap = [
  'name',
  'yTunnus',
  'address.street',
  'address.zip',
  'address.city',
  'language',
  'contactName',
  'emailAddresses',
  'phoneNumber',
  'address.country'
]

// NOTE: field order matters
var billingFieldMap = [
  'billing.address.street',
  'billing.address.zip',
  'billing.address.city',
  'billing.invoiceText'
]

// NOTE: field order matters
var eInvoiceFieldMap = [
  'eInvoice.address',
  'eInvoice.operator'
]

// NOTE: field order matters
var locationFieldMap = [
  'name',
  'address.street',
  'address.zip',
  'address.city',
  'isPayer',
  'contactName',
  'emailAddresses',
  'phoneNumber',
  'Recordings_provide',
  'Public_presentation',
  'National_TV',
  'Regional_TV',
  'Transmitted_abroad_program',
  'Subscription_of_program',
  'url',
  'adultContent'
]

var fieldNames = {
  'name': 'Nimi',
  'yTunnus': 'Y-tunnus',
  'address.street': 'lähiosoite',
  'address.zip': 'postinro',
  'address.city': 'postitoimipaikka',
  'language': 'asiointikieli',
  'contactName': 'yhteyshenkilö',
  'emailAddresses': 'sähköposti',
  'phoneNumber': 'puhelinnumero'
}

// These need to match exactly with the labels in the provider Excel file
var i18n = {
  sv: {
    'Tarjoaja': 'Leverantör',
    'Lasku eri osoitteeseen kuin Tarjoajan osoite': 'Faktura till annan adress än Leverantörens',
    'TAI verkkolasku': 'ELLER nätfaktura',
    'Tarjoamispaikkojen tiedot ja tarjoamistavat': 'Information om ställen och sätt för tillhandahållning'
  }
}

function sv(txt) {
  return i18n.sv[txt] || txt
}

exports.import = function(file, callback) {
  var parser = false

  if (file.originalname.search(/.xls$/) > 1) parser = xls
  else if (file.originalname.search(/.xlsx$/) > 1) parser = xlsx
  else return callback({ message: '.xlsx or .xls required' })

  var allSheets = parser.readFile(file.path)
  var sheetFi = allSheets.Sheets['Tarjoajaksi ilmoittautuminen']
  var sheetSv = allSheets.Sheets['Leverantörsanmälan'] || allSheets.Sheets['Leverantörsanmälan']
  var useFi = isEmptySheet(sheetSv, i18n.sv['Tarjoaja'])

  getProviderAndLocationsFromSpreadSheet(useFi ? sheetFi : sheetSv, useFi ? identity : sv, function(err, providerAndLocations) {
    if (err) return callback(err)
    var provider = createProvider(providerAndLocations.provider, providerAndLocations.billing)
    provider.locations = createLocations(providerAndLocations.locations)
    return callback(null, provider)
  })

  function createProvider(providerData, billingData) {
    var provider = createObjectAndSetValuesWithMap(providerData, providerFieldMap)
    provider.deleted = false
    provider.active = false
    provider.creationDate = new Date()
    provider.language = (provider.language && provider.language.toLowerCase() == 'svenska') ? 'SV' : 'FI'
    provider.address.country = enums.getCountryCode(provider.address.country) || 'FI'

    var billing = createObjectAndSetValuesWithMap(billingData, billingFieldMap)

    provider = utils.merge(provider, billing)

    if (provider.billing && provider.billing.address) {
      var address = provider.billing.address
      provider.billingPreference = 'address'
    }

    if (provider.eInvoice) {
      provider.billingPreference = 'eInvoice'
    }

    return provider
  }

  function createLocations(locationsData) {
    return _.map(locationsData, function(location) {
      var location = createObjectAndSetValuesWithMap(location, locationFieldMap, { providingType: _.keys(enums.providingType) })

      return utils.merge(location, {
        deleted: false,
        active: true,
        isPayer: stringXToBoolean(location.isPayer),
        adultContent: stringXToBoolean(location.adultContent),
      })
    })
  }
  function stringXToBoolean(x) { return _.isString(x) ? x.toLowerCase() === 'x' : false }
}

function getProviderAndLocationsFromSpreadSheet(providerSheet, text, callback) {
  var requiredProviderFields = {
    name: 'Tarjoajan tiedot:',
    values: ['name', 'yTunnus', 'contactName', 'address.street', 'address.zip', 'address.city', 'address.country', 'phoneNumber', 'language']
  }

  var requiredLocationFields = {
    name: 'Tarjoamispaikan tiedot:',
    values: ['name', 'contactName', 'address.street', 'address.zip', 'address.city', 'phoneNumber']
  }

  var noRequiredFields = { name: '', values: [] }

  var errors = []

  var providerData = parseFieldRowAndValueRowAfterColumn(text('Tarjoaja'), providerFieldMap, requiredProviderFields)
  var billingData = parseFieldRowAndValueRowAfterColumn(text('Lasku eri osoitteeseen kuin Tarjoajan osoite'), billingFieldMap, noRequiredFields)
  var eInvoiceData = parseFieldRowAndValueRowAfterColumn(text('TAI verkkolasku'), eInvoiceFieldMap, noRequiredFields)
  var locationsData = parseFieldRowAndValueRowsAfterColumn(text('Tarjoamispaikkojen tiedot ja tarjoamistavat'), locationFieldMap, requiredLocationFields)

  if (locationsData.length === 0) errors.push('Tarjoamispaikkojen tiedot puuttuvat')

  if (errors.length > 0) {
    return callback({ messages: errors })
  } else {
    return callback(null, {
      provider: providerData,
      billing: utils.merge(billingData, eInvoiceData),
      locations: locationsData
    })
  }

  function parseFieldRowAndValueRowAfterColumn(column, fieldMap, requiredFields) {
    var rowNumber = findColumnRowByValue(providerSheet, column)
    var row = toObject(providerSheet, rowNumber + 2, fieldMap)
    var errorMessages = validate(row, requiredFields, rowNumber + 2, fieldMap)
    errorMessages.forEach(function(msg) {
      errors.push(msg)
    })

    return row
  }

  function parseFieldRowAndValueRowsAfterColumn(column, fieldMap, requiredFields) {
    var rowNumber = findColumnRowByValue(providerSheet, column)

    var rows = values([], rowNumber + 2)

    var errorMessages = _.reduce(rows, function(acc, val) {
      var index = acc[0], errors = acc[1]
      var fieldErrors = validate(val, requiredFields, index, fieldMap)
      return [index + 1, errors.concat(fieldErrors)
        .concat(validateProvidingType(val, index))
        .concat(validateRequiredEmail(val, index))]
    }, [rowNumber + 2, []])[1]

    errorMessages.forEach(function(msg) {
      errors.push(msg)
    })

    return rows

    function values(xs, row) {
      var currentValues = toObject(providerSheet, row, fieldMap)
      if (_.every(currentValues, function(x) { return x === null})) {
        return xs
      } else {
        return values(xs.concat([currentValues]), row + 1)
      }
    }

    function validateProvidingType(val, index) {
      var providingTypeFields = _.keys(enums.providingType)
      var present = _.keys(val)
      var hasAtLeastOneProvidingType = _(providingTypeFields).map(function(name) {
        return _.indexOf(present, name) > 0
      }).some()

      if (!hasAtLeastOneProvidingType) {
        return ['Tarjoamispaikan tiedot rivillä ' + index + ': tarjoamispaikalla täytyy olla ainakin yksi tajoamistapa.']
      } else {
        return []
      }
    }

    function validateRequiredEmail(val, row) {
      var msg = 'Tarjoamispaikan tiedot rivillä ' + row + ': sähköpostiosoite on pakollinen jos lasku lähetetään tarjoamispaikalle.'
      if (val.isPayer && !val.emailAddresses) return [msg]
      else return []
    }
  }

  function validate(values, requiredFields, index, fieldMap) {
    var present = _.keys(values)
    var missing = _.reduce(requiredFields.values, function(acc, r) {
      if (_.indexOf(present, r) === -1) return acc.concat(r)
      else return acc
    }, [])

    return _.map(missing, function (field) {
      var errorString = 'Rivillä <%- row %>. <%- name %> pakollinen kenttä "<%- field %>" puuttuu'
      return _.template(errorString)({
        name: requiredFields.name,
        field: fieldNames[field],
        row: index
      })
    })
  }

}

function findColumnRowByValue(from, value) {
  var columnRowNumber = undefined

  _.find(from, function(field, key) {
    if (field.v && (field.v.trim().toLowerCase() == value.toLowerCase())) {
      columnRowNumber = parseRowNumber(key)
      return true
    }
  })

  return columnRowNumber

  function parseRowNumber(key) { return parseInt(key.substring(key.search(/\d/))) }
}

function toObject(from, row, fields) {
  var fst = function(x) { return x[0] }
  var snd = function(x) { return x[1] }

  var ob = _.reduce(from, function(result, field, key) {
    if (key.match(new RegExp('.' + row))) {
      return utils.merge(result, utils.keyValue(key.substr(0, 1), field.v))
    }
    else return result
  }, emptyRow(fields.length))

  var values = _(ob).toPairs().sortBy(fst).map(snd).value()

  return _.pickBy(_.zipObject(fields, values), _.identity)
}

function emptyRow(count) {
  return _('BCDEFGHIJKLMNOPQRSTU'.split('')).take(count).reduce(function(ob, c) {
    return utils.merge(ob, utils.keyValue(c, null))
  }, {})
}

function isEmptySheet(s, heading) {
  var rowNumber = findColumnRowByValue(s, heading)
  var row = toObject(s, rowNumber + 2, providerFieldMap)
  return _.isEmpty(row)
}

function identity(x) { return x }

function createObjectAndSetValuesWithMap(object, map, enumProperties) {
  var enumProps = _.reduce(_.toPairs(enumProperties), function(ob, x) {
    var propName = x[0], fields = x[1]
    return utils.merge(ob, utils.keyValue(propName, toArray(fields)))

    function toArray(fields) {
      return _.reduce(fields, function(acc, field) {
        if (object[field]) return acc.concat(field)
        else return acc
      }, [])
    }
  }, {})

  var props = _.reduce(_.toPairs(utils.flattenObject(object)), function(ob, pair) {
    var key = pair[0], val = pair[1], prop = {}
    utils.setValueForPath(key.split('.'), prop, val)
    return utils.merge(ob, prop)
  }, {})

  return utils.merge(enumProps, omitEnumProps(props))

  function omitEnumProps(props) {
    var enumPropNames = _(enumProperties).toPairs().map(function (x) { return x[1] }).flatten().value()
    return _.omit(props, enumPropNames)
  }
}
<|endoftext|>


<commit_before>var Tethys = (function (my) {

    document.querySelector('#tree').addEventListener('click', function (event) {
        if (event.target.className.indexOf('file') !== -1) {
            var fileId = event.target.dataset.fileid;
            if (fileId === 'new') {
                var parentId = event.target.dataset.parent;
                Modal.onsubmit["createFile"] = function (button, input) {
                    var newName = input[0];
                    if (newName.length <= 0) newName = "New " + button;
                    if (button === 'file') {
                        FileSystem.mkfile(parentId, newName);
                        Modal.close();
                    } else if (button === 'folder'){
                        FileSystem.mkdir(parentId, newName);
                        Modal.close();
                    } else if (button === "github"){
                        Modal.onsubmit["github"] = function(button, input){
                            FileSystem.fetchRepo(parentId, input[0], input[1]);
                            Modal.close();
                        }
                        Modal.open("github");
                    }else{
                        Modal.close();
                    }
                }
                Modal.open('createFile');
                document.querySelector("#fileUpload").addEventListener('change', function(event){
                    var files = event.target.files;
                    for (var i=0; i<files.length; i++){
                        FileSystem.loadFile(files[i], parentId);
                    }
                    Modal.close();
                });
            } else if (fileId === 'delete'){
                var parentId = event.target.dataset.parent;
                var fileName = event.target.dataset.name;
                Modal.onsubmit["confirmFolderDelete"] = function (button, input) {
                    if (button === 'yes') {
                        FileSystem.del(parentId);
                    }
                    Modal.close();
                }
                Modal.open('confirmFolderDelete',{name:fileName});
            }else {
                FileSystem.open(fileId);
            }

        }
    });

    document.querySelector('#delete').addEventListener('click', function (event) {
        Modal.onsubmit["confirmDelete"] = function (button, input) {
            if (button === 'yes') {
                FileSystem.delCurrent();
            }
            Modal.close();
        }
        Modal.open('confirmDelete', FileSystem.workingFile);
    });

    var toolbarCollapsed=false;
    document.querySelector('#collapsetoolbar').addEventListener('click', function (event) {
        toolbarCollapsed=!toolbarCollapsed;
        if (toolbarCollapsed){
            document.querySelector('.toolbar').style.height='30px';
            document.querySelector('.workspace').style.bottom='30px';
            document.querySelector('.sidebar').style.bottom='30px';
            document.querySelector('.roomlist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist').style.border = '0';
        }else{
            document.querySelector('.toolbar').style.height='';
            document.querySelector('.workspace').style.bottom='';
            document.querySelector('.sidebar').style.bottom='';
            document.querySelector('.roomlist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist').style.border = '';
        }
    });

    var sidebarCollapsed=false;
    document.querySelector('#collapsesidebar').addEventListener('click', function (event) {
        sidebarCollapsed=!sidebarCollapsed;
        if (sidebarCollapsed){
            document.querySelector('.sidebar').style.width='30px';
            document.querySelector('.workspace').style.left='30px';
            document.querySelector('#tree').style.display='none';
            document.querySelector('.sidebar .panel-topbar').style.display='none';
        }else{
            document.querySelector('.sidebar').style.width='';
            document.querySelector('.workspace').style.left='';
            document.querySelector('#tree').style.display='';
            document.querySelector('.sidebar .panel-topbar').style.display='';
        }
    });

    document.querySelector('#savezip').addEventListener('click', function (event) {
        FileSystem.saveAsZip();
    });

    document.querySelector('#settings').addEventListener('click', function (event) {
        Modal.onsubmit['themes'] = function(button, input){
            FileSystem.setTheme(button);
        }
        Modal.open("themes");
    });

    document.querySelector('#roomlist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me" || !SocketAPI.isMyRoom) return;
            Modal.onsubmit["confirmKick"] = function () {
                SocketAPI.kick(userID);
                Modal.close();
            };
            Modal.open('confirmKick', {
                name: name
            });
        }
    });

    document.querySelector('#onlinelist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me") return;
            Modal.onsubmit["requestInvite"] = function () {
                SocketAPI.requestRoom(userID);
                Modal.close();
            };
            Modal.open('requestInvite', {
                name: name
            });
        }
    });

    var me;
    var username;
    var hash;
    Modal.onsubmit['intro'] = function (button, input) {
        if (!input[0] || input[0].length <= 1) {
            input[0]="Guest";
        }
        username = input[0];
        var pic = Math.floor(Math.random() * 95);
        hash = Math.random();
        SocketAPI.joinOnline(username, pic, hash);

        me = {
            id: "me",
            name: "You",
            pic: pic,
            hash : hash
        }
        makeUser(me, "room", true);

        Modal.open('welcome');
    }

    var roomlistElement = document.querySelector("#roomlist > .panel");
    var onlinelistElement = document.querySelector("#onlinelist > .panel");

    var roomElements = {};
    var onlineElements = {};
    var userTemplate = `<img class="user-img" data-name="{{name}}" data-userid="{{id}}" src="img/miniman/avatar-{{pic}}.png"><label>{{name}}</label>`;

    my.roomEmpty = function(){
        return roomElements <= 1;
    }

    var cursors = {};

    function makeCursor(user){
        var img = document.createElement('img');
        img.src="img/pointer.png";
        img.className = "cursor";
        img.displayed=false;
        img.style.display='none';
        cursors[user.id]=document.body.appendChild(img);
    }

    function moveCursor(userId, coords){
        var x = coords.x+getSidebarWidth();
        while (x > window.innerWidth){ //Deal with line wrapping (only large to small for now)
            x = x - getEditorWidth();
            coords.y = coords.y+19; //19 is height of line
        }

        cursors[userId].style.left = x+"px";
        cursors[userId].style.top = coords.y+"px";
    }

    function getEditorWidth(){
        return window.innerWidth - getSidebarWidth() - 29; //29 is width of number column
    }

    function getSidebarWidth(){
        if (window.innerWidth >= 768){
            return 340;
        }else{
            return 150;
        }
    }

    var cursorMoveMutex = false;
    var lastCursor = {x: 0, y:0};
    var sidebarWidth;
    window.addEventListener('mousemove', function(e){
        return; //TODO: Calculate cursor positions on editor
        if (my.roomEmpty()) return;
        //Subtract sidebar width
        lastCursor={x: e.clientX-getSidebarWidth(), y: e.clientY};

        if (cursorMoveMutex) return;  //Ratelimit
        cursorMoveMutex = true;
        setTimeout(function(){
            SocketAPI.moveCursor(lastCursor);
            cursorMoveMutex = false;
        },100);

    });

    window.addEventListener('mouseout', function(e){
        e = e ? e : window.event;
        var from = e.relatedTarget || e.toElement;
        if (!from || from.nodeName == "HTML") {
            setTimeout(function(){
                SocketAPI.moveCursor({x:-50, y:-50});
            },500);
        }
    },false);

    SocketAPI.onMoveCursor = function(userId, fileId, coords) {
        return; //TODO: Calculate cursor positions on editor
        if (fileId === FileSystem.workingFile.fileId){
            if (!cursors[userId].displayed){
                cursors[userId].displayed=true;
                cursors[userId].style.display = '';
            }
            moveCursor(userId, coords);
        }else{
            if (cursors[userId].displayed){
                cursors[userId].displayed=false;
                cursors[userId].style.display = 'none';
            }
        }
    }

    function makeUser(user, group, isMe){
        if (user.hash == hash && !isMe) return; //Don't make self
        var div = document.createElement('div');
        div.className = "square";
        div.innerHTML = Microstache.template(userTemplate, user);

        if (group === "online"){
            onlinelistElement.appendChild(div);
            onlineElements[user.id] = div;
        }
        if (group === 'room'){
            roomlistElement.appendChild(div);
            roomElements[user.id] = div;
        }
    }
    function removeUser(user, group){
        var re = roomElements[user.id];
        var we = onlineElements[user.id]
        if (re && re.parentNode == roomlistElement){
            roomlistElement.removeChild(roomElements[user.id]);
        }
        if (we && we.parentNode == onlinelistElement){
            onlinelistElement.removeChild(onlineElements[user.id]);
        }
    }
    function clearRoom(){
        while (roomlistElement.firstChild){
            roomlistElement.removeChild(roomlistElement.firstChild);
        }
        makeUser(me, 'room', true);
    }

    SocketAPI.onOtherJoinOnline = function (user) {
        removeUser(user);
        makeUser(user,'online');
    }
    SocketAPI.onOtherLeftOnline = function (user) {
        removeUser(user);
        if (cursors[user.id]){
            cursors[user.id].parentNode.removeChild(cursors[user.id]); // Remove their cursor
        }
    }
    SocketAPI.onOtherJoinRoom = function (user) {
        removeUser(user);
        makeUser(user, 'room');
        makeCursor(user); //Make a cursor
    }
    SocketAPI.onOtherLeftRoom = function (user) {
        removeUser(user, 'room');
        if (cursors[user.id]){
            cursors[user.id].parentNode.removeChild(cursors[user.id]); // Remove their cursor
        }
    }
    SocketAPI.onWho = function(onlineList){
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
    }
    SocketAPI.onRequestRoom = function(user, orignalId){
        Modal.onsubmit["request-join"]=function(button){
            if (button==="accept"){
                SocketAPI.respondToRoomRequest(user.id, orignalId);
            }
            Modal.close();
        }
        Modal.open('request-join', user);
    }
    SocketAPI.onRoomRespond = function(roomOwner, who){
        Modal.onsubmit['join-response'] = function(){};
        Modal.open('join-response', {name:roomOwner.name});
        clearRoom();
        for (var i=0; i<who.length; i++){
            removeUser(who[i]);
            makeUser(who[i], 'room');
            makeCursor(who[i]);
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = roomOwner.name+"'s Room";
    }
    SocketAPI.onKick = function(onlineList){
        clearRoom();
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = "Your Room";
        Modal.onsubmit['kick-alert'] = function(){};
        Modal.open('kick-alert');
    }

    FileSystem.init(true);
    FileSystem.open("welcome");
    Modal.open('intro');

    var code = Util.getParameterByName("code");
    var ext= Util.getParameterByName("ext");
    var theme = Util.getParameterByName("theme");
    FileSystem.openString(code,ext);
    if (theme){
        FileSystem.setTheme(theme);
    }

    console.log("%c Rock that console! If you're after the source: https://github.com/RationalCoding/MultiHack", "color:#263238; font-size: 15px;");

    return my;
}({}))<commit_msg>reenable cursor sharing for desktop-desktop<commit_after>var Tethys = (function (my) {

    document.querySelector('#tree').addEventListener('click', function (event) {
        if (event.target.className.indexOf('file') !== -1) {
            var fileId = event.target.dataset.fileid;
            if (fileId === 'new') {
                var parentId = event.target.dataset.parent;
                Modal.onsubmit["createFile"] = function (button, input) {
                    var newName = input[0];
                    if (newName.length <= 0) newName = "New " + button;
                    if (button === 'file') {
                        FileSystem.mkfile(parentId, newName);
                        Modal.close();
                    } else if (button === 'folder'){
                        FileSystem.mkdir(parentId, newName);
                        Modal.close();
                    } else if (button === "github"){
                        Modal.onsubmit["github"] = function(button, input){
                            FileSystem.fetchRepo(parentId, input[0], input[1]);
                            Modal.close();
                        }
                        Modal.open("github");
                    }else{
                        Modal.close();
                    }
                }
                Modal.open('createFile');
                document.querySelector("#fileUpload").addEventListener('change', function(event){
                    var files = event.target.files;
                    for (var i=0; i<files.length; i++){
                        FileSystem.loadFile(files[i], parentId);
                    }
                    Modal.close();
                });
            } else if (fileId === 'delete'){
                var parentId = event.target.dataset.parent;
                var fileName = event.target.dataset.name;
                Modal.onsubmit["confirmFolderDelete"] = function (button, input) {
                    if (button === 'yes') {
                        FileSystem.del(parentId);
                    }
                    Modal.close();
                }
                Modal.open('confirmFolderDelete',{name:fileName});
            }else {
                FileSystem.open(fileId);
            }

        }
    });

    document.querySelector('#delete').addEventListener('click', function (event) {
        Modal.onsubmit["confirmDelete"] = function (button, input) {
            if (button === 'yes') {
                FileSystem.delCurrent();
            }
            Modal.close();
        }
        Modal.open('confirmDelete', FileSystem.workingFile);
    });

    var toolbarCollapsed=false;
    document.querySelector('#collapsetoolbar').addEventListener('click', function (event) {
        toolbarCollapsed=!toolbarCollapsed;
        if (toolbarCollapsed){
            document.querySelector('.toolbar').style.height='30px';
            document.querySelector('.workspace').style.bottom='30px';
            document.querySelector('.sidebar').style.bottom='30px';
            document.querySelector('.roomlist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist .panel-topbar').style.display = 'none';
            document.querySelector('.onlinelist').style.border = '0';
        }else{
            document.querySelector('.toolbar').style.height='';
            document.querySelector('.workspace').style.bottom='';
            document.querySelector('.sidebar').style.bottom='';
            document.querySelector('.roomlist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist .panel-topbar').style.display = '';
            document.querySelector('.onlinelist').style.border = '';
        }
    });

    var sidebarCollapsed=false;
    document.querySelector('#collapsesidebar').addEventListener('click', function (event) {
        sidebarCollapsed=!sidebarCollapsed;
        if (sidebarCollapsed){
            document.querySelector('.sidebar').style.width='30px';
            document.querySelector('.workspace').style.left='30px';
            document.querySelector('#tree').style.display='none';
            document.querySelector('.sidebar .panel-topbar').style.display='none';
        }else{
            document.querySelector('.sidebar').style.width='';
            document.querySelector('.workspace').style.left='';
            document.querySelector('#tree').style.display='';
            document.querySelector('.sidebar .panel-topbar').style.display='';
        }
    });

    document.querySelector('#savezip').addEventListener('click', function (event) {
        FileSystem.saveAsZip();
    });

    document.querySelector('#settings').addEventListener('click', function (event) {
        Modal.onsubmit['themes'] = function(button, input){
            FileSystem.setTheme(button);
        }
        Modal.open("themes");
    });

    document.querySelector('#roomlist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me" || !SocketAPI.isMyRoom) return;
            Modal.onsubmit["confirmKick"] = function () {
                SocketAPI.kick(userID);
                Modal.close();
            };
            Modal.open('confirmKick', {
                name: name
            });
        }
    });

    document.querySelector('#onlinelist').addEventListener('click', function (event) {
        if (event.target.className.indexOf('square') !== -1) {
            var imgEl = event.target.getElementsByTagName('img')[0];
            var userID = imgEl.dataset.userid;
            var name = imgEl.dataset.name;
            if (userID === "me") return;
            Modal.onsubmit["requestInvite"] = function () {
                SocketAPI.requestRoom(userID);
                Modal.close();
            };
            Modal.open('requestInvite', {
                name: name
            });
        }
    });

    var me;
    var username;
    var hash;
    Modal.onsubmit['intro'] = function (button, input) {
        if (!input[0] || input[0].length <= 1) {
            input[0]="Guest";
        }
        username = input[0];
        var pic = Math.floor(Math.random() * 95);
        hash = Math.random();
        SocketAPI.joinOnline(username, pic, hash);

        me = {
            id: "me",
            name: "You",
            pic: pic,
            hash : hash
        }
        makeUser(me, "room", true);

        Modal.open('welcome');
    }

    var roomlistElement = document.querySelector("#roomlist > .panel");
    var onlinelistElement = document.querySelector("#onlinelist > .panel");

    var roomElements = {};
    var onlineElements = {};
    var userTemplate = `<img class="user-img" data-name="{{name}}" data-userid="{{id}}" src="img/miniman/avatar-{{pic}}.png"><label>{{name}}</label>`;

    my.roomEmpty = function(){
        return roomElements <= 1;
    }

    var cursors = {};

    function makeCursor(user){
        var img = document.createElement('img');
        img.src="img/pointer.png";
        img.className = "cursor";
        img.displayed=false;
        img.style.display='none';
        cursors[user.id]=document.body.appendChild(img);
    }

    function moveCursor(userId, coords){
        var x = coords.x+getSidebarWidth();
        while (x > window.innerWidth){ //Deal with line wrapping (only large to small for now)
            x = x - getEditorWidth();
            coords.y = coords.y+19; //19 is height of line
        }

        cursors[userId].style.left = x+"px";
        cursors[userId].style.top = coords.y+"px";
    }

    function getEditorWidth(){
        return window.innerWidth - getSidebarWidth() - 29; //29 is width of number column
    }

    function getSidebarWidth(){
        if (window.innerWidth >= 768){
            return 340;
        }else{
            return 150;
        }
    }

    var cursorMoveMutex = false;
    var lastCursor = {x: 0, y:0};
    var sidebarWidth;
    window.addEventListener('mousemove', function(e){
        //TODO: Calculate cursor positions on editor
        if (window.innerWidth < 480) return; //Mismatches on mobile get too extreme
        if (my.roomEmpty()) return;
        //Subtract sidebar width
        lastCursor={x: e.clientX-getSidebarWidth(), y: e.clientY};

        if (cursorMoveMutex) return;  //Ratelimit
        cursorMoveMutex = true;
        setTimeout(function(){
            SocketAPI.moveCursor(lastCursor);
            cursorMoveMutex = false;
        },100);

    });

    window.addEventListener('mouseout', function(e){
        e = e ? e : window.event;
        var from = e.relatedTarget || e.toElement;
        if (!from || from.nodeName == "HTML") {
            setTimeout(function(){
                SocketAPI.moveCursor({x:-50, y:-50});
            },500);
        }
    },false);

    SocketAPI.onMoveCursor = function(userId, fileId, coords) {
        //TODO: Calculate cursor positions on editor
        if (window.innerWidth < 480) return; //Mismatches on mobile get too extreme
        if (fileId === FileSystem.workingFile.fileId){
            if (!cursors[userId].displayed){
                cursors[userId].displayed=true;
                cursors[userId].style.display = '';
            }
            moveCursor(userId, coords);
        }else{
            if (cursors[userId].displayed){
                cursors[userId].displayed=false;
                cursors[userId].style.display = 'none';
            }
        }
    }

    function makeUser(user, group, isMe){
        if (user.hash == hash && !isMe) return; //Don't make self
        var div = document.createElement('div');
        div.className = "square";
        div.innerHTML = Microstache.template(userTemplate, user);

        if (group === "online"){
            onlinelistElement.appendChild(div);
            onlineElements[user.id] = div;
        }
        if (group === 'room'){
            roomlistElement.appendChild(div);
            roomElements[user.id] = div;
        }
    }
    function removeUser(user, group){
        var re = roomElements[user.id];
        var we = onlineElements[user.id]
        if (re && re.parentNode == roomlistElement){
            roomlistElement.removeChild(roomElements[user.id]);
        }
        if (we && we.parentNode == onlinelistElement){
            onlinelistElement.removeChild(onlineElements[user.id]);
        }
    }
    function clearRoom(){
        while (roomlistElement.firstChild){
            roomlistElement.removeChild(roomlistElement.firstChild);
        }
        makeUser(me, 'room', true);
    }

    SocketAPI.onOtherJoinOnline = function (user) {
        removeUser(user);
        makeUser(user,'online');
    }
    SocketAPI.onOtherLeftOnline = function (user) {
        removeUser(user);
        if (cursors[user.id]){
            cursors[user.id].parentNode.removeChild(cursors[user.id]); // Remove their cursor
        }
    }
    SocketAPI.onOtherJoinRoom = function (user) {
        removeUser(user);
        makeUser(user, 'room');
        makeCursor(user); //Make a cursor
    }
    SocketAPI.onOtherLeftRoom = function (user) {
        removeUser(user, 'room');
        if (cursors[user.id]){
            cursors[user.id].parentNode.removeChild(cursors[user.id]); // Remove their cursor
        }
    }
    SocketAPI.onWho = function(onlineList){
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
    }
    SocketAPI.onRequestRoom = function(user, orignalId){
        Modal.onsubmit["request-join"]=function(button){
            if (button==="accept"){
                SocketAPI.respondToRoomRequest(user.id, orignalId);
            }
            Modal.close();
        }
        Modal.open('request-join', user);
    }
    SocketAPI.onRoomRespond = function(roomOwner, who){
        Modal.onsubmit['join-response'] = function(){};
        Modal.open('join-response', {name:roomOwner.name});
        clearRoom();
        for (var i=0; i<who.length; i++){
            removeUser(who[i]);
            makeUser(who[i], 'room');
            makeCursor(who[i]);
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = roomOwner.name+"'s Room";
    }
    SocketAPI.onKick = function(onlineList){
        clearRoom();
        for (var i=0; i<onlineList.length; i++){
            removeUser(onlineList[i]);
            makeUser(onlineList[i],'online');
        }
        document.querySelector("#roomlist > .panel-topbar").innerHTML = "Your Room";
        Modal.onsubmit['kick-alert'] = function(){};
        Modal.open('kick-alert');
    }

    FileSystem.init(true);
    FileSystem.open("welcome");
    Modal.open('intro');

    var code = Util.getParameterByName("code");
    var ext= Util.getParameterByName("ext");
    var theme = Util.getParameterByName("theme");
    FileSystem.openString(code,ext);
    if (theme){
        FileSystem.setTheme(theme);
    }

    console.log("%c Rock that console! If you're after the source: https://github.com/RationalCoding/MultiHack", "color:#263238; font-size: 15px;");

    return my;
}({}))<|endoftext|>


<commit_before>// Official roles GET controllers

'use strict';

var aFrom               = require('es5-ext/array/from')
  , flatten             = require('es5-ext/array/#/flatten')
  , remove              = require('es5-ext/array/#/remove')
  , uniq                = require('es5-ext/array/#/uniq')
  , constant            = require('es5-ext/function/constant')
  , isNaturalNumber     = require('es5-ext/number/is-natural')
  , toNaturalNumber     = require('es5-ext/number/to-pos-integer')
  , normalizeOptions    = require('es5-ext/object/normalize-options')
  , toArray             = require('es5-ext/object/to-array')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , includes            = require('es5-ext/string/#/contains')
  , uncapitalize        = require('es5-ext/string/#/uncapitalize')
  , d                   = require('d')
  , ensureSet           = require('es6-set/valid-set')
  , deferred            = require('deferred')
  , memoize             = require('memoizee')
  , serializeValue      = require('dbjs/_setup/serialize/value')
  , unserializeValue    = require('dbjs/_setup/unserialize/value')
  , ObservableSet       = require('observable-set/primitive')
  , mano                = require('mano')
  , roleNameMap         = require('mano/lib/server/user-role-name-map')
  , QueryHandler        = require('../../utils/query-handler')
  , defaultItemsPerPage = require('../../conf/objects-list-items-per-page')
  , getDbSet            = require('../utils/get-db-set')
  , getDbArray          = require('../utils/get-db-array')
  , getIndexMap         = require('../utils/get-db-sort-index-map')

  , hasBadWs = RegExp.prototype.test.bind(/\s{2,}/)
  , compareStamps = function (a, b) { return a.stamp - b.stamp; }
  , isArray = Array.isArray, slice = Array.prototype.slice, push = Array.prototype.push
  , ceil = Math.ceil, create = Object.create
  , defineProperty = Object.defineProperty, stringify = JSON.stringify;

var compareIndexMeta = function (meta1, meta2) {
	return meta1.name.localeCompare(meta2.name) || meta1.value.localeCompare(meta2.value);
};

// Business processes table query handler
var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

// Single business process full data query handler
var getBusinessProcessQueryHandler = function (indexName) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				if (!value) throw new Error("Missing id");
				return mano.dbDriver.getComputed(value + '/' + indexName)(function (data) {
					if (!data || (data.value !== '11')) return null;
					return value;
				});
			}
		}
	]);
};

var getFilteredSet = memoize(function (baseSet, filterString) {
	var set = new ObservableSet(), baseSetListener, indexListener
	  , def = deferred(), count = 0, isInitialized = false;
	var filter = function (ownerId, data) {
		var value = unserializeValue(data.value);
		if (value && includes.call(value, filterString)) set.add(ownerId);
		else set.delete(ownerId);
	};
	var findAndFilter = function (ownerId) {
		return mano.dbDriver.getComputed(ownerId + '/searchString').aside(function (data) {
			if (!baseSet.has(ownerId)) return;
			if (!data) return;
			filter(ownerId, data);
		});
	};
	baseSet.on('change', baseSetListener = function (event) {
		if (event.type === 'add') findAndFilter(event.value).done();
		else set.delete(event.value);
	});
	mano.dbDriver.on('key:searchString', indexListener = function (event) {
		if (!baseSet.has(event.ownerId)) return;
		filter(event.ownerId, event.data);
	});
	baseSet.forEach(function (ownerId) {
		++count;
		findAndFilter(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(set);
		});
	});
	isInitialized = true;
	if (!count) def.resolve(set);
	defineProperty(set, '_dispose', d(function () {
		baseSet.off(baseSetListener);
		mano.dbDriver.off('key:searchString', indexListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (set) { set._dispose(); } });

var getDbArrayLru = memoize(function (set, sortIndexName) {
	var arr = [], itemsMap = getIndexMap(sortIndexName)
	  , count = 0, isInitialized = false, def = deferred(), setListener, itemsListener;
	var add = function (ownerId) {
		return deferred(itemsMap[ownerId] || mano.dbDriver.getComputed(ownerId + '/' + sortIndexName))
			.aside(function (data) {
				if (!set.has(ownerId)) return;
				if (!itemsMap[ownerId]) itemsMap[ownerId] = { id: ownerId, stamp: data.stamp };
				arr.push(itemsMap[ownerId]);
				if (def.resolved) arr.sort(compareStamps);
			});
	};
	set.on('change', setListener = function (event) {
		if (event.type === 'add') add(event.value).done();
		else remove.call(arr, itemsMap[event.value]);
	});
	itemsMap.on('update', itemsListener = function (event) {
		if (!set.has(event.ownerId)) return;
		if (def.resolved) arr.sort(compareStamps);
	});
	set.forEach(function (ownerId) {
		++count;
		add(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(arr.sort(compareStamps));
		});
	});
	isInitialized = true;
	if (!count) def.resolve(arr.sort(compareStamps));
	defineProperty(set, '_dispose', d(function () {
		set.off(setListener);
		itemsMap.off(itemsListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (arr) { arr._dispose(); } });

var initializeHandler = function (conf) {
	conf = normalizeOptions(ensureObject(conf));
	var roleName = ensureString(conf.roleName)
	  , statusIndexName = ensureString(conf.statusIndexName)
	  , allIndexName = ensureString(conf.allIndexName)
	  , bpListProps = ensureSet(conf.listProperties)
	  , bpListComputedProps = conf.listComputedProperties && aFrom(conf.listComputedProperties)
	  , tableQueryHandler = getTableQueryHandler(ensureObject(conf.statusMap))
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(conf.allIndexName)
	  , itemsPerPage = toNaturalNumber(conf.itemsPerPage) || defaultItemsPerPage
	  , indexes;

	if (conf.resolveCollectionMeta != null) ensureCallable(conf.resolveCollectionMeta);

	if (bpListComputedProps) {
		indexes = [];
		deferred.map(bpListComputedProps, function (keyPath) {
			return mano.dbDriver.indexKeyPath(keyPath)(function (map) {
				indexes.push({ keyPath: keyPath, map: map });
			});
		});
	}

	var getTableData = memoize(function (query) {
		var indexMeta = exports.getIndexMeta(query, conf), promise;
		if (isArray(indexMeta)) {
			promise = deferred.map(indexMeta.sort(compareIndexMeta), function (indexMeta) {
				return getDbSet('computed', indexMeta.name, indexMeta.value);
			})(function (sets) {
				return aFrom(sets).reduce(function (set1, set2) { return set1.and(set2); });
			});
		} else {
			promise = getDbSet('computed', indexMeta.name, indexMeta.value);
		}
		if (query.assignedTo) {
			promise = promise.then(function (baseSet) {
				return getDbSet('direct', conf.assigneePath, '7' + query.assignedTo)(function (set) {
					return baseSet.and(set);
				});
			});
		}
		return promise(function (baseSet) {
			if (!query.search) return getDbArray(baseSet, 'computed', allIndexName);
			return deferred.map(query.search.split(/\s+/).sort(), function (value) {
				return getFilteredSet(baseSet, value)(function (set) {
					return getDbArrayLru(set, allIndexName);
				});
			})(function (arrays) {
				if (arrays.length === 1) return arrays[0];
				return uniq.call(arrays.reduce(function (current, next, index) {
					if (index === 1) current = aFrom(current);
					push.apply(current, next);
					return current;
				})).sort(compareStamps);
			});
		})(function (arr) {
			var size = arr.length, pageCount, offset, computedEvents, directEvents, statuses, statusMap;
			if (!size) return { size: size };
			pageCount = ceil(size / itemsPerPage);
			if (query.page > pageCount) return { size: size };

			// Pagination
			offset = (query.page - 1) * itemsPerPage;
			arr = slice.call(arr, offset, offset + itemsPerPage);
			if (bpListComputedProps) {
				computedEvents = deferred.map(arr, function (data) {
					var objId = data.id;
					return deferred.map(bpListComputedProps, function (keyPath) {
						return mano.dbDriver.getComputed(objId + '/' + keyPath)(function (data) {
							if (isArray(data.value)) {
								return data.value.map(function (data) {
									var key = data.key ? '*' + data.key : '';
									return data.stamp + '.' + objId + '/' + keyPath + key + '.' + data.value;
								});
							}
							return data.stamp + '.' + objId + '/' + keyPath + '.' + data.value;
						});
					});
				});
			} else {
				computedEvents = [];
			}
			directEvents = deferred.map(arr, function (data) {
				return mano.dbDriver.getObject(data.id, { keyPaths: bpListProps })(function (datas) {
					return datas.map(function (data) {
						return data.data.stamp + '.' + data.id + '.' + data.data.value;
					});
				});
			});
			if (!query.status) {
				statusMap = create(null);
				statuses = deferred.map(arr, function (data) {
					return mano.dbDriver.getComputed(data.id + '/' + statusIndexName)
						.aside(function (record) {
							statusMap[data.id] = record ? unserializeValue(record.value) : null;
						});
				})(statusMap);
			}
			return deferred(directEvents, computedEvents, statuses)
				.spread(function (directEvents, computedEvents, statusMap) {
					return {
						view: arr.map(function (data) { return data.stamp + '.' + data.id; }).join('\n'),
						size: size,
						data: flatten.call([directEvents, computedEvents]),
						statusMap: statusMap
					};
				});
		});
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		tableQueryHandler: tableQueryHandler,
		getTableData: getTableData,
		businessProcessQueryHandler: businessProcessQueryHandler,
		roleName: roleName,
		assigneePath: conf.assigneePath
	};
};

module.exports = exports = function (mainConf/*, options */) {
	var resolveHandler, options, mapResolver;
	options = Object(arguments[1]);
	if (isArray(mainConf)) {
		resolveHandler = (function () {
			var map = mainConf.reduce(function (map, conf) {
				map[conf.roleName] = initializeHandler(conf);
				return map;
			}, create(null));
			if (options.resolveConf && (typeof options.resolveConf === 'function')) {
				mapResolver = function (req) {
					return deferred(map[options.resolveConf(req)]);
				};
			} else {
				mapResolver = function (req) {
					return roleNameMap.get(req.$user)(function (roleName) {
						var handler;
						if (roleName) {
							roleName = unserializeValue(roleName);
							roleName = uncapitalize.call(roleName.slice('official'.length));
							handler = map[roleName];
						}
						if (!handler) {
							throw new Error("Cannot resolve conf for role name: " +  stringify(roleName));
						}
						return handler;
					});
				};
			}
			return mapResolver;
		}());
	} else {
		resolveHandler = constant(deferred(initializeHandler(mainConf)));
	}
	return {
		'get-business-processes-view': function (query) {
			var userId = this.req.$user;
			return resolveHandler(this.req)(function (handler) {
				// Get snapshot of business processes table page
				return handler.tableQueryHandler.resolve(query)(function (query) {
					if (handler.assigneePath) {
						query.assignedTo = userId;
					}
					return handler.getTableData(query);
				});
			});
		},
		'get-business-process-data': function (query) {
			return resolveHandler(this.req)(function (handler) {
				// Get full data of one of the business processeses
				return handler.businessProcessQueryHandler.resolve(query)(function (query) {
					var recordId;
					if (!query.id) return { passed: false };
					recordId = this.req.$user + '/recentlyVisited/businessProcesses/' +
						handler.roleName + '*7' + query.id;
					return mano.dbDriver.store(recordId, '11')({ passed: true });
				}.bind(this));
			}.bind(this));
		}
	};
};

exports.getIndexMeta = function (query, conf) {
	var meta;
	if (query.status) {
		if (conf.resolveCollectionMeta) {
			meta = conf.resolveCollectionMeta(query.status);
			return { name: meta.name, value: serializeValue(meta.value) };
		}
		return { name: conf.statusIndexName, value: serializeValue(query.status) };
	}
	return { name: conf.allIndexName, value: '11' };
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, {
	name: 'search',
	ensure: function (value) {
		if (!value) return;
		if (value.toLowerCase() !== value) throw new Error("Unexpected search value");
		if (hasBadWs(value)) throw new Error("Unexpected search value");
		if (value !== uniq.call(value.split(/\s/)).join(' ')) {
			throw new Error("Unexpected search value");
		}
		return value;
	}
}, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<commit_msg>#1096 cleanup<commit_after>// Official roles GET controllers

'use strict';

var aFrom               = require('es5-ext/array/from')
  , flatten             = require('es5-ext/array/#/flatten')
  , remove              = require('es5-ext/array/#/remove')
  , uniq                = require('es5-ext/array/#/uniq')
  , constant            = require('es5-ext/function/constant')
  , isNaturalNumber     = require('es5-ext/number/is-natural')
  , toNaturalNumber     = require('es5-ext/number/to-pos-integer')
  , normalizeOptions    = require('es5-ext/object/normalize-options')
  , toArray             = require('es5-ext/object/to-array')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , includes            = require('es5-ext/string/#/contains')
  , uncapitalize        = require('es5-ext/string/#/uncapitalize')
  , d                   = require('d')
  , ensureSet           = require('es6-set/valid-set')
  , deferred            = require('deferred')
  , memoize             = require('memoizee')
  , serializeValue      = require('dbjs/_setup/serialize/value')
  , unserializeValue    = require('dbjs/_setup/unserialize/value')
  , ObservableSet       = require('observable-set/primitive')
  , mano                = require('mano')
  , roleNameMap         = require('mano/lib/server/user-role-name-map')
  , QueryHandler        = require('../../utils/query-handler')
  , defaultItemsPerPage = require('../../conf/objects-list-items-per-page')
  , getDbSet            = require('../utils/get-db-set')
  , getDbArray          = require('../utils/get-db-array')
  , getIndexMap         = require('../utils/get-db-sort-index-map')

  , hasBadWs = RegExp.prototype.test.bind(/\s{2,}/)
  , compareStamps = function (a, b) { return a.stamp - b.stamp; }
  , isArray = Array.isArray, slice = Array.prototype.slice, push = Array.prototype.push
  , ceil = Math.ceil, create = Object.create
  , defineProperty = Object.defineProperty, stringify = JSON.stringify;

var compareIndexMeta = function (meta1, meta2) {
	return meta1.name.localeCompare(meta2.name) || meta1.value.localeCompare(meta2.value);
};

// Business processes table query handler
var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

// Single business process full data query handler
var getBusinessProcessQueryHandler = function (indexName) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				if (!value) throw new Error("Missing id");
				return mano.dbDriver.getComputed(value + '/' + indexName)(function (data) {
					if (!data || (data.value !== '11')) return null;
					return value;
				});
			}
		}
	]);
};

var getFilteredSet = memoize(function (baseSet, filterString) {
	var set = new ObservableSet(), baseSetListener, indexListener
	  , def = deferred(), count = 0, isInitialized = false;
	var filter = function (ownerId, data) {
		var value = unserializeValue(data.value);
		if (value && includes.call(value, filterString)) set.add(ownerId);
		else set.delete(ownerId);
	};
	var findAndFilter = function (ownerId) {
		return mano.dbDriver.getComputed(ownerId + '/searchString').aside(function (data) {
			if (!baseSet.has(ownerId)) return;
			if (!data) return;
			filter(ownerId, data);
		});
	};
	baseSet.on('change', baseSetListener = function (event) {
		if (event.type === 'add') findAndFilter(event.value).done();
		else set.delete(event.value);
	});
	mano.dbDriver.on('key:searchString', indexListener = function (event) {
		if (!baseSet.has(event.ownerId)) return;
		filter(event.ownerId, event.data);
	});
	baseSet.forEach(function (ownerId) {
		++count;
		findAndFilter(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(set);
		});
	});
	isInitialized = true;
	if (!count) def.resolve(set);
	defineProperty(set, '_dispose', d(function () {
		baseSet.off(baseSetListener);
		mano.dbDriver.off('key:searchString', indexListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (set) { set._dispose(); } });

var getDbArrayLru = memoize(function (set, sortIndexName) {
	var arr = [], itemsMap = getIndexMap(sortIndexName)
	  , count = 0, isInitialized = false, def = deferred(), setListener, itemsListener;
	var add = function (ownerId) {
		return deferred(itemsMap[ownerId] || mano.dbDriver.getComputed(ownerId + '/' + sortIndexName))
			.aside(function (data) {
				if (!set.has(ownerId)) return;
				if (!itemsMap[ownerId]) itemsMap[ownerId] = { id: ownerId, stamp: data.stamp };
				arr.push(itemsMap[ownerId]);
				if (def.resolved) arr.sort(compareStamps);
			});
	};
	set.on('change', setListener = function (event) {
		if (event.type === 'add') add(event.value).done();
		else remove.call(arr, itemsMap[event.value]);
	});
	itemsMap.on('update', itemsListener = function (event) {
		if (!set.has(event.ownerId)) return;
		if (def.resolved) arr.sort(compareStamps);
	});
	set.forEach(function (ownerId) {
		++count;
		add(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(arr.sort(compareStamps));
		});
	});
	isInitialized = true;
	if (!count) def.resolve(arr.sort(compareStamps));
	defineProperty(set, '_dispose', d(function () {
		set.off(setListener);
		itemsMap.off(itemsListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (arr) { arr._dispose(); } });

var initializeHandler = function (conf) {
	conf = normalizeOptions(ensureObject(conf));
	var roleName = ensureString(conf.roleName)
	  , statusIndexName = ensureString(conf.statusIndexName)
	  , allIndexName = ensureString(conf.allIndexName)
	  , bpListProps = ensureSet(conf.listProperties)
	  , bpListComputedProps = conf.listComputedProperties && aFrom(conf.listComputedProperties)
	  , tableQueryHandler = getTableQueryHandler(ensureObject(conf.statusMap))
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(conf.allIndexName)
	  , itemsPerPage = toNaturalNumber(conf.itemsPerPage) || defaultItemsPerPage
	  , indexes;

	if (conf.resolveCollectionMeta != null) ensureCallable(conf.resolveCollectionMeta);

	if (bpListComputedProps) {
		indexes = [];
		deferred.map(bpListComputedProps, function (keyPath) {
			return mano.dbDriver.indexKeyPath(keyPath)(function (map) {
				indexes.push({ keyPath: keyPath, map: map });
			});
		});
	}

	var getTableData = memoize(function (query) {
		var indexMeta = exports.getIndexMeta(query, conf), promise;
		if (isArray(indexMeta)) {
			promise = deferred.map(indexMeta.sort(compareIndexMeta), function (indexMeta) {
				return getDbSet('computed', indexMeta.name, indexMeta.value);
			})(function (sets) {
				return aFrom(sets).reduce(function (set1, set2) { return set1.and(set2); });
			});
		} else {
			promise = getDbSet('computed', indexMeta.name, indexMeta.value);
		}
		if (query.assignedTo) {
			promise = promise.then(function (baseSet) {
				return getDbSet('direct', conf.assigneePath, '7' + query.assignedTo)(function (set) {
					return baseSet.and(set);
				});
			});
		}
		return promise(function (baseSet) {
			if (!query.search) return getDbArray(baseSet, 'computed', allIndexName);
			return deferred.map(query.search.split(/\s+/).sort(), function (value) {
				return getFilteredSet(baseSet, value)(function (set) {
					return getDbArrayLru(set, allIndexName);
				});
			})(function (arrays) {
				if (arrays.length === 1) return arrays[0];
				return uniq.call(arrays.reduce(function (current, next, index) {
					if (index === 1) current = aFrom(current);
					push.apply(current, next);
					return current;
				})).sort(compareStamps);
			});
		})(function (arr) {
			var size = arr.length, pageCount, offset, computedEvents, directEvents, statuses, statusMap;
			if (!size) return { size: size };
			pageCount = ceil(size / itemsPerPage);
			if (query.page > pageCount) return { size: size };

			// Pagination
			offset = (query.page - 1) * itemsPerPage;
			arr = slice.call(arr, offset, offset + itemsPerPage);
			if (bpListComputedProps) {
				computedEvents = deferred.map(arr, function (data) {
					var objId = data.id;
					return deferred.map(bpListComputedProps, function (keyPath) {
						return mano.dbDriver.getComputed(objId + '/' + keyPath)(function (data) {
							if (isArray(data.value)) {
								return data.value.map(function (data) {
									var key = data.key ? '*' + data.key : '';
									return data.stamp + '.' + objId + '/' + keyPath + key + '.' + data.value;
								});
							}
							return data.stamp + '.' + objId + '/' + keyPath + '.' + data.value;
						});
					});
				});
			} else {
				computedEvents = [];
			}
			directEvents = deferred.map(arr, function (data) {
				return mano.dbDriver.getObject(data.id, { keyPaths: bpListProps })(function (datas) {
					return datas.map(function (data) {
						return data.data.stamp + '.' + data.id + '.' + data.data.value;
					});
				});
			});
			if (!query.status) {
				statusMap = create(null);
				statuses = deferred.map(arr, function (data) {
					return mano.dbDriver.getComputed(data.id + '/' + statusIndexName)
						.aside(function (record) {
							statusMap[data.id] = record ? unserializeValue(record.value) : null;
						});
				})(statusMap);
			}
			return deferred(directEvents, computedEvents, statuses)
				.spread(function (directEvents, computedEvents, statusMap) {
					return {
						view: arr.map(function (data) { return data.stamp + '.' + data.id; }).join('\n'),
						size: size,
						data: flatten.call([directEvents, computedEvents]),
						statusMap: statusMap
					};
				});
		});
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		tableQueryHandler: tableQueryHandler,
		getTableData: getTableData,
		businessProcessQueryHandler: businessProcessQueryHandler,
		roleName: roleName,
		assigneePath: conf.assigneePath
	};
};

module.exports = exports = function (mainConf/*, options */) {
	var resolveHandler, options, roleNameResolve;
	options = Object(arguments[1]);
	if (isArray(mainConf)) {
		resolveHandler = (function () {
			var map = mainConf.reduce(function (map, conf) {
				map[conf.roleName] = initializeHandler(conf);
				return map;
			}, create(null));
			roleNameResolve = function (req) {
				if (options.resolveConf && (typeof options.resolveConf === 'function')) {
					return deferred(options.resolveConf(req));
				}
				return roleNameMap.get(req.$user)(function (roleName) {
					roleName = unserializeValue(roleName);
					return uncapitalize.call(roleName.slice('official'.length));
				});
			};
			return function (req) {
				return roleNameResolve(req)(function (roleName) {
					var handler;
					if (roleName) {
						handler = map[roleName];
					}
					if (!handler) {
						throw new Error("Cannot resolve conf for role name: " + stringify(roleName));
					}
					return handler;
				});
			};
		}());
	} else {
		resolveHandler = constant(deferred(initializeHandler(mainConf)));
	}
	return {
		'get-business-processes-view': function (query) {
			var userId = this.req.$user;
			return resolveHandler(this.req)(function (handler) {
				// Get snapshot of business processes table page
				return handler.tableQueryHandler.resolve(query)(function (query) {
					if (handler.assigneePath) {
						query.assignedTo = userId;
					}
					return handler.getTableData(query);
				});
			});
		},
		'get-business-process-data': function (query) {
			return resolveHandler(this.req)(function (handler) {
				// Get full data of one of the business processeses
				return handler.businessProcessQueryHandler.resolve(query)(function (query) {
					var recordId;
					if (!query.id) return { passed: false };
					recordId = this.req.$user + '/recentlyVisited/businessProcesses/' +
						handler.roleName + '*7' + query.id;
					return mano.dbDriver.store(recordId, '11')({ passed: true });
				}.bind(this));
			}.bind(this));
		}
	};
};

exports.getIndexMeta = function (query, conf) {
	var meta;
	if (query.status) {
		if (conf.resolveCollectionMeta) {
			meta = conf.resolveCollectionMeta(query.status);
			return { name: meta.name, value: serializeValue(meta.value) };
		}
		return { name: conf.statusIndexName, value: serializeValue(query.status) };
	}
	return { name: conf.allIndexName, value: '11' };
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, {
	name: 'search',
	ensure: function (value) {
		if (!value) return;
		if (value.toLowerCase() !== value) throw new Error("Unexpected search value");
		if (hasBadWs(value)) throw new Error("Unexpected search value");
		if (value !== uniq.call(value.split(/\s/)).join(' ')) {
			throw new Error("Unexpected search value");
		}
		return value;
	}
}, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<|endoftext|>


<commit_before><commit_msg>adds size and redraw functions<commit_after>(function(){
// set up the timeout variable
var t;
// setup the sizing function,
// with an argument that tells the chart to animate or not
function size(animate){
    // If we are resizing, we don't want the charts drawing on every resize event.
    // This clears the timeout so that we only run the sizing function
    // when we are done resizing the window
    clearTimeout(t);
    // This will reset the timeout right after clearing it.
    t = setTimeout(function(){
        $("canvas").each(function(i,el){
            // Set the canvas element's height and width to it's parent's height and width.
            // The parent element is the div.canvas-container
            $(el).attr({
                "width":$(el).parent().width(),
                "height":$(el).parent().outerHeight()
            });
        });
        // kickoff the redraw function, which builds all of the charts.
        redraw(animate);

        // loop through the widgets and find the tallest one, and set all of them to that height.
        var m = 0;
        // we have to remove any inline height setting first so that we get the automatic height.
        $(".widget").height("");
        $(".widget").each(function(i,el){ m = Math.max(m,$(el).height()); });
        $(".widget").height(m);

    }, 100); // the timeout should run after 100 milliseconds
}
$(window).on('resize', size);
function redraw(animation){
    var options = {};
    if (!animation){
        options.animation = false;
    } else {
        options.animation = true;
    }
    // ....
        // the rest of our chart drawing will happen here
    // ....
}
size(); // this kicks off the first drawing; note that the first call to size will animate the charts in.
});<|endoftext|>


<commit_before>var config = require('../config');
var fs = require('fs');
var express = require('express');
var async = require('async');
var _ = require('lodash');

var router = express.Router();

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

require('../models/search.js');
require('../models/response.js');

// TO DO: apis.json file
router.post('/', function(req, res, next) {

  var startTime = new Date().getTime();
  var response = new Response();

  // ensure proper content type
  if (req.headers['content-type'] !== 'application/json') {
    var err = new Error();
    err.status = 400;
    err.error = "Invalid content type";
    err.message = "Valid content type is 'application/json'";
    next(err);
  } else {

    if (!req.body.search) {
      var err = new Error();
      err.status = 400;
      err.error = "A search attribute was not found in the body";
      err.message = "A search key/value must be passed in body (ex. {'search':'ibuprofen'})";
      next(err);
    } else {

      var search = new Search();

      search.search = req.body.search;

      var incrementCount = function(search, db, callback) {
        var collection = db.collection('search');
        collection.findAndModify({search: search.search.toLowerCase()}, {}, {$inc: {count:1}}, {upsert:true}, function(err, object) {
          callback(object)
        });
      };

      MongoClient.connect(mongo_url, function(err, db) {
        incrementCount(search, db, function(searchDocument) {
          var endTime = new Date().getTime();
          response.meta.execution_time = String ((endTime - startTime) / 1000) + 's'  ;

          // The find and upsert capability starts the first count at 0, so response is incremented by 1 before responding to API consumer
          if (searchDocument === null || !searchDocument.value.count) {
            response.data.search = search.search;
            response.data.count = 1;

          } else {
            response.data.search = search.search;
            response.data.count = searchDocument.value.count + 1;
          }

          db.close();
          res.json(response);

        });
      });

    }

  }

});

router.get('/', function(req, res, next) {

    var response = new Response();
    var startTime = new Date().getTime();

    if (!req.query.limit) {req.query.limit = 25;} else {req.query.limit = parseInt(req.query.limit);}

    if (req.query.limit < 1) {
      req.query.limit = 1;
    }

    if (req.query.limit > 200) {
      req.query.limit = 200;
    }

    if (!req.query.offset) {
      req.query.offset = 0;
    } else {
      req.query.offset = parseInt(req.query.offset);
    }

    var findAll = function(db, callback) {

      var collection = db.collection('search');

      var cursor = collection.find({ }).sort({count:-1});

      async.series([

          // Get count from cursor
          function(callback){
            cursor.count(function(err, count) {
              response.meta.limit = req.query.limit;
              response.meta.offset = req.query.offset;
              response.meta.total_count = count;

            });
            callback(null);
          },

          // Get results from curor
          function(callback){
            cursor.limit(req.query.limit);
            cursor.skip(req.query.offset);

            cursor.toArray(function(err, result) {
              response.data = result;
              callback(null);
            });
          }

        ], function(err){

          db.close();

          if (!response.data) {
            var endTime = new Date().getTime();
            response.meta.execution_time = String ((endTime - startTime) / 1000) + 's'  ;

            res.status(404);
            res.json(response);
            db.close();

          } else {

           // ... then remove the _id keys from the results and send response back
            _.forEach(response.data, function(v, k) {
              delete response.data[k]._id;
            })

            var endTime = new Date().getTime();
            response.meta.execution_time = String ((endTime - startTime) / 1000) + 's'  ;

            res.json(response);
            db.close();

          }

      });

    }

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

      });
    });

});

module.exports = router;
<commit_msg>Adding conditional check for null error on response<commit_after>var config = require('../config');
var fs = require('fs');
var express = require('express');
var async = require('async');
var _ = require('lodash');

var router = express.Router();

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

require('../models/search.js');
require('../models/response.js');

// TO DO: apis.json file
router.post('/', function(req, res, next) {

  var startTime = new Date().getTime();
  var response = new Response();

  // ensure proper content type
  if (req.headers['content-type'] !== 'application/json') {
    var err = new Error();
    err.status = 400;
    err.error = "Invalid content type";
    err.message = "Valid content type is 'application/json'";
    next(err);
  } else {

    if (!req.body.search) {
      var err = new Error();
      err.status = 400;
      err.error = "A search attribute was not found in the body";
      err.message = "A search key/value must be passed in body (ex. {'search':'ibuprofen'})";
      next(err);
    } else {

      var search = new Search();

      search.search = req.body.search;

      var incrementCount = function(search, db, callback) {
        var collection = db.collection('search');
        collection.findAndModify({search: search.search.toLowerCase()}, {}, {$inc: {count:1}}, {upsert:true}, function(err, object) {
          callback(object)
        });
      };

      MongoClient.connect(mongo_url, function(err, db) {
        incrementCount(search, db, function(searchDocument) {
          var endTime = new Date().getTime();
          response.meta.execution_time = String ((endTime - startTime) / 1000) + 's'  ;

          // The find and upsert capability starts the first count at 0, so
          // response is incremented by 1 before responding to API consumer
          if (searchDocument === null ||
+             searchDocument.value === null ||
+             !searchDocument.value.count) {
            response.data.search = search.search;
            response.data.count = 1;

          } else {
            response.data.search = search.search;
            response.data.count = searchDocument.value.count + 1;
          }

          db.close();
          res.json(response);

        });
      });

    }

  }

});

router.get('/', function(req, res, next) {

    var response = new Response();
    var startTime = new Date().getTime();

    if (!req.query.limit) {req.query.limit = 25;} else {req.query.limit = parseInt(req.query.limit);}

    if (req.query.limit < 1) {
      req.query.limit = 1;
    }

    if (req.query.limit > 200) {
      req.query.limit = 200;
    }

    if (!req.query.offset) {
      req.query.offset = 0;
    } else {
      req.query.offset = parseInt(req.query.offset);
    }

    var findAll = function(db, callback) {

      var collection = db.collection('search');

      var cursor = collection.find({ }).sort({count:-1});

      async.series([

          // Get count from cursor
          function(callback){
            cursor.count(function(err, count) {
              response.meta.limit = req.query.limit;
              response.meta.offset = req.query.offset;
              response.meta.total_count = count;

            });
            callback(null);
          },

          // Get results from curor
          function(callback){
            cursor.limit(req.query.limit);
            cursor.skip(req.query.offset);

            cursor.toArray(function(err, result) {
              response.data = result;
              callback(null);
            });
          }

        ], function(err){

          db.close();

          if (!response.data) {
            var endTime = new Date().getTime();
            response.meta.execution_time = String ((endTime - startTime) / 1000) + 's'  ;

            res.status(404);
            res.json(response);
            db.close();

          } else {

           // ... then remove the _id keys from the results and send response back
            _.forEach(response.data, function(v, k) {
              delete response.data[k]._id;
            })

            var endTime = new Date().getTime();
            response.meta.execution_time = String ((endTime - startTime) / 1000) + 's'  ;

            res.json(response);
            db.close();

          }

      });

    }

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

      });
    });

});

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

function repo_init(){
    core_repo_init({
      'globals': {
        'keyclick_ready': 1,
        'upgrades': {
          'manual': {
            'bonus': 1,
            'cost': 2,
            'multiplier': 2,
            'type': 'per-click',
          },
          'script': {
            'bonus': 1,
            'cost': 20,
            'multiplier': 4,
            'type': 'per-second',
          },
          'employee': {
            'bonus': 2,
            'cost': 50,
            'multiplier': 8,
            'type': 'per-second',
          },
          'server': {
            'bonus': 3,
            'cost': 100,
            'multiplier': 16,
            'type': 'per-second',
          },
          'cluster': {
            'bonus': 4,
            'cost': 200,
            'multiplier': 32,
            'type': 'per-second',
          },
          'investor': {
            'bonus': 1,
            'cost': 20,
            'multiplier': 64,
            'type': 'multiplier',
          },
        },
      },
      'info-events': {
        'click-button': {
          'todo': click_button,
        },
      },
      'storage': {
        'clicks': 0,
        'clicks-multiplier': 100,
        'clicks-per-click': 1,
        'clicks-per-click-multiplied': 1,
        'clicks-per-second': 0,
        'clicks-per-second-multiplied': 0,
      },
      'title': 'Click.htm',
    });

    var multiplier = (core_storage_data['clicks-multiplier'] / 100);
    core_storage_data['clicks-per-click-multiplied'] = Math.floor(core_storage_data['clicks-per-click'] * multiplier);
    core_storage_data['clicks-per-second-multiplied'] = Math.floor(core_storage_data['clicks-per-second'] * multiplier);

    for(var id in upgrades){
        var upgrade = id[0].toUpperCase() + id.substring(1);

        document.getElementById('upgrades').innerHTML +=
          '0'
          + ' <input id=' + id + ' type=button value=' + upgrade + '>'
          + ' ' + (upgrades[id]['cost'] + core_storage_data['upgrade-' + id + '-cost']) +'
';
    }

    for(id in upgrades){
        var storage = {};

        storage['upgrade-' + id] = 0;
        storage['upgrade-' + id + '-cost'] = upgrades[id]['cost'];

        core_storage_add({
          'storage': storage,
        });

        document.getElementById(id).onclick = function(){
            purchase(
              this.id,
              core_storage_data['upgrade-' + this.id + '-cost'],
              'clicks-' + upgrades[this.id]['type']
            );
        };
    }

    window.setTimeout(
      second,
      1000
    );

    core_storage_update();
}
<commit_msg>changed info-events to events<commit_after>'use strict';

function repo_init(){
    core_repo_init({
      'events': {
        'click-button': {
          'onclick': click_button,
        },
      },
      'globals': {
        'keyclick_ready': 1,
        'upgrades': {
          'manual': {
            'bonus': 1,
            'cost': 2,
            'multiplier': 2,
            'type': 'per-click',
          },
          'script': {
            'bonus': 1,
            'cost': 20,
            'multiplier': 4,
            'type': 'per-second',
          },
          'employee': {
            'bonus': 2,
            'cost': 50,
            'multiplier': 8,
            'type': 'per-second',
          },
          'server': {
            'bonus': 3,
            'cost': 100,
            'multiplier': 16,
            'type': 'per-second',
          },
          'cluster': {
            'bonus': 4,
            'cost': 200,
            'multiplier': 32,
            'type': 'per-second',
          },
          'investor': {
            'bonus': 1,
            'cost': 20,
            'multiplier': 64,
            'type': 'multiplier',
          },
        },
      },
      'storage': {
        'clicks': 0,
        'clicks-multiplier': 100,
        'clicks-per-click': 1,
        'clicks-per-click-multiplied': 1,
        'clicks-per-second': 0,
        'clicks-per-second-multiplied': 0,
      },
      'title': 'Click.htm',
    });

    var multiplier = (core_storage_data['clicks-multiplier'] / 100);
    core_storage_data['clicks-per-click-multiplied'] = Math.floor(core_storage_data['clicks-per-click'] * multiplier);
    core_storage_data['clicks-per-second-multiplied'] = Math.floor(core_storage_data['clicks-per-second'] * multiplier);

    for(var id in upgrades){
        var upgrade = id[0].toUpperCase() + id.substring(1);

        document.getElementById('upgrades').innerHTML +=
          '0'
          + ' <input id=' + id + ' type=button value=' + upgrade + '>'
          + ' ' + (upgrades[id]['cost'] + core_storage_data['upgrade-' + id + '-cost']) +'
';
    }

    for(id in upgrades){
        var storage = {};

        storage['upgrade-' + id] = 0;
        storage['upgrade-' + id + '-cost'] = upgrades[id]['cost'];

        core_storage_add({
          'storage': storage,
        });

        document.getElementById(id).onclick = function(){
            purchase(
              this.id,
              core_storage_data['upgrade-' + this.id + '-cost'],
              'clicks-' + upgrades[this.id]['type']
            );
        };
    }

    window.setTimeout(
      second,
      1000
    );

    core_storage_update();
}
<|endoftext|>


<commit_before>// We want to be able to access Lichess' variables--specifically _ld_--so we
// inject a