text: var fs = require("fs"),
      q = require("q"),
      qfs = require("q-io/fs"),
      jimp = require("jimp"),
      resemble = require("node-resemble-js");
  
  // CURRENT POINTER STATE
  var pointer = { x: 0, y: 0, isDown: false };
  
  module.exports = function addGenericCommands(client, capabilities, runId) {
      // WEBDRIVER COMMAND: NORMALIZED SCREENSHOT - ignore platform specific offsets
      client.addCommand("saveNormalizedScreenshot", function(filePath, bounds) {
          return this.saveCroppedScreenshot(filePath, bounds);
      });
  
      // WEBDRIVER COMMAND: CROPPED SCREENSHOT
      client.addCommand("saveCroppedScreenshot", function(filePath, bounds) {
          if (arguments.length === 1) return this.saveScreenshot(filePath);
  
          return this.saveScreenshot().then(function(screenshotBuffer, response) {
              return jimp.read(screenshotBuffer).then(function(screenshot) {
                  var deferred = q.defer();
                  var x =
                          bounds.x > 0
                              ? Math.min(bounds.x, screenshot.bitmap.width - 1)
                              : 0,
                      y =
                          bounds.y > 0
                              ? Math.min(bounds.y, screenshot.bitmap.height - 1)
                              : 0,
                      w =
                          bounds.w > 0
                              ? Math.min(bounds.w, screenshot.bitmap.width - x)
                              : screenshot.bitmap.width - x,
                      h =
                          bounds.h > 0
                              ? Math.min(bounds.h, screenshot.bitmap.height - y)
                              : screenshot.bitmap.height - y;
  
                  screenshot
                      .crop(x, y, w, h)
                      .write(filePath, deferred.makeNodeResolver());
                  return deferred.promise;
              });
          });
      });
  
      // WEBDRIVER COMMAND: IMAGE COMPARE
      client.addCommand("resemble", function(
          actualPath,
          expectedPath,
          diffPath,
          bounds,
          checkAntialiasing
      ) {
          var self = this;
          return qfs.exists(expectedPath).then(function(exists) {
              if (
                  !exists // baseline screenshot to compare against doesn't exist; save it
              )
                  return self.saveNormalizedScreenshot(expectedPath, bounds);
              // baseline screenshot to compare against exists; do comparison
              else
                  return self
                      .saveNormalizedScreenshot(actualPath, bounds)
                      .then(function() {
                          var deferred = q.defer();
                          resemble(actualPath)
                              .compareTo(expectedPath)
                              [
                                  checkAntialiasing
                                      ? "ignoreNothing"
                                      : "ignoreAntialiasing"
                              ]()
                              .onComplete(function(data) {
                                  data.getDiffImage()
                                      .pack()
                                      .pipe(fs.createWriteStream(diffPath))
                                      .on("error", deferred.reject)
                                      .on("close", deferred.reject)
                                      .on("finish", function() {
                                          deferred.resolve(data);
                                      });
                              });
                          return deferred.promise;
                      });
          });
      });
  
      // WEBDRIVER COMMAND: NORMALIZED POINTER
      client.addCommand("pointerDown", function() {
          pointer.isDown = true;
          return this.isMobile
              ? this.touchDown(pointer.x, pointer.y)
              : this.buttonDown();
      });
      client.addCommand("pointerMove", function(x, y) {
          pointer.x = x;
          pointer.y = y;
          if (this.isMobile) {
              if (pointer.isDown) return this.touchMove(x, y);
          } else {
              return this.moveToObject(":root", x, y);
          }
      });
      client.addCommand("pointerUp", function() {
          pointer.isDown = false;
          return this.isMobile
              ? this.touchUp(pointer.x, pointer.y)
              : this.buttonUp();
      });
  
      // WEBDRIVER COMMAND: NORMALIZED KEYPRESS
      client.addCommand("keyDown", function(key) {
          return this.keys(key);
      });
      client.addCommand("keyUp", function(key) {
          return this.keys(key);
      });
  };
  