{"version":3,"sources":["jsdelivr-header.js","/npm/botpress-analytics@2.2.7/bin/webpack:/webpack/bootstrap 01e033689e6f98b188e1","webpack:///src/index.js","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"botpress-version-manager\"","webpack:///src/analytics.js","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"fs\"","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"path\"","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"eventemitter2\"","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"lodash\"","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"moment\"","webpack:///src/stats.js","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"bluebird\"","/npm/botpress-analytics@2.2.7/bin/webpack:/external \"botpress\"","webpack:///src/custom_analytics.js","webpack:///src/db.js"],"names":[],"mappings":"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","file":"/npm/botpress-analytics@2.2.7/bin/node.bundle.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/botpress-analytics@2.2.7/bin/node.bundle.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n",null,"const checkVersion = require('botpress-version-manager')\n\nconst Analytics = require('./analytics')\nconst CustomAnalytics = require('./custom_analytics')\nconst DB = require('./db')\nconst _ = require('lodash')\n\nlet analytics = null\nlet db = null\n\nconst interactionsToTrack = ['message', 'text', 'button', 'template', 'quick_reply', 'postback']\n\nconst incomingMiddleware = (event, next) => {\n  if (!_.includes(interactionsToTrack, event.type)) {\n    return next()\n  }\n\n  if (event.user) {\n    // Asynchronously save the interaction (non-blocking)\n    db &&\n      db\n        .saveIncoming(event)\n        .then()\n        .catch(() => {\n          event.bp && event.bp.logger.debug('[Analytics] Could not save incoming interaction for ' + event.platform)\n        })\n  }\n\n  next()\n}\n\nconst outgoingMiddleware = (event, next) => {\n  if (!_.includes(interactionsToTrack, event.type)) {\n    return next()\n  }\n\n  // Asynchronously save the interaction (non-blocking)\n  db &&\n    db\n      .saveOutgoing(event)\n      .then()\n      .catch(() => {\n        event.bp && event.bp.logger.debug('[Analytics] Could not save outgoing interaction for ' + event.platform)\n      })\n\n  next()\n}\n\nmodule.exports = {\n  init: function(bp) {\n    checkVersion(bp, __dirname)\n\n    bp.middlewares.register({\n      name: 'analytics.incoming',\n      module: 'botpress-analytics',\n      type: 'incoming',\n      handler: incomingMiddleware,\n      order: 5,\n      description: 'Tracks incoming messages for Analytics purposes'\n    })\n\n    bp.middlewares.register({\n      name: 'analytics.outgoing',\n      module: 'botpress-analytics',\n      type: 'outgoing',\n      handler: outgoingMiddleware,\n      description: 'Tracks outgoing messages for Analytics purposes'\n    })\n\n    bp.analytics = {\n      custom: CustomAnalytics({ bp })\n    }\n\n    bp.db.get().then(knex => {\n      db = DB(knex, bp)\n      return db.initializeDb().then(() => (analytics = new Analytics(bp, knex)))\n    })\n  },\n\n  ready: function(bp) {\n    bp.getRouter('botpress-analytics').get('/graphs', (req, res, next) => {\n      res.send(analytics.getChartsGraphData())\n    })\n\n    bp.getRouter('botpress-analytics').get('/metadata', (req, res, next) => {\n      analytics.getAnalyticsMetadata().then(metadata => res.send(metadata))\n    })\n\n    bp.getRouter('botpress-analytics').get('/custom_metrics', async (req, res, next) => {\n      const metrics = await bp.analytics.custom.getAll(req.query.from, req.query.to)\n      res.send(metrics)\n    })\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.js",null,"const fs = require('fs')\nconst path = require('path')\nconst EventEmitter = require('eventemitter2');\nconst _ = require('lodash')\nconst moment = require('moment')\n\nconst Stats = require('./stats')\n\nconst createEmptyFileIfDoesntExist = (file) => {\n  if(!fs.existsSync(file)) {\n    fs.writeFileSync(file, '{}')\n  }\n}\n\nconst loadDataFromFile = (file) => {\n  if(!fs.existsSync(file)){\n    console.log(\"Analytics file (\" + file + \") doesn\\'t exist.\")\n  }\n  return JSON.parse(fs.readFileSync(file, \"utf-8\"))\n}\n\nclass Analytics {\n  constructor(bp, knex) {\n    if (!bp){\n      throw new Error('You need to specify botpress');\n    }\n\n    this.bp = bp\n    this.knex = knex\n    this.stats = Stats(knex)\n    this.chartsDatafile = path.join(bp.projectLocation, bp.botfile.dataDir, 'botpress-analytics.charts.json')\n\n    createEmptyFileIfDoesntExist(this.chartsDatafile)\n\n    let running = false\n    setInterval(() => {\n      this.stats.getLastRun()\n      .then(ts => {\n        const elasped = moment.duration(moment().diff(ts)).asMinutes()\n        if(!ts || elasped >= this.getUpdateFrequency()) {\n          this.updateData()\n        }\n      })\n    }, 5000)\n  }\n\n  getDBSize() {\n    if (this.bp.db.location !== 'postgres') {\n      return fs.statSync(this.bp.db.location)['size'] / 1000000.0 // in megabytes  \n    } else {\n      return 1\n    }\n  }\n\n  getAnalyticsMetadata() {\n    return this.stats.getLastRun()\n    .then(ts => {\n      const run = moment(new Date(ts))\n      const then = moment(new Date()).subtract(30, 'min')\n      const elasped = moment.duration(then.diff(run)).humanize()\n      return { lastUpdated: elasped, size: this.getDBSize() }\n    })\n  }\n\n  getUpdateFrequency() {\n    return this.getDBSize() < 5 ? 5 : 60\n  }\n\n  updateData() {\n    if(this.running) return\n    this.running = true\n    this.bp.logger.debug('botpress-analytics: recompiling analytics')\n    this.stats.getTotalUsers()\n    .then(data => this.savePartialData('totalUsers', data))\n    .then(() => this.stats.getDailyActiveUsers())\n    .then(data => this.savePartialData('activeUsers', data))\n    .then(() => this.stats.getDailyGender())\n    .then(data => this.savePartialData('genderUsage', data))\n    .then(() => this.stats.getInteractionRanges())\n    .then(data => this.savePartialData('interactionsRange', data))\n    .then(() => this.stats.getAverageInteractions())\n    .then(averageInteractions => {\n      this.stats.getNumberOfUsers()\n      .then(nbUsers => {\n        this.savePartialData('fictiveSpecificMetrics', {\n          numberOfInteractionInAverage: averageInteractions,\n          numberOfUsersToday: nbUsers.today,\n          numberOfUsersYesterday: nbUsers.yesterday,\n          numberOfUsersThisWeek: nbUsers.week\n        })\n      })\n    })\n    .then(() => this.stats.usersRetention())\n    .then(data => this.savePartialData('retentionHeatMap', data))\n    .then(() => this.stats.getBusyHours())\n    .then(data => this.savePartialData('busyHoursHeatMap', data))\n    .then(() => {\n      const data = this.getChartsGraphData()\n      this.bp.events.emit('data.send', data)\n      this.stats.setLastRun()\n    })\n    .then(() => this.running = false)\n  }\n\n  savePartialData(property, data) {\n    const chartsData = loadDataFromFile(this.chartsDatafile)\n    chartsData[property] = data\n    fs.writeFileSync(this.chartsDatafile, JSON.stringify(chartsData))\n  }\n\n  getChartsGraphData() {\n\n    const chartsData = loadDataFromFile(this.chartsDatafile)\n\n    if(_.isEmpty(chartsData)) {\n      return { loading: true, noData: true }\n    }\n\n    return {\n      loading: false,\n      noData: false,\n      totalUsersChartData: chartsData.totalUsers || [],\n      activeUsersChartData: chartsData.activeUsers || [],\n      genderUsageChartData: chartsData.genderUsage || [],\n      typicalConversationLengthInADay: chartsData.interactionsRange || [],\n      specificMetricsForLastDays: chartsData.fictiveSpecificMetrics || {},\n      retentionHeatMap: chartsData.retentionHeatMap || [],\n      busyHoursHeatMap: chartsData.busyHoursHeatMap || []\n    }\n  }\n}\n\nmodule.exports = Analytics;\n\n\n\n// WEBPACK FOOTER //\n// ./src/analytics.js",null,null,null,null,null,"import moment from 'moment'\nimport Promise from 'bluebird'\nimport _ from 'lodash'\nimport { DatabaseHelpers as helpers } from 'botpress'\n\nconst oneDayMs = 1000 * 60 * 60 * 24\n\nlet knex = null\n\nfunction rangeDates() {\n  return knex('users').select(knex.raw('max(created_on) as max, min(created_on) as min'))\n  .then().get(0).then((result) => {\n    if(!result.min || !result.max) {\n      return null\n    }\n\n    var range = moment(result.max).diff(moment(result.min), 'days')\n    var ranges = []\n    for(var i = 1; i <= 10; i++) {\n      ranges.push(parseInt(result.min + (range/10*i)))\n    }\n    const ret = { \n      min: result.min, \n      max: result.max, \n      format: null, \n      ranges: ranges\n    }\n    if(range < 360) {\n      ret.format = date => moment(date).format('MMM Do')\n    } else { // > 1year period\n      ret.format = date => moment(date).format('MMM YY')\n    }\n\n    return ret\n  })\n}\n\nfunction getTotalUsers() {\n  return rangeDates()\n  .then(dates => {\n    if (!dates) return\n    return knex('users').select(knex.raw('distinct platform'))\n    .then(platforms => {\n      \n      const statsBase = platforms.reduce((acc, curr) => {\n        acc[curr.platform] = 0\n        return acc\n      }, { total: 0 })\n\n      return knex('users')\n      .select(knex.raw('count(*) as count, max(created_on) as date, max(platform) as platform'))\n      .groupBy(knex.raw(\"date(created_on), platform\"))\n      .orderBy(knex.raw('date(created_on)'))\n      .then(rows => {\n        let total = 0\n        let totalPlatform = {}\n        const result = {}\n        const min = dates.format(moment(new Date(dates.min)).subtract(1, 'day'))\n        result[min] = Object.assign({}, statsBase)\n        rows.map(row => {\n          const date = dates.format(row.date)\n          if(!result[date]) {\n            result[date] = Object.assign({}, statsBase)\n          }\n          if(!totalPlatform[row.platform]) {\n            totalPlatform[row.platform] = 0\n          }\n          const count = parseInt(row.count)\n          totalPlatform[row.platform] += count\n          result[date].total = total += count\n          result[date][row.platform] = totalPlatform[row.platform]\n        })\n        const max = dates.format(moment(new Date(dates.max)).add(1, 'hour'))\n        result[max] = Object.assign({}, statsBase, { total: total }, totalPlatform)\n        return _.toPairs(result).map(([k, v]) => {\n          v.name = k\n          return v\n        })\n      })\n\n    })\n  })\n}\n\nfunction getLastDaysRange(nb) {\n  const nbOfDays = nb || 14\n\n  let ranges = _.times(nbOfDays, Number)\n  return ranges.map((n) => {\n    var date = moment(new Date()).subtract(n, 'days')\n    return {\n      date: date.format('MMM Do'),\n      start: date.startOf('day').toDate(), \n      end: date.endOf('day').toDate(),\n      day: date.format('l')\n    }\n  })\n}\n\nfunction getDailyActiveUsers() {\n  const ranges = _.reverse(getLastDaysRange())\n  return Promise.mapSeries(ranges, range => {\n    return knex('analytics_interactions')\n    .select(knex.raw('count(*) as count, platform'))\n    .join('users', 'users.id', 'analytics_interactions.user')\n    .where(helpers(knex).date.isBetween('ts', range.start, range.end))\n    .andWhere('direction', '=', 'in')\n    .groupBy(['user', 'platform'])\n    .then(results => {\n      return results.reduce(function(acc, curr) {\n        const count = parseInt(curr.count)\n        acc.total += count\n        acc[curr.platform] = count\n        return acc\n      }, { total: 0, name: range.date })\n    })\n  })\n}\n\nfunction getDailyGender() {\n  const ranges = _.reverse(getLastDaysRange())\n  return Promise.mapSeries(ranges, (range) => {\n    return knex('analytics_interactions')\n    .select(knex.raw('count(*) as count, gender'))\n    .join('users', 'users.id', 'analytics_interactions.user')\n    .where(helpers(knex).date.isBetween('ts', range.start, range.end))\n    .andWhere('direction', '=', 'in')\n    .groupBy(['user', 'gender'])\n    .then(results => {\n      return results.reduce(function(acc, curr) {\n        const count = parseInt(curr.count)\n        acc.total += count\n        acc[curr.gender] = count\n        return acc\n      }, { total: 0, name: range.date })\n    })\n  })\n}\n\nfunction getInteractionRanges() {\n  const ranges = getLastDaysRange()\n  return Promise.mapSeries(ranges, range => {\n\n    const inner = knex.from('analytics_interactions')\n      .where(helpers(knex).date.isBetween('ts', range.start, range.end))\n      .andWhere('direction', '=', 'in')\n      .groupBy('user')\n      .select(knex.raw('count(*) as c')).toString()\n\n    return knex.raw(`select\n      sum(r1) as s1,\n      sum(r2) as s2,\n      sum(r3) as s3,\n      sum(r4) as s4,\n      sum(r5) as s5,\n      sum(r6) as s6,\n      sum(r7) as s7,\n      sum(r8) as s8\n    from (select \n      (select count(*) as count where c between 0 and 1) as r1,\n      (select count(*) where c between 2 and 3) as r2,\n      (select count(*) where c between 4 and 5) as r3,\n      (select count(*) where c between 6 and 9) as r4,\n      (select count(*) where c between 10 and 14) as r5,\n      (select count(*) where c between 15 and 29) as r6,\n      (select count(*) where c between 30 and 50) as r7,\n      (select count(*) where c > 50) as r8\n        from (` + inner + `) as q1 ) as q2`)\n  }).then(rows => {\n    if (rows[0].rows) {\n      return rows.map(r => r.rows[0])\n    } else {\n      return rows.map(r => r[0])\n    }\n  })\n  .then(results => {\n    return results.reduce(function(acc, curr) {\n      return _.mapValues(acc, (a, k) => {\n        return a + (parseInt(curr[k]) || 0)\n      })\n    }, { s1: 0, s2: 0, s3: 0, s4: 0, s5: 0, s6: 0, s7: 0, s8: 0 })\n  })\n  .then(results => {\n    return [\n      { name: '[0-2]', count: results.s1 },\n      { name: '[2-4]', count: results.s2 },\n      { name: '[4-6]', count: results.s3 },\n      { name: '[6-10]', count: results.s4 },\n      { name: '[10-15]', count: results.s5 },\n      { name: '[15-30]', count: results.s6 },\n      { name: '[30-50]', count: results.s7 },\n      { name: '50+', count: results.s8 }\n    ]\n  })\n}\n\nfunction getAverageInteractions() {\n  // Average incoming interactions per user per day for the last 7 days\n  const lastWeek = moment(new Date()).subtract(7, 'days').toDate()\n  const now = helpers(knex).date.now()\n\n  return knex.select(knex.raw('avg(c) as count')).from(function() {\n    return this.from('analytics_interactions')\n    .where(helpers(knex).date.isBetween('ts', lastWeek, now))\n    .andWhere('direction', '=', 'in')\n    .groupBy(knex.raw(\"user, date(ts)\"))\n    .select(knex.raw('count(*) as c'))\n    .as('q1')\n  })\n  .then().get(0).then(result => {\n    return parseFloat(result.count) || 0.0\n  })\n}\n\nfunction getNumberOfUsers() {\n  // Get total number of active users for today, yesterday, this week\n\n  const ranges = [\n    {\n      label: 'today', \n      start: moment(new Date()).startOf('day').toDate(),\n      end: new Date() \n    },\n    {\n      label: 'yesterday',\n      start: moment(new Date()).subtract(1, 'days').startOf('day').toDate(),\n      end: moment(new Date()).subtract(1, 'days').endOf('day').toDate()\n    },\n    {\n      label: 'week',\n      start: moment(new Date()).startOf('week').toDate(),\n      end: moment(new Date()).endOf('week').toDate()\n    }\n  ]\n\n  return Promise.mapSeries(ranges, (range) => {\n    return knex.select(knex.raw('count(*) as count')).from(function() {\n      return this.from('analytics_interactions')\n      .where(helpers(knex).date.isBetween('ts', range.start, range.end))\n      .andWhere('direction', '=', 'in')\n      .groupBy('user')\n      .select(knex.raw(1))\n      .as('q1')\n    })\n    .then().get(0)\n    .then(result => ({ label: range.label, count: result.count }))\n  })\n  .then(results => {\n    return results.reduce((acc, curr) => {\n      acc[curr.label] = curr.count\n      return acc\n    }, {})\n  })\n}\n\nfunction usersRetention() {\n  // Get the last 7 days cohort of users along with the retention rate\n\n  let cohorts = _.times(8, n => Number(8 - n))\n  cohorts = cohorts.map(n => {\n    const day = moment().subtract(n, 'days')\n    return {\n      start: day.startOf('day').toDate(),\n      end: day.endOf('day').toDate(),\n      name: day.format('MMM Do'),\n      date: day\n    }\n  })\n\n  const result = {}\n\n  // For each days of the cohort\n  return Promise.mapSeries(cohorts, coo => {\n    // Compute the cohort size [i.e. how many new users on this day?]\n    return knex('users')\n      .where(helpers(knex).date.isBetween('created_on', coo.start, coo.end))\n      .select(knex.raw('count(*) as cohort_size'))\n      .then().get(0).then(({ cohort_size }) => {\n        cohort_size = parseFloat(cohort_size)\n\n        // Compute the next 7 days of the cohort\n        // and check how many users [from this cohort] spoke on or before this date\n        // A user is considered as retentioned if he interacted with the bot any day after he onboarded\n\n        const daysToAdd = _.times(7, n => n) // from 0 to 6\n        return Promise.mapSeries(daysToAdd, dta => {\n          const since = moment(coo.start).add(dta, 'days').endOf('day').toDate() // +x days\n\n          return knex.from(function() {\n            this.from('analytics_interactions')\n            .join('users', 'analytics_interactions.user', 'users.id')\n            // where he is a member a this cohort\n            .where(helpers(knex).date.isBetween('created_on', coo.start, coo.end))\n            // and where he interacted with the bot since onboard+X days\n            .andWhere(helpers(knex).date.isAfter('ts', since))\n            // and where the user spoke, not the bot\n            .andWhere('direction', '=', 'in')\n            .groupBy('users')\n            // returns the number of interactions per user\n            .select(knex.raw('count(*) as interaction_count'))\n            .as('q1')\n          }).select(knex.raw('count(*) as partial_retention')) // return the total number of users\n          .then().get(0).then(({ partial_retention }) => {\n            partial_retention = parseFloat(partial_retention)\n\n            // if the date is out of the cohort sample\n            if (moment(since).startOf('day').isSameOrAfter(moment().startOf('day'))) {\n              return null\n            }\n\n            return (partial_retention / cohort_size) || 0\n          })\n        }).then(retention => {\n          const mean = _.mean(_.filter(retention, v => v !== null))\n          result[coo.name] = [cohort_size, ...retention, mean]\n        })\n      })\n    })\n  .then(() => result)\n}\n\nfunction getBusyHours() {\n  const ranges = getLastDaysRange(7)\n  const result = {}\n\n  return Promise.mapSeries(ranges, range => {\n    // select count(*) as count, ts from interactions\n    // group by strftime('%H', ts/1000, 'unixepoch')\n    return knex('analytics_interactions')\n    .where(helpers(knex).date.isBetween('ts', range.start, range.end))\n    .select(knex.raw('count(*) as count, ' + helpers(knex).date.hourOfDay('ts').sql + ' as ts'))\n    .groupBy(helpers(knex).date.hourOfDay('ts'))\n    .then(rows => {\n      const row = []\n      _.times(24, () => row.push(0))\n      const biggest = rows.reduce((acc, curr) => {\n        return acc = curr.count > acc ? curr.count : acc\n      }, 0)\n      rows.map(x => {\n        row[parseInt(x.ts)] = Math.min(Number((x.count/biggest).toFixed(2)), 0.75)\n      })\n\n      result[range.date] = row\n    })\n  })\n  .then(() => result)\n}\n\nfunction getLastRun() {\n  return knex('analytics_runs').orderBy('ts', 'desc').limit(1)\n  .then().get(0).then(entry => {\n    return entry && moment(entry.ts)\n  })\n}\n\nfunction setLastRun() {\n  return knex('analytics_runs')\n  .insert({ ts: helpers(knex).date.now() })\n  .then(true)\n}\n\nmodule.exports = k => {\n  knex = k\n  return {\n    getTotalUsers: getTotalUsers,\n    getDailyActiveUsers: getDailyActiveUsers,\n    getDailyGender: getDailyGender,\n    getInteractionRanges: getInteractionRanges,\n    getAverageInteractions: getAverageInteractions,\n    getNumberOfUsers: getNumberOfUsers,\n    usersRetention: usersRetention,\n    getBusyHours: getBusyHours,\n    getLastRun: getLastRun,\n    setLastRun: setLastRun\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/stats.js",null,null,"import moment from 'moment'\nimport _ from 'lodash'\nimport Promise from 'bluebird'\n\nmodule.exports = ({ bp }) => {\n  const graphs = []\n\n  async function update(name, operation, value, racing = false) {\n    if (!_.isString(name)) {\n      throw new Error('Invalid name, expected a string')\n    }\n\n    const knex = await bp.db.get()\n\n    const today = moment().format('YYYY-MM-DD')\n    name = name.toLowerCase().trim()\n\n    if (!name.includes('~')) {\n      name += '~'\n    }\n\n    const result = await knex('analytics_custom')\n      .where('date', today)\n      .andWhere('name', name)\n      .update('count', operation)\n      .then()\n\n    if (result == 0 && !racing) {\n      await knex('analytics_custom')\n        .insert({\n          name: name,\n          date: today,\n          count: value\n        })\n        .catch(err => {\n          return update(name, operation, value, true)\n        })\n    }\n  }\n\n  async function increment(name, count = 1) {\n    if (!_.isNumber(count)) {\n      throw new Error('Invalid count increment, expected a valid number')\n    }\n\n    const countQuery = count < 0 ? 'count - ' + Math.abs(count) : 'count + ' + Math.abs(count)\n\n    const knex = await bp.db.get()\n\n    return update(name, knex.raw(countQuery), count)\n  }\n\n  async function decrement(name, count = 1) {\n    return increment(name, count * -1)\n  }\n\n  async function set(name, count = 1) {\n    return update(name, count, count)\n  }\n\n  //{ name, type, description, variables }\n  function addGraph(graph) {\n    if (!_.includes(['count', 'percent', 'piechart'], graph.type)) {\n      throw new Error('Unknown graph of type ' + graph.type)\n    }\n\n    graphs.push(graph)\n  }\n\n  const getters = {\n    count: async function(graph, from, to) {\n      const knex = await bp.db.get()\n\n      const variable = _.first(graph.variables)\n\n      const rows = await knex('analytics_custom')\n        .select(['date', knex.raw('sum(count) as count')])\n        .where('date', '>=', from)\n        .andWhere('date', '<=', to)\n        .andWhere('name', 'LIKE', variable + '~%')\n        .groupBy('date')\n        .then(rows => {\n          return rows.map(row => {\n            return Object.assign(row, { count: parseInt(row.count) })\n          })\n        })\n\n      return Object.assign({}, graph, { results: rows })\n    },\n\n    percent: async function(graph, from, to) {\n      const variable1 = _.first(graph.variables)\n      const variable2 = _.last(graph.variables)\n\n      const count1 = await getters.count({ variables: [variable1] }, from, to)\n      const count2 = await getters.count({ variables: [variable2] }, from, to)\n\n      const allDates = _.uniq([..._.map(count1.results, 'date'), ..._.map(count2.results, 'date')])\n\n      const rows = allDates.map(date => {\n        const n1 = _.find(count1.results, { date: date }) || { count: 0 }\n        const n2 = _.find(count2.results, { date: date }) || { count: 1 }\n\n        let percent = n1.count / n2.count\n\n        if (_.isFunction(graph.fn)) {\n          percent = graph.fn(n1.count, n2.count)\n        }\n\n        if (percent > 1) {\n          percent = 1\n        }\n\n        return { date: date, percent: percent }\n      })\n\n      return Object.assign({}, graph, { results: rows })\n    },\n\n    piechart: async function(graph, from, to) {\n      const knex = await bp.db.get()\n\n      const variable = _.first(graph.variables)\n\n      const rows = await knex('analytics_custom')\n        .select(['name', knex.raw('sum(count) as count')])\n        .where('date', '>=', from)\n        .andWhere('date', '<=', to)\n        .andWhere('name', 'LIKE', variable + '~%')\n        .groupBy('name')\n        .then(rows => {\n          return rows.map(row => {\n            const name = _.drop(row.name.split('~')).join('~')\n\n            return Object.assign(row, {\n              name: _.isEmpty(name) ? 'unknown' : name,\n              count: parseInt(row.count)\n            })\n          })\n        })\n\n      return Object.assign({}, graph, { results: rows })\n    }\n  }\n\n  async function getAll(from, to) {\n    return Promise.map(graphs, graph => getters[graph.type](graph, from, to))\n  }\n\n  return { increment, decrement, set, addGraph, getAll }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/custom_analytics.js","import Promise from 'bluebird'\nimport moment from 'moment'\nimport { DatabaseHelpers as helpers } from 'botpress'\nimport _ from 'lodash'\n\nlet knex = null\nlet bp = null\n\nfunction initializeDb() {\n  if (!knex) {\n    throw new Error('you must initialize the database before')\n  }\n\n  return helpers(knex).createTableIfNotExists('analytics_interactions', function (table) {\n    table.increments('id').primary()\n    table.timestamp('ts')\n    table.string('type')\n    table.string('text')\n    table.string('user').references('users.id')\n    table.enu('direction', ['in', 'out'])\n  })\n  .then(function() {\n    return helpers(knex).createTableIfNotExists('analytics_runs', function(table) {\n      table.increments('id').primary()\n      table.timestamp('ts')\n    })\n  })\n  .then(function() {\n    return helpers(knex).createTableIfNotExists('analytics_custom', function(table) {\n      table.string('date')\n      table.string('name')\n      table.integer('count')\n      table.unique(['date', 'name'])\n    })\n  })\n  .then(() => knex)\n}\n\nfunction saveInteractionIn(event) {\n\n  let user = _.get(event, 'user.id')\n    || _.get(event, 'user.userId')\n    || _.get(event, 'raw.from')\n    || _.get(event, 'user')\n\n  if (!user.startsWith(event.platform)) {\n    user = event.platform + ':' + user\n  }\n\n  const interactionRow = {\n    ts: helpers(knex).date.now(),\n    type: event.type,\n    text: event.text,\n    user: user,\n    direction: 'in'\n  }\n\n  return knex('analytics_interactions').insert(interactionRow)\n}\n\nfunction saveInteractionOut(event) {\n\n  let userId = _.get(event, 'user.id')\n    || _.get(event, 'user.userId')\n    || _.get(event, 'raw.to')\n    || _.get(event, 'user')\n\n  if (!userId.startsWith(event.platform)) {\n    userId = event.platform + ':' + userId\n  }\n\n  const interactionRow = {\n    ts: helpers(knex).date.now(),\n    type: event.type,\n    text: event.text,\n    user: userId,\n    direction: 'out'\n  }\n\n  return knex('analytics_interactions').insert(interactionRow)\n  .then(function(result) { return true })\n}\n\nmodule.exports = (k, botpress) => {\n  knex = k\n  bp = botpress\n\n  return {\n    initializeDb: initializeDb,\n    saveIncoming: saveInteractionIn,\n    saveOutgoing: saveInteractionOut\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/db.js"]}