text: #! /usr/bin/env node
  "use strict";
  
  /**
   * @module BrowserSync
   */
  var pjson         = require("./package.json");
  var BrowserSync   = require("./lib/browser-sync");
  var publicUtils   = require("./lib/public/public-utils");
  var events        = require("events");
  var PassThrough   = require("stream").PassThrough;
  var logger        = require("eazy-logger").Logger({
      useLevelPrefixes: true
  });
  
  var singleton        = false;
  var singletonPlugins = [];
  var instances        = [];
  
  /**
   * @type {boolean|EventEmitter}
   */
  var singletonEmitter = false;
  
  module.exports         = initSingleton;
  
  /**
   * Create a Browsersync instance
   * @method create
   * @param {String} name an identifier that can used for retrieval later
   */
  module.exports.create    = create;
  
  /**
   * Get a single instance by name. This is useful if you have your
   * build scripts in separate files
   * @method get
   * @param {String} name
   * @returns {Object|Boolean}
   */
  module.exports.get = function (name) {
      var instance = getSingle(name);
      if (instance) {
          return instance;
      }
      throw new Error("An instance with the name `%s` was not found.".replace("%s", name));
  };
  
  /**
   * Start the Browsersync service. This will launch a server, proxy or start the snippet
   * mode depending on your use-case.
   * @method init
   * @param {Object} [config] This is the main configuration for your Browsersync instance and can contain any of the [available options]({{site.links.options}})
   *  If you do not pass a config an argument for configuration, Browsersync will still run; but it will be in the `snippet` mode
   * @param {Function} [cb] If you pass a callback function, it will be called when Browsersync has completed all setup tasks and is ready to use. This
   * is useful when you need to wait for information (for example: urls, port etc) or perform other tasks synchronously.
   * @returns {BrowserSync}
   */
  module.exports.init    = initSingleton;
  
  /**
   * Register a plugin. Must implement at least a 'plugin' method that returns a
   * callable function.
   *
   * @method use
   * @param {String} name The name of the plugin
   * @param {Object} module The object to be `required`.
   * @param {Function} [cb] A callback function that will return any errors.
   */
  module.exports.use     = function () {
      var args = Array.prototype.slice.call(arguments);
      singletonPlugins.push({
          args: args
      });
  };
  
  /**
   * The `reload` method will inform all browsers about changed files and will either cause the browser to refresh, or inject the files where possible.
   *
   * @method reload
   * @param {String|Array|Object} [arg] The file or files to be reloaded.
   * @returns {*}
   */
  module.exports.reload  = noop("reload");
  
  /**
   * The `stream` method returns a transform stream and can act once or on many files.
   *
   * @method stream
   * @param {Object} [opts] Configuration for the stream method
   * @since 2.6.0
   * @returns {*}
   */
  module.exports.stream  = noop("stream");
  
  /**
   * Helper method for browser notifications
   *
   * @method notify
   * @param {String|HTML} msg Can be a simple message such as 'Connected' or HTML
   * @param {Number} [timeout] How long the message will remain in the browser. @since 1.3.0
   */
  module.exports.notify  = noop("notify");
  
  /**
   * This method will close any running server, stop file watching & exit the current process.
   *
   * @method exit
   */
  module.exports.exit    = noop("exit");
  
  /**
   * Stand alone file-watcher. Use this along with Browsersync to create your own, minimal build system
   * @method watch
   * @param {string} patterns Glob patterns for files to watch
   * @param {object} [opts] Options to be passed to Chokidar - check what's available in [their docs](https://github.com/paulmillr/chokidar#getting-started)
   * @param {function} [fn] Callback function for each event.
   * @since 2.6.0
   */
  module.exports.watch   = noop("watch");
  
  /**
   * Method to pause file change events
   *
   * @method pause
   */
  module.exports.pause   = noop("pause");
  
  /**
   * Method to resume paused watchers
   *
   * @method resume
   */
  module.exports.resume  = noop("resume");
  
  /**
   * Add properties fo
   */
  Object.defineProperties(module.exports, {
      /**
       * The internal Event Emitter used by the running Browsersync instance (if there is one).
       * You can use this to emit your own events, such as changed files, logging etc.
       *
       * @property emitter
       */
      "emitter": {
          get: function () {
              if (!singletonEmitter) {
                  singletonEmitter = newEmitter();
                  return singletonEmitter;
              }
              return singletonEmitter;
          }
      },
      /**
       * A simple true/false flag that you can use to determine if there's a currently-running Browsersync instance.
       *
       * @property active
       */
      "active": {
          get: getSingletonValue.bind(null, "active")
      },
      /**
       * A simple true/false flag to determine if the current instance is paused
       *
       * @property paused
       */
      "paused": {
          get: getSingletonValue.bind(null, "paused")
      }
  });
  
  /**
   * Event emitter factory
   * @returns {EventEmitter}
   */
  function newEmitter() {
      var emitter = new events.EventEmitter();
      emitter.setMaxListeners(20);
      return emitter;
  }
  
  /**
   * Get the singleton's emitter, or a new one.
   * @returns {EventEmitter}
   */
  function getSingletonEmitter() {
      if (singletonEmitter) {
          return singletonEmitter;
      }
      singletonEmitter = newEmitter();
      return singletonEmitter;
  }
  
  /**
   * Helper to allow methods to be called on the module export
   * before there's a running instance
   * @param {String} name
   * @returns {Function}
   */
  function noop(name) {
      return function () {
          var args = Array.prototype.slice.call(arguments);
          if (singleton) {
              return singleton[name].apply(singleton, args);
          } else {
              if (publicUtils.isStreamArg(name, args)) {
                  return new PassThrough({objectMode: true});
              }
          }
      };
  }
  
  /**
   * Create a single instance when module export is used directly via browserSync({});
   * This is mostly for back-compatibility, for also for the nicer api.
   * This will never be removed to ensure we never break user-land, but
   * we should discourage it's use.
   * @returns {*}
   */
  function initSingleton() {
      var instance;
      if (instances.length) {
          instance = instances.filter(function (item) {
              return item.name === "singleton";
          });
          if (instance.length) {
              logger.error("{yellow:You tried to start Browsersync twice!} To create multiple instances, use {cyan:browserSync.create().init()");
              return instance;
          }
      }
      var args = Array.prototype.slice.call(arguments);
      singleton = create("singleton", getSingletonEmitter());
  
      if (singletonPlugins.length) {
          singletonPlugins.forEach(function (obj) {
              singleton.instance.registerPlugin.apply(singleton.instance, obj.args);
          });
      }
  
      singleton.init.apply(null, args);
      return singleton;
  }
  
  /**
   * @param {String} prop
   * @returns {Object|Boolean}
   */
  function getSingletonValue(prop) {
      var single = getSingle("singleton");
      if (single) {
          return single[prop];
      }
      return false;
  }
  
  /**
   * Get a single instance by name
   * @param {String} name
   * @returns {Object|Boolean}
   */
  function getSingle(name) {
      if (instances.length) {
          var match = instances.filter(function (item) {
              return item.name === name;
          });
          if (match.length) {
              return match[0];
          }
      }
      return false;
  }
  
  /**
   * Create an instance of Browsersync
   * @param {String} [name]
   * @param {EventEmitter} [emitter]
   * @returns {{init: *, exit: (exit|exports), notify: *, reload: *, cleanup: *, emitter: (Browsersync.events|*), use: *}}
   */
  function create(name, emitter) {
  
      name    = name    || new Date().getTime();
      emitter = emitter || newEmitter();
  
      var browserSync = new BrowserSync(emitter, name);
  
      var instance = {
          name:      name,
          instance:  browserSync,
          exit:      require("./lib/public/exit")(browserSync),
          notify:    require("./lib/public/notify")(browserSync),
          pause:     require("./lib/public/pause")(browserSync),
          resume:    require("./lib/public/resume")(browserSync),
          reload:    require("./lib/public/reload")(emitter),
          stream:    require("./lib/public/stream")(emitter),
          cleanup:   browserSync.cleanup.bind(browserSync),
          use:       browserSync.registerPlugin.bind(browserSync),
          getOption: browserSync.getOption.bind(browserSync),
          emitter:   browserSync.events,
          watch:     require("./lib/file-watcher").watch
      };
  
      browserSync.publicInstance = instance;
      instance.init = require("./lib/public/init")(browserSync, name, pjson);
  
      Object.defineProperty(instance, "active", {
          get: function () {
              return browserSync.active;
          }
      });
  
      Object.defineProperty(instance, "paused", {
          get: function () {
              return browserSync.paused;
          }
      });
  
      /**
       * Access to client-side socket for emitting events
       *
       * @property sockets
       */
      Object.defineProperty(instance, "sockets", {
          get: function () {
              if (!browserSync.active) {
                  return {
                      emit: function () {},
                      on: function () {}
                  };
              } else {
                  return browserSync.io.sockets;
              }
          }
      });
  
      instances.push(instance);
  
      return instance;
  }
  
  /**
   * Reset the state of the module.
   * (should only be needed for test environments)
   */
  module.exports.reset = function () {
      instances.forEach(function (item) {
          item.cleanup();
      });
      instances        = [];
      singletonPlugins = [];
      singletonEmitter = false;
      singleton        = false;
      process.removeAllListeners("SIGINT");
  };
  
  /**
   * @type {Array}
   */
  module.exports.instances = instances;
  