Demo for query storing

Change-Id: I947bcac841992c3f6cfd01ab337c265b0d01cb70
diff --git a/node_modules/grunt-contrib-watch/tasks/lib/livereload.js b/node_modules/grunt-contrib-watch/tasks/lib/livereload.js
new file mode 100644
index 0000000..55fc098
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/lib/livereload.js
@@ -0,0 +1,63 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var tinylr = require('tiny-lr');
+var _ = require('lodash');
+
+// Holds the servers out of scope in case watch is reloaded
+var servers = Object.create(null);
+
+module.exports = function(grunt) {
+
+  var defaults = {port: 35729};
+
+  function LR(options) {
+    if (options === true) {
+      options = defaults;
+    } else if (typeof options === 'number') {
+      options = {port: options};
+    } else {
+      options = _.defaults(options, defaults);
+    }
+
+    var host = (options.host || '*') + ':' + options.port;
+
+    if (servers[host]) {
+      this.server = servers[host];
+    } else {
+      this.server = tinylr(options);
+      this.server.server.removeAllListeners('error');
+      this.server.server.on('error', function(err) {
+        if (err.code === 'EADDRINUSE') {
+          grunt.fatal('Port ' + options.port + ' is already in use by another process.');
+        } else {
+          grunt.fatal(err);
+        }
+        process.exit(1);
+      });
+      this.server.listen(options.port, options.host, function(err) {
+        if (err) {
+          return grunt.fatal(err);
+        }
+        grunt.log.verbose.writeln('Live reload server started on ' + host);
+      });
+      servers[host] = this.server;
+    }
+  }
+
+  LR.prototype.trigger = function(files) {
+    grunt.log.verbose.writeln('Live reloading ' + grunt.log.wordlist(files) + '...');
+    this.server.changed({body: {files: files}});
+  };
+
+  return function(options) {
+    return new LR(options);
+  };
+};
diff --git a/node_modules/grunt-contrib-watch/tasks/lib/taskrun.js b/node_modules/grunt-contrib-watch/tasks/lib/taskrun.js
new file mode 100644
index 0000000..34d0672
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/lib/taskrun.js
@@ -0,0 +1,110 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+module.exports = function(grunt) {
+
+  // Create a TaskRun on a target
+  function TaskRun(target) {
+    this.name = target.name || 0;
+    this.files = target.files || [];
+    this._getConfig = target._getConfig;
+    this.options = target.options;
+    this.startedAt = false;
+    this.spawned = null;
+    this.changedFiles = Object.create(null);
+    this.spawnTaskFailure = false;
+    this.livereloadOnError = true;
+    if (typeof this.options.livereloadOnError !== 'undefined') {
+      this.livereloadOnError = this.options.livereloadOnError;
+    }
+  }
+
+  var getErrorCount = function() {
+    if (typeof grunt.fail.forever_warncount !== 'undefined') {
+      return grunt.fail.forever_warncount + grunt.fail.forever_errorcount;
+    } else {
+      return grunt.fail.warncount + grunt.fail.errorcount;
+    }
+  };
+
+  // Run it
+  TaskRun.prototype.run = function(done) {
+    var self = this;
+
+    // Dont run if already running
+    if (self.startedAt !== false) {
+      return;
+    }
+
+    // Start this task run
+    self.startedAt = Date.now();
+
+    // reset before each run
+    self.spawnTaskFailure = false;
+    self.errorsAndWarningsCount = getErrorCount();
+
+    // pull the tasks here in case they were changed by a watch event listener
+    self.tasks = self._getConfig('tasks') || [];
+    if (typeof self.tasks === 'string') {
+      self.tasks = [self.tasks];
+    }
+
+    // If no tasks just call done to trigger potential livereload
+    if (self.tasks.length < 1) {
+      return done();
+    }
+
+    if (self.options.spawn === false || self.options.nospawn === true) {
+      grunt.task.run(self.tasks);
+      done();
+    } else {
+      self.spawned = grunt.util.spawn({
+        // Spawn with the grunt bin
+        grunt: true,
+        // Run from current working dir and inherit stdio from process
+        opts: {
+          cwd: self.options.cwd.spawn,
+          stdio: 'inherit'
+        },
+        // Run grunt this process uses, append the task to be run and any cli options
+        args: self.tasks.concat(self.options.cliArgs || [])
+      }, function(err, res, code) {
+        self.spawnTaskFailure = (code !== 0);
+        if (self.options.interrupt !== true || (code !== 130 && code !== 1)) {
+          // Spawn is done
+          self.spawned = null;
+          done();
+        }
+      });
+    }
+  };
+
+  // When the task run has completed
+  TaskRun.prototype.complete = function() {
+    var time = Date.now() - this.startedAt;
+    this.startedAt = false;
+    if (this.spawned) {
+      this.spawned.kill('SIGINT');
+      this.spawned = null;
+    }
+
+    var taskFailed = this.spawnTaskFailure || (getErrorCount() > this.errorsAndWarningsCount);
+    this.errorsAndWarningsCount = getErrorCount();
+
+    // Trigger livereload if necessary
+    if (this.livereload && (this.livereloadOnError || !taskFailed)) {
+      this.livereload.trigger(Object.keys(this.changedFiles));
+      this.changedFiles = Object.create(null);
+    }
+    return time;
+  };
+
+  return TaskRun;
+};
diff --git a/node_modules/grunt-contrib-watch/tasks/lib/taskrunner.js b/node_modules/grunt-contrib-watch/tasks/lib/taskrunner.js
new file mode 100644
index 0000000..fb8c1d6
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/lib/taskrunner.js
@@ -0,0 +1,387 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var path = require('path');
+var EE = require('events').EventEmitter;
+var util = require('util');
+var _ = require('lodash');
+var async = require('async');
+
+// Track which targets to run after reload
+var reloadTargets = [];
+
+// A default target name for config where targets are not used (keep this unique)
+var defaultTargetName = '_$_default_$_';
+
+module.exports = function(grunt) {
+
+  var TaskRun = require('./taskrun')(grunt);
+  var livereload = require('./livereload')(grunt);
+
+  function Runner() {
+    EE.call(this);
+    // Name of the task
+    this.name = 'watch';
+    // Options for the runner
+    this.options = {};
+    // Function to close the task
+    this.done = function() {};
+    // Targets available to task run
+    this.targets = Object.create(null);
+    // The queue of task runs
+    this.queue = [];
+    // Whether we're actively running tasks
+    this.running = false;
+    // If a nospawn task has ran (and needs the watch to restart)
+    this.nospawn = false;
+    // Set to true before run() to reload task
+    this.reload = false;
+    // For re-queuing arguments with the task that originally ran this
+    this.nameArgs = [];
+    // A list of changed files to feed to task runs for livereload
+    this.changedFiles = Object.create(null);
+  }
+  util.inherits(Runner, EE);
+
+  // Init a task for taskrun
+  Runner.prototype.init = function init(name, defaults, done) {
+    var self = this;
+
+    self.name = name || grunt.task.current.name || 'watch';
+    self.options = self._options(grunt.config([self.name, 'options']) || {}, defaults || {});
+    self.reload = false;
+    self.nameArgs = grunt.task.current.nameArgs ? grunt.task.current.nameArgs : self.name;
+
+    // Normalize cwd option
+    if (typeof self.options.cwd === 'string') {
+      self.options.cwd = {files: self.options.cwd, spawn: self.options.cwd};
+    }
+
+    // Function to call when closing the task
+    self.done = done || grunt.task.current.async();
+
+    // If a default livereload server for all targets
+    // Use task level unless target level overrides
+    var taskLRConfig = grunt.config([self.name, 'options', 'livereload']);
+    if (self.options.target && taskLRConfig) {
+      var targetLRConfig = grunt.config([self.name, self.options.target, 'options', 'livereload']);
+      if (targetLRConfig) {
+        // Dont use task level as target level will be used instead
+        taskLRConfig = false;
+      }
+    }
+    if (taskLRConfig) {
+      self.livereload = livereload(taskLRConfig);
+    }
+
+    // Return the targets normalized
+    var targets = self._getTargets(self.name);
+
+    if (self.running) {
+      // If previously running, complete the last run
+      self.complete();
+    } else if (reloadTargets.length > 0) {
+      // If not previously running but has items in the queue, needs run
+      self.queue = reloadTargets;
+      reloadTargets = [];
+      self.run();
+    } else {
+      if (!self.hadError) {
+        // Check whether target's tasks should run at start w/ atBegin option
+        self.queue = targets.filter(function(tr) {
+          return tr.options.atBegin === true && tr.tasks.length > 0;
+        }).map(function(tr) {
+          return tr.name;
+        });
+      } else {
+        // There was an error in atBegin task, we can't re-run it, as this would
+        // create an infinite loop of failing tasks
+        // See https://github.com/gruntjs/grunt-contrib-watch/issues/169
+        self.queue = [];
+        self.hadError = false;
+      }
+      if (self.queue.length > 0) {
+        self.run();
+      }
+    }
+
+    return targets;
+  };
+
+  // Normalize targets from config
+  Runner.prototype._getTargets = function _getTargets(name) {
+    var self = this;
+
+    grunt.task.current.requiresConfig(name);
+    var config = grunt.config(name);
+    var onlyTarget = self.options.target ? self.options.target : false;
+
+    var targets = (onlyTarget ? [onlyTarget] : Object.keys(config)).filter(function(key) {
+      if (key === 'options') {
+        return false;
+      }
+      return typeof config[key] !== 'string' && !Array.isArray(config[key]);
+    }).map(function(target) {
+      // Fail if any required config properties have been omitted
+      grunt.task.current.requiresConfig([name, target, 'files']);
+      var cfg = grunt.config([name, target]);
+      cfg.name = target;
+      cfg.options = self._options(cfg.options || {}, self.options);
+      self.add(cfg);
+      return cfg;
+    }, self);
+
+    // Allow "basic" non-target format
+    if (typeof config.files === 'string' || Array.isArray(config.files)) {
+      var cfg = {
+        files: config.files,
+        tasks: config.tasks,
+        name: defaultTargetName,
+        options: self._options(config.options || {}, self.options)
+      };
+      targets.push(cfg);
+      self.add(cfg);
+    }
+
+    return targets;
+  };
+
+  // Default options
+  Runner.prototype._options = function _options() {
+    var args = Array.prototype.slice.call(arguments).concat({
+      // The cwd to spawn within
+      cwd: process.cwd(),
+      // Additional cli args to append when spawning
+      cliArgs: _.without.apply(null, [[].slice.call(process.argv, 2)].concat(grunt.cli.tasks)),
+      interrupt: false,
+      nospawn: false,
+      spawn: true,
+      atBegin: false,
+      event: ['all'],
+      target: null
+    });
+    return _.defaults.apply(_, args);
+  };
+
+  // Run the current queue of task runs
+  Runner.prototype.run = _.debounce(function run() {
+    var self = this;
+    if (self.queue.length < 1) {
+      self.running = false;
+      return;
+    }
+
+    // Re-grab task options in case they changed between runs
+    self.options = self._options(grunt.config([self.name, 'options']) || {}, self.options);
+
+    // If we should interrupt
+    if (self.running === true) {
+      var shouldInterrupt = true;
+      self.queue.forEach(function(name) {
+        var tr = self.targets[name];
+        if (tr && tr.options.interrupt !== true) {
+          shouldInterrupt = false;
+          return false;
+        }
+      });
+      if (shouldInterrupt === true) {
+        self.interrupt();
+      } else {
+        // Dont interrupt the tasks running
+        return;
+      }
+    }
+
+    // If we should reload
+    if (self.reload) {
+      return self.reloadTask();
+    }
+
+    // Trigger that tasks runs have started
+    self.emit('start');
+    self.running = true;
+
+    // Run each target
+    var shouldComplete = true;
+    async.forEachSeries(self.queue, function(name, next) {
+      var tr = self.targets[name];
+      if (!tr) {
+        return next();
+      }
+
+      // Re-grab options in case they changed between runs
+      tr.options = self._options(grunt.config([self.name, name, 'options']) || {}, tr.options, self.options);
+
+      if (tr.options.spawn === false || tr.options.nospawn === true) {
+        shouldComplete = false;
+      }
+      tr.run(next);
+    }, function() {
+      if (shouldComplete) {
+        self.complete();
+      } else {
+        grunt.task.mark().run(self.nameArgs);
+        self.done();
+      }
+    });
+  }, 250);
+
+  // Push targets onto the queue
+  Runner.prototype.add = function add(target) {
+    var self = this;
+    if (!this.targets[target.name || 0]) {
+
+      // Private method for getting latest config for a watch target
+      target._getConfig = function(name) {
+        var cfgPath = [self.name];
+        if (target.name !== defaultTargetName) {
+          cfgPath.push(target.name);
+        }
+        if (name) {
+          cfgPath.push(name);
+        }
+        return grunt.config(cfgPath);
+      };
+
+      // Create a new TaskRun instance
+      var tr = new TaskRun(target);
+
+      // Add livereload to task runs
+      // Get directly from config as task level options are merged.
+      // We only want a single default LR server and then
+      // allow each target to override their own.
+      var lrconfig = grunt.config([this.name, target.name || 0, 'options', 'livereload']);
+      if (lrconfig) {
+        tr.livereload = livereload(lrconfig);
+      } else if (this.livereload && lrconfig !== false) {
+        tr.livereload = this.livereload;
+      }
+
+      return this.targets[tr.name] = tr;
+    }
+    return false;
+  };
+
+  // Do this when queued task runs have completed/scheduled
+  Runner.prototype.complete = function complete() {
+    var self = this;
+    if (self.running === false) {
+      return;
+    }
+    self.running = false;
+    var time = 0;
+    for (var i = 0, len = self.queue.length; i < len; ++i) {
+      var name = self.queue[i];
+      var target = self.targets[name];
+      if (!target) {
+        return;
+      }
+      if (target.startedAt !== false) {
+        time += target.complete();
+        self.queue.splice(i--, 1);
+        len--;
+
+        // if we're just livereloading and no tasks
+        // it can happen too fast and we dont report it
+        if (target.options.livereload && target.tasks.length < 1) {
+          time += 0.0001;
+        }
+      }
+    }
+    var elapsed = (time > 0) ? Number(time / 1000) : 0;
+    self.changedFiles = Object.create(null);
+    self.emit('end', elapsed);
+  };
+
+  // Run through completing every target in the queue
+  Runner.prototype._completeQueue = function _completeQueue() {
+    var self = this;
+    self.queue.forEach(function(name) {
+      var target = self.targets[name];
+      if (!target) {
+        return;
+      }
+      target.complete();
+    });
+  };
+
+  // Interrupt the running tasks
+  Runner.prototype.interrupt = function interrupt() {
+    var self = this;
+    self._completeQueue();
+    grunt.task.clearQueue();
+    self.emit('interrupt');
+  };
+
+  // Attempt to make this task run forever
+  Runner.prototype.forever = function forever() {
+    var self = this;
+    function rerun() {
+      // Clear queue and rerun to prevent failing
+      self._completeQueue();
+      grunt.task.clearQueue();
+      grunt.task.run(self.nameArgs);
+      self.running = false;
+      // Mark that there was an error and we needed to rerun
+      self.hadError = true;
+    }
+    grunt.fail.forever_warncount = 0;
+    grunt.fail.forever_errorcount = 0;
+    grunt.warn = grunt.fail.warn = function(e) {
+      grunt.fail.forever_warncount ++;
+      var message = typeof e === 'string' ? e : e.message;
+      grunt.log.writeln(('Warning: ' + message).yellow);
+      if (!grunt.option('force')) {
+        rerun();
+      }
+    };
+    grunt.fatal = grunt.fail.fatal = function(e) {
+      grunt.fail.forever_errorcount ++;
+      var message = typeof e === 'string' ? e : e.message;
+      grunt.log.writeln(('Fatal error: ' + message).red);
+      rerun();
+    };
+  };
+
+  // Clear the require cache for all passed filepaths.
+  Runner.prototype.clearRequireCache = function() {
+    // If a non-string argument is passed, it's an array of filepaths, otherwise
+    // each filepath is passed individually.
+    var filepaths = typeof arguments[0] !== 'string' ? arguments[0] : Array.prototype.slice(arguments);
+    // For each filepath, clear the require cache, if necessary.
+    filepaths.forEach(function(filepath) {
+      var abspath = path.resolve(filepath);
+      if (require.cache[abspath]) {
+        grunt.verbose.write('Clearing require cache for "' + filepath + '" file...').ok();
+        delete require.cache[abspath];
+      }
+    });
+  };
+
+  // Reload this watch task, like when a Gruntfile is edited
+  Runner.prototype.reloadTask = function() {
+    var self = this;
+    // Which targets to run after reload
+    reloadTargets = self.queue;
+    self.emit('reload', reloadTargets);
+
+    // Re-init the watch task config
+    grunt.task.init([self.name]);
+
+    // Complete all running tasks
+    self._completeQueue();
+
+    // Run the watch task again
+    grunt.task.run(self.nameArgs);
+    self.done();
+  };
+
+  return new Runner();
+};
diff --git a/node_modules/grunt-contrib-watch/tasks/watch.js b/node_modules/grunt-contrib-watch/tasks/watch.js
new file mode 100644
index 0000000..8a8f8b3
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/watch.js
@@ -0,0 +1,191 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var path = require('path');
+var Gaze = require('gaze').Gaze;
+var _ = require('lodash');
+var waiting = 'Waiting...';
+var changedFiles = Object.create(null);
+var watchers = [];
+
+module.exports = function(grunt) {
+
+  var taskrun = require('./lib/taskrunner')(grunt);
+
+  // Default date format logged
+  var dateFormat = function(time) {
+    grunt.log.writeln(String(
+      'Completed in ' +
+      time.toFixed(3) +
+      's at ' +
+      (new Date()).toString()
+    ).cyan + ' - ' + waiting);
+  };
+
+  // When task runner has started
+  taskrun.on('start', function() {
+    Object.keys(changedFiles).forEach(function(filepath) {
+      // Log which file has changed, and how.
+      grunt.log.ok('File "' + filepath + '" ' + changedFiles[filepath] + '.');
+    });
+    // Reset changedFiles
+    changedFiles = Object.create(null);
+  });
+
+  // When task runner has ended
+  taskrun.on('end', function(time) {
+    if (time > 0) {
+      dateFormat(time);
+    }
+  });
+
+  // When a task run has been interrupted
+  taskrun.on('interrupt', function() {
+    grunt.log.writeln('').write('Scheduled tasks have been interrupted...'.yellow);
+  });
+
+  // When taskrun is reloaded
+  taskrun.on('reload', function() {
+    taskrun.clearRequireCache(Object.keys(changedFiles));
+    grunt.log.writeln('').writeln('Reloading watch config...'.cyan);
+  });
+
+  grunt.registerTask('watch', 'Run predefined tasks whenever watched files change.', function(target) {
+    var self = this;
+    var name = self.name || 'watch';
+
+    // Close any previously opened watchers
+    watchers.forEach(function(watcher) {
+      watcher.close();
+    });
+    watchers = [];
+
+    // Never gonna give you up, never gonna let you down
+    if (grunt.config([name, 'options', 'forever']) !== false) {
+      taskrun.forever();
+    }
+
+    // If a custom dateFormat function
+    var df = grunt.config([name, 'options', 'dateFormat']);
+    if (typeof df === 'function') {
+      dateFormat = df;
+    }
+
+    if (taskrun.running === false) {
+      grunt.log.writeln(waiting);
+    }
+
+    // Initialize taskrun
+    var targets = taskrun.init(name, {target: target});
+
+    targets.forEach(function(target) {
+      if (typeof target.files === 'string') {
+        target.files = [target.files];
+      }
+
+      // Process into raw patterns
+      var patterns = _.chain(target.files).flatten().map(function(pattern) {
+        return grunt.config.process(pattern);
+      }).value();
+
+      // Validate the event option
+      if (typeof target.options.event === 'string') {
+        target.options.event = [target.options.event];
+      }
+
+      var eventCwd = process.cwd();
+      if (target.options.cwd && target.options.cwd.event) {
+        eventCwd = target.options.cwd.event;
+      }
+
+      // Set cwd if options.cwd.file is set
+      if (typeof target.options.cwd !== 'string' && target.options.cwd.files) {
+        target.options.cwd = target.options.cwd.files;
+      }
+
+      // Create watcher per target
+      watchers.push(new Gaze(patterns, target.options, function(err) {
+        if (err) {
+          if (typeof err === 'string') {
+            err = new Error(err);
+          }
+          grunt.log.writeln('ERROR'.red);
+          grunt.fatal(err);
+          return taskrun.done();
+        }
+
+        // Log all watched files with --verbose set
+        if (grunt.option('verbose')) {
+          var watched = this.watched();
+          Object.keys(watched).forEach(function(watchedDir) {
+            watched[watchedDir].forEach(function(watchedFile) {
+              grunt.log.writeln('Watching ' + path.relative(process.cwd(), watchedFile) + ' for changes.');
+            });
+          });
+        }
+
+        // On changed/added/deleted
+        this.on('all', function(status, filepath) {
+
+          // Skip events not specified
+          if (!_.includes(target.options.event, 'all') &&
+              !_.includes(target.options.event, status)) {
+            return;
+          }
+
+          filepath = path.relative(eventCwd, filepath);
+
+          // Skip empty filepaths
+          if (filepath === '') {
+            return;
+          }
+
+          // If Gruntfile.js changed, reload self task
+          if (target.options.reload || /gruntfile\.(js|coffee)/i.test(filepath)) {
+            taskrun.reload = true;
+          }
+
+          // Emit watch events if anyone is listening
+          if (grunt.event.listeners('watch').length > 0) {
+            grunt.event.emit('watch', status, filepath, target.name);
+          }
+
+          // Group changed files only for display
+          changedFiles[filepath] = status;
+
+          // Add changed files to the target
+          if (taskrun.targets[target.name]) {
+            if (!taskrun.targets[target.name].changedFiles) {
+              taskrun.targets[target.name].changedFiles = Object.create(null);
+            }
+            taskrun.targets[target.name].changedFiles[filepath] = status;
+          }
+
+          // Queue the target
+          if (taskrun.queue.indexOf(target.name) === -1) {
+            taskrun.queue.push(target.name);
+          }
+
+          // Run the tasks
+          taskrun.run();
+        });
+
+        // On watcher error
+        this.on('error', function(err) {
+          if (typeof err === 'string') {
+            err = new Error(err);
+          }
+          grunt.log.error(err.message);
+        });
+      }));
+    });
+
+  });
+};