/* ==========================================================
 * bootstrap-twipsy.js v1.4.0
 * http://twitter.github.com/bootstrap/javascript.html#twipsy
 * Adapted from the original jQuery.tipsy by Jason Frame
 * ==========================================================
 * Copyright 2011 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */

!function( $ ) {

  "use strict"

 /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
  * ======================================================= */

  var transitionEnd

  $(document).ready(function () {

    $.support.transition = (function () {
      var thisBody = document.body || document.documentElement
        , thisStyle = thisBody.style
        , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
      return support
    })()

    // set CSS transition event type
    if ( $.support.transition ) {
      transitionEnd = "TransitionEnd"
      if ( $.browser.webkit ) {
      	transitionEnd = "webkitTransitionEnd"
      } else if ( $.browser.mozilla ) {
      	transitionEnd = "transitionend"
      } else if ( $.browser.opera ) {
      	transitionEnd = "oTransitionEnd"
      }
    }

  })

 /* TWIPSY PUBLIC CLASS DEFINITION
  * ============================== */

  var Twipsy = function ( element, options ) {
    this.$element = $(element)
    this.options = options
    this.enabled = true
    this.fixTitle()
  }

  Twipsy.prototype = {

    show: function() {
      var pos
        , actualWidth
        , actualHeight
        , placement
        , $tip
        , tp

      if (this.hasContent() && this.enabled) {
        $tip = this.tip()
        this.setContent()

        if (this.options.animate) {
          $tip.addClass('fade')
        }

        $tip
          .remove()
          .css({ top: 0, left: 0, display: 'block' })
          .prependTo(document.body)

        pos = $.extend({}, this.$element.offset(), {
          width: this.$element[0].offsetWidth
        , height: this.$element[0].offsetHeight
        })

        actualWidth = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight

        placement = maybeCall(this.options.placement, this, [ $tip[0], this.$element[0] ])

        switch (placement) {
          case 'below':
            tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'above':
            tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'left':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}
            break
          case 'right':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}
            break
        }

        $tip
          .css(tp)
          .addClass(placement)
          .addClass('in')
      }
    }

  , setContent: function () {
      var $tip = this.tip()
      $tip.find('.twipsy-inner')[this.options.html ? 'html' : 'text'](this.getTitle())
      $tip[0].className = 'twipsy'
    }

  , hide: function() {
      var that = this
        , $tip = this.tip()

      $tip.removeClass('in')

      function removeElement () {
        $tip.remove()
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        $tip.bind(transitionEnd, removeElement) :
        removeElement()
    }

  , fixTitle: function() {
      var $e = this.$element
      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
        $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
      }
    }

  , hasContent: function () {
      return this.getTitle()
    }

  , getTitle: function() {
      var title
        , $e = this.$element
        , o = this.options

        this.fixTitle()

        if (typeof o.title == 'string') {
          title = $e.attr(o.title == 'title' ? 'data-original-title' : o.title)
        } else if (typeof o.title == 'function') {
          title = o.title.call($e[0])
        }

        title = ('' + title).replace(/(^\s*|\s*$)/, "")

        return title || o.fallback
    }

  , tip: function() {
      return this.$tip = this.$tip || $('
').html(this.options.template)
    }

  , validate: function() {
      if (!this.$element[0].parentNode) {
        this.hide()
        this.$element = null
        this.options = null
      }
    }

  , enable: function() {
      this.enabled = true
    }

  , disable: function() {
      this.enabled = false
    }

  , toggleEnabled: function() {
      this.enabled = !this.enabled
    }

  , toggle: function () {
      this[this.tip().hasClass('in') ? 'hide' : 'show']()
    }

  }

 /* TWIPSY PRIVATE METHODS
  * ====================== */

   function maybeCall ( thing, ctx, args ) {
     return typeof thing == 'function' ? thing.apply(ctx, args) : thing
   }

 /* TWIPSY PLUGIN DEFINITION
  * ======================== */

  $.fn.twipsy = function (options) {
    $.fn.twipsy.initWith.call(this, options, Twipsy, 'twipsy')
    return this
  }

  $.fn.twipsy.initWith = function (options, Constructor, name) {
    var twipsy
      , binder
      , eventIn
      , eventOut

    if (options === true) {
      return this.data(name)
    } else if (typeof options == 'string') {
      twipsy = this.data(name)
      if (twipsy) {
        twipsy[options]()
      }
      return this
    }

    options = $.extend({}, $.fn[name].defaults, options)

    function get(ele) {
      var twipsy = $.data(ele, name)

      if (!twipsy) {
        twipsy = new Constructor(ele, $.fn.twipsy.elementOptions(ele, options))
        $.data(ele, name, twipsy)
      }

      return twipsy
    }

    function enter() {
      var twipsy = get(this)
      twipsy.hoverState = 'in'

      if (options.delayIn == 0) {
        twipsy.show()
      } else {
        twipsy.fixTitle()
        setTimeout(function() {
          if (twipsy.hoverState == 'in') {
            twipsy.show()
          }
        }, options.delayIn)
      }
    }

    function leave() {
      var twipsy = get(this)
      twipsy.hoverState = 'out'
      if (options.delayOut == 0) {
        twipsy.hide()
      } else {
        setTimeout(function() {
          if (twipsy.hoverState == 'out') {
            twipsy.hide()
          }
        }, options.delayOut)
      }
    }

    if (!options.live) {
      this.each(function() {
        get(this)
      })
    }

    if (options.trigger != 'manual') {
      binder   = options.live ? 'live' : 'bind'
      eventIn  = options.trigger == 'hover' ? 'mouseenter' : 'focus'
      eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'
      this[binder](eventIn, enter)[binder](eventOut, leave)
    }

    return this
  }

  $.fn.twipsy.Twipsy = Twipsy

  $.fn.twipsy.defaults = {
    animate: true
  , delayIn: 0
  , delayOut: 0
  , fallback: ''
  , placement: 'above'
  , html: false
  , live: false
  , offset: 0
  , title: 'title'
  , trigger: 'hover'
  , template: '

'
  }

  $.fn.twipsy.rejectAttrOptions = [ 'title' ]

  $.fn.twipsy.elementOptions = function(ele, options) {
    var data = $(ele).data()
      , rejects = $.fn.twipsy.rejectAttrOptions
      , i = rejects.length

    while (i--) {
      delete data[rejects[i]]
    }

    return $.extend({}, options, data)
  }

}( window.jQuery || window.ender );


// Display close "x" icon when user hovers over working set file

keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace keep


/*
 * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved.
 */
define(function(require, exports, module) {

    // Load dependent modules
    var DocumentManager     = require("DocumentManager")
	, CommandManager        = require("CommandManager")
	, Commands              = require("Commands")
	,	EditorManager		= require("EditorManager")
    ,   NativeFileSystem    = require("NativeFileSystem").NativeFileSystem
    ;

    // Initialize: register listeners
    $(DocumentManager).on("currentDocumentChange", _onCurrentDocumentChange);

    function _onCurrentDocumentChange(event) {
        console.log("Current document changed!  --> "+DocumentManager.getCurrentDocument());
    }

    $(DocumentManager).on("workingSetAdd", function(event, addedDoc) {
        console.log("Working set ++ " + addedDoc);
        //console.log("  set: " + DocumentManager.getWorkingSet().join());

		_addDoc( addedDoc )

    });
    $(DocumentManager).on("workingSetRemove", function(event, removedDoc) {
        console.log("Working set -- " + removedDoc);
        //console.log("  set: " + DocumentManager.getWorkingSet().join());

		_removeDoc( removedDoc );
    });

    $(DocumentManager).on("dirtyFlagChange", function(event, doc ) {
        console.log("Dirty flag change: " + doc);

		_dirtyFlagChanged( doc );
    });

	/** Each list item in the working set stores a references to the related document in the list item's data.
	 *  Use listIem.data( _DOCUMENT_KEY ) to get the document reference
	 */
	var _DOCUMENT_KEY = "document";

	function _addDoc( doc ) {
		// Add new item to bottom of list
		var link = $("").attr( "href", "#" ).text( doc.file.name );
		var newItem = $("

").addClass("working-set-list-item").append( link );

		// TODO: Ask NJ which way is better
		//var newItem = $("
" + doc.file.name +  "
");

		newItem.data( _DOCUMENT_KEY, doc );

		$("#open-files-container").children("ul").append(newItem);

		newItem.click( function() {
			_openDoc( doc );
		});

		_updateFileStatusIcon( newItem, doc.isDirty, false);

		newItem.hover(
			// hover in
	        function() {
				_updateFileStatusIcon( $(this), doc.isDirty, true);
	        },
			// hover out
	        function() {
				_updateFileStatusIcon( $(this), doc.isDirty, false);
	        }
	    );
	}

    function _updateFileStatusIcon(listElement, isDirty, canClose) {
       var found = listElement.find(".file-status-icon");
       var fileStatusIcon = found.length != 0 ? $(found[0]) : null;
       var showIcon = isDirty || canClose;

       // remove icon if its not needed
       if (!showIcon && fileStatusIcon) {
           fileStatusIcon.remove();
           fileStatusIcon = null;
       }
       // create icon if its needed and doesn't exist
       else if (showIcon && !fileStatusIcon) {
           fileStatusIcon = $("

");
           fileStatusIcon.addClass("file-status-icon");
           listElement.prepend(fileStatusIcon);

		   fileStatusIcon.click( function() {
			   var doc = listElement.data( _DOCUMENT_KEY )
			   CommandManager.execute(Commands.FILE_CLOSE, doc.file.fullPath );
		   });
       }

       // Set icon's class
       if (fileStatusIcon) {
           fileStatusIcon.toggleClass("dirty", isDirty);
           fileStatusIcon.toggleClass("canClose", canClose);
       }
   }

   function _openDoc( doc ) {
	   CommandManager.execute(Commands.FILE_OPEN, doc.file.fullPath);

    }

   function _closeDoc( doc ) {
	   CommandManager.execute(Commands.FILE_CLOSE, doc.file.fullPath );
   }

   function _findListItemFromDocument( doc ) {
	   if( doc ){
		   $("#open-files-container").children().forEach( function( element, index, array ){
			   if(element.data( _DOCUMENT_KEY ) === doc)
			   	return element;
		   });
	   }

	   return null;
   }

	function _removeDoc( doc ) {
 	   var listIem = _findListItemFromDocument( doc );
 	   if(listIem){
 		   listItem.remove();
 	   }
	}

	function _dirtyFlagChanged( doc ){
		$("#" + doc.file.fullPath).find(".file-status-icon");
	}

	function _rebuild() {

	}

});


/* ===========================================================
 * bootstrap-popover.js v1.4.0
 * http://twitter.github.com/bootstrap/javascript.html#popover
 * ===========================================================
 * Copyright 2011 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =========================================================== */

!function( $ ) {

 "use strict"

  var Popover = function ( element, options ) {
    this.$element = $(element)
    this.options = options
    this.enabled = true
    this.fixTitle()
  }

  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TWIPSY.js
     ========================================= */

  Popover.prototype = $.extend({}, $.fn.twipsy.Twipsy.prototype, {

    setContent: function () {
      var $tip = this.tip()
      $tip.find('.title')[this.options.html ? 'html' : 'text'](this.getTitle())
      $tip.find('.content > *')[this.options.html ? 'html' : 'text'](this.getContent())
      $tip[0].className = 'popover'
    }

  , hasContent: function () {
      return this.getTitle() || this.getContent()
    }

  , getContent: function () {
      var content
       , $e = this.$element
       , o = this.options

      if (typeof this.options.content == 'string') {
        content = $e.attr(this.options.content)
      } else if (typeof this.options.content == 'function') {
        content = this.options.content.call(this.$element[0])
      }

      return content
    }

  , tip: function() {
      if (!this.$tip) {
        this.$tip = $('
')
          .html(this.options.template)
      }
      return this.$tip
    }

  })

 /* POPOVER PLUGIN DEFINITION
  * ======================= */

  $.fn.popover = function (options) {
    if (typeof options == 'object') options = $.extend({}, $.fn.popover.defaults, options)
    $.fn.twipsy.initWith.call(this, options, Popover, 'popover')
    return this
  }

  $.fn.popover.defaults = $.extend({} , $.fn.twipsy.defaults, {
    placement: 'right'
  , content: 'data-content'
  , template: '

'
  })

  $.fn.twipsy.rejectAttrOptions.push( 'content' )

}( window.jQuery || window.ender );


/* =========================================================
 * bootstrap-modal.js v1.4.0
 * http://twitter.github.com/bootstrap/javascript.html#modal
 * =========================================================
 * Copyright 2011 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================= */

!function( $ ){

  "use strict"

 /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
  * ======================================================= */

  var transitionEnd

  $(document).ready(function () {

    $.support.transition = (function () {
      var thisBody = document.body || document.documentElement
        , thisStyle = thisBody.style
        , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
      return support
    })()

    // set CSS transition event type
    if ( $.support.transition ) {
      transitionEnd = "TransitionEnd"
      if ( $.browser.webkit ) {
      	transitionEnd = "webkitTransitionEnd"
      } else if ( $.browser.mozilla ) {
      	transitionEnd = "transitionend"
      } else if ( $.browser.opera ) {
      	transitionEnd = "oTransitionEnd"
      }
    }

  })

 /* MODAL PUBLIC CLASS DEFINITION
  * ============================= */

  var Modal = function ( content, options ) {
    this.settings = $.extend({}, $.fn.modal.defaults, options)
    this.$element = $(content)
      .delegate('.close', 'click.modal', $.proxy(this.hide, this))

    if ( this.settings.show ) {
      this.show()
    }

    return this
  }

  Modal.prototype = {

      toggle: function () {
        return this[!this.isShown ? 'show' : 'hide']()
      }

    , show: function () {
        var that = this
        this.isShown = true
        this.$element.trigger('show')

        escape.call(this)
        backdrop.call(this, function () {
          var transition = $.support.transition && that.$element.hasClass('fade')

          that.$element
            .appendTo(document.body)
            .show()

          if (transition) {
            that.$element[0].offsetWidth // force reflow
          }

          that.$element.addClass('in')

          transition ?
            that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) :
            that.$element.trigger('shown')

        })

        return this
      }

    , hide: function (e) {
        e && e.preventDefault()

        if ( !this.isShown ) {
          return this
        }

        var that = this
        this.isShown = false

        escape.call(this)

        this.$element
          .trigger('hide')
          .removeClass('in')

        $.support.transition && this.$element.hasClass('fade') ?
          hideWithTransition.call(this) :
          hideModal.call(this)

        return this
      }

  }

 /* MODAL PRIVATE METHODS
  * ===================== */

  function hideWithTransition() {
    // firefox drops transitionEnd events :{o
    var that = this
      , timeout = setTimeout(function () {
          that.$element.unbind(transitionEnd)
          hideModal.call(that)
        }, 500)

    this.$element.one(transitionEnd, function () {
      clearTimeout(timeout)
      hideModal.call(that)
    })
  }

  function hideModal (that) {
    this.$element
      .hide()
      .trigger('hidden')

    backdrop.call(this)
  }

  function backdrop ( callback ) {
    var that = this
      , animate = this.$element.hasClass('fade') ? 'fade' : ''
    if ( this.isShown && this.settings.backdrop ) {
      var doAnimate = $.support.transition && animate

      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
        .appendTo(document.body)

      if ( this.settings.backdrop != 'static' ) {
        this.$backdrop.click($.proxy(this.hide, this))
      }

      if ( doAnimate ) {
        this.$backdrop[0].offsetWidth // force reflow
      }

      this.$backdrop.addClass('in')

      doAnimate ?
        this.$backdrop.one(transitionEnd, callback) :
        callback()

    } else if ( !this.isShown && this.$backdrop ) {
      this.$backdrop.removeClass('in')

      $.support.transition && this.$element.hasClass('fade')?
        this.$backdrop.one(transitionEnd, $.proxy(removeBackdrop, this)) :
        removeBackdrop.call(this)

    } else if ( callback ) {
       callback()
    }
  }

  function removeBackdrop() {
    this.$backdrop.remove()
    this.$backdrop = null
  }

  function escape() {
    var that = this
    if ( this.isShown && this.settings.keyboard ) {
      $(document).bind('keyup.modal', function ( e ) {
        if ( e.which == 27 ) {
          that.hide()
        }
      })
    } else if ( !this.isShown ) {
      $(document).unbind('keyup.modal')
    }
  }

 /* MODAL PLUGIN DEFINITION
  * ======================= */

  $.fn.modal = function ( options ) {
    var modal = this.data('modal')

    if (!modal) {

      if (typeof options == 'string') {
        options = {
          show: /show|toggle/.test(options)
        }
      }

      return this.each(function () {
        $(this).data('modal', new Modal(this, options))
      })
    }

    if ( options === true ) {
      return modal
    }

    if ( typeof options == 'string' ) {
      modal[options]()
    } else if ( modal ) {
      modal.toggle()
    }

    return this
  }

  $.fn.modal.Modal = Modal

  $.fn.modal.defaults = {
    backdrop: false
  , keyboard: false
  , show: false
  }

 /* MODAL DATA- IMPLEMENTATION
  * ========================== */

  $(document).ready(function () {
    $('body').delegate('[data-controls-modal]', 'click', function (e) {
      e.preventDefault()
      var $this = $(this).data('show', true)
      $('#' + $this.attr('data-controls-modal')).modal( $this.data() )
    })
  })

}( window.jQuery || window.ender );


This directory is marked read only when tests are run. Attempts to write files here should fail.


name: 'gulp',
completions: completion,
extensions: interpret.jsVariants,
nodeFlags: v8flags.fetch()
});
// exit with 0 or 1

gulp

The streaming build system

marked-man --name gulp docs/CLI.md > gulp.1

jshint lib bin index.js --reporter node_modules/jshint-stylish/stylish.js --exclude node_modules

npm run-script lint && mocha --reporter spec

istanbul cover _mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage


# Mocha test-runner with gulp

### Passing shared module in all tests

```js
// npm install gulp gulp-mocha

var gulp = require('gulp');
var mocha = require('gulp-mocha');

gulp.task('default', function() {
  return gulp.src(['test/test-*.js'], { read: false })
    .pipe(mocha({
      reporter: 'spec',
      globals: {
        should: require('should')
      }
    }));
});
```

### Running mocha tests when files change

```js
// npm install gulp gulp-mocha gulp-util

var gulp = require('gulp');
var mocha = require('gulp-mocha');
var gutil = require('gulp-util');

gulp.task('mocha', function() {
    return gulp.src(['test/*.js'], { read: false })
        .pipe(mocha({ reporter: 'list' }))
        .on('error', gutil.log);
});

gulp.task('watch-mocha', function() {
    gulp.watch(['lib/**', 'test/**'], ['mocha']);
});
```


#!/usr/bin/env fish

# Usage:
#
# To enable fish <tab> completion for gulp, add the following line to
# your ~/.config/fish/config.fish file:
#
# gulp --completion=fish | source

complete -c gulp -a "(gulp --tasks-simple)" -f


# Pass arguments from the command line

```js
// npm install --save-dev gulp gulp-if gulp-uglify minimist

var gulp = require('gulp');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var minimist = require('minimist');

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'production' }
};

var options = minimist(process.argv.slice(2), knownOptions);

gulp.task('scripts', function() {
  return gulp.src('**/*.js')
    .pipe(gulpif(options.env === 'production', uglify())) // only minify in production
    .pipe(gulp.dest('dist'));
});
```

Then run gulp with:

```sh
$ gulp scripts --env development
```


keep keep keep keep keep replace keep keep keep keep

#!/usr/bin/env node

'use strict';
var gutil = require('gulp-util');
var prettyTime = require('pretty-hrtime');
var chalk = require('chalk');
var semver = require('semver');
var archy = require('archy');
var Liftoff = require('liftoff');
var tildify = require('tildify');
var interpret = require('interpret');
var v8flags = require('v8flags');
var completion = require('../lib/completion');
var argv = require('minimist')(process.argv.slice(2));
var taskTree = require('../lib/taskTree');

// set env var for ORIGINAL cwd
// before anything touches it
process.env.INIT_CWD = process.cwd();

var cli = new Liftoff({
  name: 'gulp',
  completions: completion,
  extensions: interpret.jsVariants,
  nodeFlags: v8flags.fetch()
});

// exit with 0 or 1
var failed = false;
process.once('exit', function(code) {
  if (code === 0 && failed) {
    process.exit(1);
  }
});

// parse those args m8
var cliPackage = require('../package');
var versionFlag = argv.v || argv.version;
var tasksFlag = argv.T || argv.tasks;
var tasks = argv._;
var toRun = tasks.length ? tasks : ['default'];

// this is a hold-over until we have a better logging system
// with log levels
var simpleTasksFlag = argv['tasks-simple'];
var shouldLog = !argv.silent && !simpleTasksFlag;

if (!shouldLog) {
  gutil.log = function(){};
}

cli.on('require', function (name) {
  gutil.log('Requiring external module', chalk.magenta(name));
});

cli.on('requireFail', function (name) {
  gutil.log(chalk.red('Failed to load external module'), chalk.magenta(name));
});

cli.on('respawn', function (flags, child) {
  var nodeFlags = chalk.magenta(flags.join(', '));
  var pid = chalk.magenta(child.pid);
  gutil.log('Node flags detected:', nodeFlags);
  gutil.log('Respawned to PID:', pid);
});

cli.launch({
  cwd: argv.cwd,
  configPath: argv.gulpfile,
  require: argv.require,
  completion: argv.completion
}, handleArguments);

// the actual logic
function handleArguments(env) {
  if (versionFlag && tasks.length === 0) {
    gutil.log('CLI version', cliPackage.version);
    if (env.modulePackage && typeof env.modulePackage.version !== 'undefined') {
      gutil.log('Local version', env.modulePackage.version);
    }
    process.exit(0);
  }

  if (!env.modulePath) {
    gutil.log(
      chalk.red('Local gulp not found in'),
      chalk.magenta(tildify(env.cwd))
    );
    gutil.log(chalk.red('Try running: npm install gulp'));
    process.exit(1);
  }

  if (!env.configPath) {
    gutil.log(chalk.red('No gulpfile found'));
    process.exit(1);
  }

  // check for semver difference between cli and local installation
  if (semver.gt(cliPackage.version, env.modulePackage.version)) {
    gutil.log(chalk.red('Warning: gulp version mismatch:'));
    gutil.log(chalk.red('Global gulp is', cliPackage.version));
    gutil.log(chalk.red('Local gulp is', env.modulePackage.version));
  }

  // chdir before requiring gulpfile to make sure
  // we let them chdir as needed
  if (process.cwd() !== env.cwd) {
    process.chdir(env.cwd);
    gutil.log(
      'Working directory changed to',
      chalk.magenta(tildify(env.cwd))
    );
  }

  // this is what actually loads up the gulpfile
  require(env.configPath);
  gutil.log('Using gulpfile', chalk.magenta(tildify(env.configPath)));

  var gulpInst = require(env.modulePath);
  logEvents(gulpInst);

  process.nextTick(function () {
    if (simpleTasksFlag) {
      return logTasksSimple(env, gulpInst);
    }
    if (tasksFlag) {
      return logTasks(env, gulpInst);
    }
    gulpInst.start.apply(gulpInst, toRun);
  });
}

function logTasks(env, localGulp) {
  var tree = taskTree(localGulp.tasks);
  tree.label = 'Tasks for ' + chalk.magenta(tildify(env.configPath));
  archy(tree)
    .split('\n')
    .forEach(function (v) {
      if (v.trim().length === 0) {
        return;
      }
      gutil.log(v);
    });
}

function logTasksSimple(env, localGulp) {
  console.log(Object.keys(localGulp.tasks)
    .join('\n')
    .trim());
}

// format orchestrator errors
function formatError(e) {
  if (!e.err) {
    return e.message;
  }

  // PluginError
  if (typeof e.err.showStack === 'boolean') {
    return e.err.toString();
  }

  // normal error
  if (e.err.stack) {
    return e.err.stack;
  }

  // unknown (string, number, etc.)
  return new Error(String(e.err)).stack;
}

// wire up logging events
function logEvents(gulpInst) {

  // total hack due to poor error management in orchestrator
  gulpInst.on('err', function () {
    failed = true;
  });

  gulpInst.on('task_start', function (e) {
    // TODO: batch these
    // so when 5 tasks start at once it only logs one time with all 5
    gutil.log('Starting', '\'' + chalk.cyan(e.task) + '\'...');
  });

  gulpInst.on('task_stop', function (e) {
    var time = prettyTime(e.hrDuration);
    gutil.log(
      'Finished', '\'' + chalk.cyan(e.task) + '\'',
      'after', chalk.magenta(time)
    );
  });

  gulpInst.on('task_err', function (e) {
    var msg = formatError(e);
    var time = prettyTime(e.hrDuration);
    gutil.log(
      '\'' + chalk.cyan(e.task) + '\'',
      chalk.red('errored after'),
      chalk.magenta(time)
    );
    gutil.log(msg);
  });

  gulpInst.on('task_not_found', function (err) {
    gutil.log(
      chalk.red('Task \'' + err.task + '\' is not in your gulpfile')
    );
    gutil.log('Please check the documentation for proper gulpfile formatting');
    process.exit(1);
  });
}


# Using multiple sources in one task

```js
// npm install --save-dev gulp merge-stream

var gulp = require('gulp');
var merge = require('merge-stream');

gulp.task('test', function() {
  var bootstrap = gulp.src('bootstrap/js/*.js')
    .pipe(gulp.dest('public/bootstrap'));

  var jquery = gulp.src('jquery.cookie/jquery.cookie.js')
    .pipe(gulp.dest('public/jquery'));

  return merge(bootstrap, jquery);
});
```

`gulp.src` will emit files in the order they were added:

```js
// npm install gulp gulp-concat

var gulp = require('gulp');
var concat = require('gulp-concat');

gulp.task('default', function() {
  return gulp.src(['foo/*', 'bar/*'])
    .pipe(concat('result.txt'))
    .pipe(gulp.dest('build'));
});


# Copyright (c) 2014 Jason Jarrett
#
# Tab completion for the `gulp`
#
# Usage:
#
# To enable powershell <tab> completion for gulp you need to be running
# at least PowerShell v3 or greater and add the below to your $PROFILE
#
#     Invoke-Expression ((gulp --completion=powershell) -join [System.Environment]::NewLine)
#
#

$gulp_completion_Process = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

	# Load up an assembly to read the gulpfile's sha1
	if(-not $global:GulpSHA1Managed) {
		[Reflection.Assembly]::LoadWithPartialName("System.Security") | out-null
		$global:GulpSHA1Managed = new-Object System.Security.Cryptography.SHA1Managed
	}

	# setup a global (in-memory) cache
	if(-not $global:GulpfileShaCache) {
		$global:GulpfileShaCache = @{};
	}

	$cache = $global:GulpfileShaCache;

	# Get the gulpfile's sha1
	$sha1gulpFile = (resolve-path gulpfile.js -ErrorAction Ignore | %{
		$file = [System.IO.File]::Open($_.Path, "open", "read")
		[string]::join('', ($global:GulpSHA1Managed.ComputeHash($file) | %{ $_.ToString("x2") }))
		$file.Dispose()
	})

	# lookup the sha1 for previously cached task lists.
	if($cache.ContainsKey($sha1gulpFile)){
		$tasks = $cache[$sha1gulpFile];
	} else {
		$tasks = (gulp --tasks-simple).split("`n");
		$cache[$sha1gulpFile] = $tasks;
	}

    $tasks |
        where { $_.startswith($commandName) }
        Sort-Object |
        foreach { New-Object System.Management.Automation.CompletionResult $_, $_, 'ParameterValue', ('{0}' -f $_) }
}

if (-not $global:options) {
    $global:options = @{
        CustomArgumentCompleters = @{};
        NativeArgumentCompleters = @{}
    }
}

$global:options['NativeArgumentCompleters']['gulp'] = $gulp_completion_Process
$function:tabexpansion2 = $function:tabexpansion2 -replace 'End\r\n{','End { if ($null -ne $options) { $options += $global:options} else {$options = $global:options}'


# Dealing with streams

> It is highly recommended to write plugins supporting streams. Here is some information on creating a gulp plugin that supports streams.

> Make sure to follow the best practice regarding error handling and add the line that make the gulp plugin re-emit the first error caught during the transformation of the content

[Writing a Plugin](README.md) > Writing stream based plugins

## Dealing with streams

Let's implement a plugin prepending some text to files. This plugin supports all possible forms of file.contents.

```js
var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;

// consts
const PLUGIN_NAME = 'gulp-prefixer';

function prefixStream(prefixText) {
  var stream = through();
  stream.write(prefixText);
  return stream;
}

// plugin level function (dealing with files)
function gulpPrefixer(prefixText) {
  if (!prefixText) {
    throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
  }

  prefixText = new Buffer(prefixText); // allocate ahead of time

  // creating a stream through which each file will pass
  var stream = through.obj(function(file, enc, cb) {
    if (file.isBuffer()) {
      this.emit('error', new PluginError(PLUGIN_NAME, 'Buffers not supported!'));
      return cb();
    }

    if (file.isStream()) {
      // define the streamer that will transform the content
      var streamer = prefixStream(prefixText);
      // catch errors from the streamer and emit a gulp plugin error
      streamer.on('error', this.emit.bind(this, 'error'));
      // start the transformation
      file.contents = file.contents.pipe(streamer);
    }

    // make sure the file goes through the next gulp plugin
    this.push(file);
    // tell the stream engine that we are done with this file
    cb();
  });

  // returning the file stream
  return stream;
}

// exporting the plugin main function
module.exports = gulpPrefixer;
```

The above plugin can be used like this:

```js
var gulp = require('gulp');
var gulpPrefixer = require('gulp-prefixer');

gulp.src('files/**/*.js', { buffer: false })
  .pipe(gulpPrefixer('prepended string'))
  .pipe(gulp.dest('modified-files'));
```

## Some plugins using streams

* [gulp-svgicons2svgfont](https://github.com/nfroidure/gulp-svgiconstosvgfont)


keep keep keep keep keep replace keep keep keep keep keep

The streaming build system


#!/bin/zsh

# Borrowed from grunt-cli
# http://gruntjs.com/
#
# Copyright (c) 2012 Tyler Kellen, contributors
# Licensed under the MIT license.
# https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT

# Usage:
#
# To enable zsh <tab> completion for gulp, add the following line (minus the
# leading #, which is the zsh comment character) to your ~/.zshrc file:
#
# eval "$(gulp --completion=zsh)"

# Enable zsh autocompletion.
function _gulp_completion() {
  # Grab tasks
  compls=$(gulp --tasks-simple)
  completions=(${=compls})
  compadd -- $completions
}

compdef _gulp_completion gulp


'use strict';

module.exports = function (tasks) {
  return Object.keys(tasks)
    .reduce(function (prev, task) {
      prev.nodes.push({
        label: task,
        nodes: tasks[task].dep
      });
      return prev;
    }, {
      nodes: []
    });
};


# Combining streams to handle errors

By default, emitting an error on a stream will cause it to be thrown unless it already has a listener attached to the `error` event. This gets a bit tricky when you're working with longer pipelines of streams.

By using [stream-combiner2](https://github.com/substack/stream-combiner2) you can turn a series of streams into a single stream, meaning you only need to listen to the `error` event in one place in your code.

Here's an example of using it in a gulpfile:

```js
var combiner = require('stream-combiner2');
var uglify = require('gulp-uglify');
var gulp = require('gulp');

gulp.task('test', function() {
  var combined = combiner.obj([
    gulp.src('bootstrap/js/*.js'),
    uglify(),
    gulp.dest('public/bootstrap')
  ]);

  // any errors in the above streams will get caught
  // by this listener, instead of being thrown:
  combined.on('error', console.error.bind(console));

  return combined;
});
```


* @param {string} id The ID of the command.

* @param {function} command The function to call when the command is executed. Any arguments passed to

*     execute() (after the id) are passed as arguments to the function. If the function is asynchronous,

*     it must return a jQuery Deferred that is resolved when the command completes. Otherwise, the

*     CommandManager will assume it is synchronous, and return a Deferred that is already resolved.

keep keep keep replace keep keep keep keep

* @param {function(...)} command The function to call when the command is executed. Any arguments passed to

/*
 * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved.
 */
define(function(require, exports, module) {

    // TODO: Determine proper public/private API for this module, splitting into separate modules as needed

    var NativeFileSystem = {

        /** showOpenDialog
         *
         * @param {bool} allowMultipleSelection
         * @param {bool} chooseDirectories
         * @param {string} title
         * @param {string} initialPath
         * @param {string[]} fileTypes
         * @param {function} resultCallback
         * @constructor
         */
        showOpenDialog: function (  allowMultipleSelection,
                                    chooseDirectories,
                                    title,
                                    initialPath,
                                    fileTypes,
                                    successCallback,
                                    errorCallback )
        {
            if( !successCallback )
                return;

            var files = brackets.fs.showOpenDialog( allowMultipleSelection,
                chooseDirectories,
                title,
                initialPath,
                fileTypes,
                function( err, data ) {
                    if( ! err )
                        successCallback( data );
                    else if (errorCallback)
                        errorCallback(NativeFileSystem._nativeToFileError(err));
                });
        },

        /** requestNativeFileSystem
         *
         * @param {string} path
         * @param {function} successCallback
         * @param {function} errorCallback
         */
        requestNativeFileSystem: function( path, successCallback, errorCallback ){
            brackets.fs.stat(path, function( err, data ){
                if( !err ){
                    var root = new NativeFileSystem.DirectoryEntry( path );
                    successCallback( root );
                }
                else if (errorCallback) {
                    errorCallback(NativeFileSystem._nativeToFileError(err));
                }
            });
        },

        _nativeToFileError: function(nativeErr) {
            // The HTML file spec says SECURITY_ERR is a catch-all to be used in situations
            // not covered by other error codes.
            var error = FileError.SECURITY_ERR;

            switch (nativeErr) {
                // We map ERR_UNKNOWN and ERR_INVALID_PARAMS to SECURITY_ERR,
                // since there aren't specific mappings for these.
                case brackets.fs.ERR_UNKNOWN:
                case brackets.fs.ERR_INVALID_PARAMS:
                    error = FileError.SECURITY_ERR;
                    break;
                case brackets.fs.ERR_NOT_FOUND:
                    error = FileError.NOT_FOUND_ERR;
                    break;
                case brackets.fs.ERR_CANT_READ:
                    error = FileError.NOT_READABLE_ERR;
                    break;
                // It might seem like you should use FileError.ENCODING_ERR for this,
                // but according to the spec that's for malformed URLs.
                case brackets.fs.ERR_UNSUPPORTED_ENCODING:
                    error = FileError.SECURITY_ERR;
                    break;
                case brackets.fs.ERR_CANT_WRITE:
                    error = FileError.NO_MODIFICATION_ALLOWED_ERR;
                    break;
                case brackets.fs.ERR_OUT_OF_SPACE:
                    error = FileError.QUOTA_EXCEEDED_ERR;
                    break;
                case brackets.fs.PATH_EXISTS_ERR:
                    error = FileError.PATH_EXISTS_ERR;
                    break;
            }
            return new NativeFileSystem.FileError(error);
        }
    };

    /** class: Entry
     *
     * @param {string} name
     * @param {string} isFile
     * @constructor
     */
    NativeFileSystem.Entry = function( fullPath, isDirectory) {
        this.isDirectory = isDirectory;
        this.isFile = !isDirectory;
        // IMPLEMENT LATER void      getMetadata (MetadataCallback successCallback, optional ErrorCallback errorCallback);
        this.fullPath = fullPath;

        // Extract name from fullPath
        this.name = null; // default if extraction fails
        if( fullPath ){
            var pathParts = fullPath.split( "/" );
            if( pathParts.length > 0 )
                this.name = pathParts.pop();
        }

        // IMPLEMENT LATER var filesystem;
        // IMPLEMENT LATER void      moveTo (DirectoryEntry parent, optional DOMString newName, optional EntryCallback successCallback, optional ErrorCallback errorCallback);
        // IMPLEMENT LATER void      copyTo (DirectoryEntry parent, optional DOMString newName, optional EntryCallback successCallback, optional ErrorCallback errorCallback);
        // IMPLEMENT LATER DOMString toURL (optional DOMString mimeType);
        // IMPLEMENT LATER void      remove (VoidCallback successCallback, optional ErrorCallback errorCallback);
        // IMPLEMENT LATER void      getParent (EntryCallback successCallback, optional ErrorCallback errorCallback);
    };

    /**
     * This interface represents a file on a file system.
     *
     * @param {string} name
     * @constructor
     * @extends {Entry}
     */
    NativeFileSystem.FileEntry = function( name ) {
        NativeFileSystem.Entry.call(this, name, false);

        // TODO: make FileEntry actually inherit from Entry by modifying prototype. I don't know how to do this yet.

    };

    /**
     * Creates a new FileWriter associated with the file that this FileEntry represents.
     *
     * @param {function(_FileWriter)} successCallback
     * @param {function(FileError)} errorCallback
     */
    NativeFileSystem.FileEntry.prototype.createWriter = function( successCallback, errorCallback ) {
        var fileEntry = this;

        // [NoInterfaceObject]
        // interface FileWriter : FileSaver
        var _FileWriter = function( data ) {
            NativeFileSystem.FileSaver.call(this, data);

            // _FileWriter private memeber vars
            this._length = 0;
            this._position = 0;

            // initialize file length
            // TODO (jasonsj): handle async
            var self = this;

            brackets.fs.readFile( fileEntry.fullPath, "utf8", function(err, contents) {
                self._err = err;

                if ( contents )
                    self._length = contents.length;
            });
        };

        _FileWriter.prototype.length = function( ) {
            return this._length;
        };

        _FileWriter.prototype.position = function( ) {
            return this._position;
        };

        // TODO (jasonsj): handle Blob data instead of string
        _FileWriter.prototype.write = function( data ) {
            if ( data === undefined )
                throw new Error();

            if ( this.readyState === NativeFileSystem.FileSaver.WRITING )
                throw new NativeFileSystem.FileException( NativeFileSystem.FileException.INVALID_STATE_ERR );

            this._readyState = NativeFileSystem.FileSaver.WRITING;

            if ( this.onwritestart ) {
                // TODO (jasonsj): progressevent
                this.onwritestart();
            }

            var self = this;

            brackets.fs.writeFile( fileEntry.fullPath, data, "utf8", function( err ) {
                var fileError = null;

                if ( ( err != brackets.fs.NO_ERROR ) && self.onerror ) {
                    fileError = NativeFileSystem._nativeToFileError( err );

                    // TODO (jasonsj): set readonly FileSaver.error attribute
                    // self._error = fileError;

                    self.onerror ( fileError );

                    // TODO (jasonsj): partial write, update length and position
                }
                else {
                    // TODO (jasonsj): After changing data argument to Blob, use
                    // Blob.size to update position and length upon successful
                    // completion of a write.

                    // self.position = ;
                    // self.length = ;
                }

                // DONE is set regardless of error
                this._readyState = NativeFileSystem.FileSaver.DONE;

                if ( self.onwrite ) {
                    // TODO (jasonsj): progressevent
                    self.onwrite();
                }

                if ( self.onwriteend ) {
                    // TODO (jasonsj): progressevent
                    self.onwriteend();
                }
            });
        };

        _FileWriter.prototype.seek = function( offset ) {
        };

        _FileWriter.prototype.truncate = function( size ) {
        };

        var fileWriter = new _FileWriter();

        if ( fileWriter._err && ( errorCallback !== undefined ) ) {
            errorCallback( NativeFileSystem._nativeToFileError( fileWriter._err ) );
        }
        else if ( successCallback !== undefined ) {
            successCallback( fileWriter );
        }
    };

    /**
     * This interface extends the FileException interface described in to add
     * several new error codes. Any errors that need to be reported synchronously,
     * including all that occur during use of the synchronous filesystem methods,
     * are reported using the FileException exception.
     *
     * @param {number} code The code attribute, on getting, must return one of the
     * constants of the FileException exception, which must be the most appropriate
     * code from the table below.
     */
    NativeFileSystem.FileException = function ( code ){
        this.code = code || 0;
    };

    // FileException constants
    Object.defineProperties(NativeFileSystem.FileException,
        { NOT_FOUND_ERR:                { value: 1, writable: false }
        , SECURITY_ERR:                 { value: 2, writable: false }
        , ABORT_ERR:                    { value: 3, writable: false }
        , NOT_READABLE_ERR:             { value: 4, writable: false }
        , ENCODING_ERR:                 { value: 5, writable: false }
        , NO_MODIFICATION_ALLOWED_ERR:  { value: 6, writable: false }
        , INVALID_STATE_ERR:            { value: 7, writable: false }
        , SYNTAX_ERR:                   { value: 8, writable: false }
        , QUOTA_EXCEEDED_ERR:           { value: 10, writable: false }
    });

    /**
     * This interface provides methods to monitor the asynchronous writing of blobs
     * to disk using progress events and event handler attributes.
     *
     * This interface is specified to be used within the context of the global
     * object (Window) and within Web Workers.
     *
     * @param {Blob} data
     * @constructor
     */
    NativeFileSystem.FileSaver = function( data ) {
        // FileSaver private member vars
        this._data = data;
        this._readyState = NativeFileSystem.FileSaver.INIT;
        this._error = null;
    };

    // FileSaver constants
    Object.defineProperties(NativeFileSystem.FileSaver,
        { INIT:     { value: 1, writable: false }
        , WRITING:  { value: 2, writable: false }
        , DONE:     { value: 3, writable: false }
    });

    // FileSaver methods

    /**
     *
     */
    NativeFileSystem.FileSaver.prototype.readyState = function() {
        return this._readyState;
    }

    // TODO (jasonsj): http://dev.w3.org/2009/dap/file-system/file-writer.html#widl-FileSaver-abort-void
    NativeFileSystem.FileSaver.prototype.abort = function() {
        // If readyState is DONE or INIT, terminate this overall series of steps without doing anything else..
        if (_readyState == FileSaver.INIT || _readyState == FileSaver.DONE)
        return;

        // Terminate any steps having to do with writing a file.

        // Set the error attribute to a FileError object with the code ABORT_ERR.
        _error = new NativeFileSystem.FileError(FileError.ABORT_ERR);

        // Set readyState to DONE.
        _readyState = FileSaver.DONE;

        // Dispatch a progress event called abort
        // Dispatch a progress event called writeend
        // Stop dispatching any further progress events.
        // Terminate this overall set of steps.

        return err;
    };

    /**
     * Obtains the File objecte for a FileEntry object
     *
     * @param {function} successCallback
     * @param {function} errorCallback
     */
    NativeFileSystem.FileEntry.prototype.file = function( successCallback, errorCallback ){
        var newFile = new NativeFileSystem.File( this );
        successCallback( newFile );

        // TODO Ty: error handling
        // errorCallback
    };

    /*
    TODO Jason
    NativeFileSystem.FileEntry.prototype.createfileerror = function( successCallback, errorCallback ){
    };
    */

    /**
     * This interface represents a directory on a file system.
     *
     * @constructor
     * @param {string} name
     * @extends {Entry}
     */
    NativeFileSystem.DirectoryEntry = function( name ) {
        NativeFileSystem.Entry.call(this, name, true);

        // TODO: make DirectoryEntry actually inherit from Entry by modifying prototype. I don't know how to do this yet.

        // IMPLEMENT LATERvoid            getDirectory (DOMString path, optional Flags options, optional EntryCallback successCallback, optional ErrorCallback errorCallback);
        // IMPLEMENT LATERvoid            removeRecursively (VoidCallback successCallback, optional ErrorCallback errorCallback);
    };

    NativeFileSystem.DirectoryEntry.prototype.createReader = function() {
        var dirReader = new NativeFileSystem.DirectoryReader();
        dirReader._directory = this;

        return dirReader;
    };

    /**
     * Creates or looks up a file.
     *
     * @param {string} path Either an absolute path or a relative path from this
     *        DirectoryEntry to the file to be looked up or created. It is an error
     *        to attempt to create a file whose immediate parent does not yet
     *        exist.
     * @param {Object.<string, boolean>} options
     * @param {function(number)} successCallback
     * @param {function(number)} errorCallback
     */
    NativeFileSystem.DirectoryEntry.prototype.getFile = function( path, options, successCallback, errorCallback ) {
        // TODO (jasonsj): handle absolute paths
        var fileFullPath = this.fullPath + "/" + path;

        var createFileEntry = function () {
            if ( successCallback ) {
                successCallback( new NativeFileSystem.FileEntry( fileFullPath ) );
            }
        }

        var createFileError = function ( err ) {
            if ( errorCallback ) {
                errorCallback( NativeFileSystem._nativeToFileError( err ) );
            }
        }

        // Use stat() to check if file exists
        brackets.fs.stat( fileFullPath, function( err, stats ) {
            if ( ( err === brackets.fs.NO_ERROR ) ) {
                // NO_ERROR implies the path already exists

                // throw error if the file the path is a directory
                if ( stats.isDirectory() ) {
                    if ( errorCallback ) {
                        errorCallback( new NativeFileSystem.FileError( FileError.TYPE_MISMATCH_ERR ) );
                    }

                    return;
                }

                // throw error if the file exists but create is exclusive
                if ( options.create && options.exclusive ) {
                    if ( errorCallback ) {
                        errorCallback( new NativeFileSystem.FileError( FileError.PATH_EXISTS_ERR ) );
                    }

                    return;
                }

                // Create a file entry for the existing file. If create == true,
                // a file entry is created without error.
                createFileEntry();
            } else if ( err === brackets.fs.ERR_NOT_FOUND ) {
                // ERR_NOT_FOUND implies we write a new, empty file

                // create the file
                if ( options.create ) {
                    brackets.fs.writeFile( fileFullPath, "", "utf8", function( err ) {
                        if ( err )
                            createFileError( err );
                        else
                            createFileEntry();
                    });

                    return;
                }

                // throw error if file not found and the create == false
                if ( errorCallback ) {
                    errorCallback( new NativeFileSystem.FileError( FileError.NOT_FOUND_ERR ) );
                }
            } else {
                // all other brackets.fs.stat() errors
                createFileError( err );
            }
        });
    };

    /** class: DirectoryReader
     */
    NativeFileSystem.DirectoryReader = function() {

    };

    /** readEntries
     *
     * @param {function} successCallback
     * @param {function} errorCallback
     * @returns {Entry[]}
     */
    NativeFileSystem.DirectoryReader.prototype.readEntries = function( successCallback, errorCallback ){
        var rootPath = this._directory.fullPath;
        var jsonList = brackets.fs.readdir( rootPath, function( err, filelist ) {
            if( ! err ){
                // Create entries for each name
                var entries = [];
    			var statErr;
    			for( var i = 0; i < filelist.length; i++ ){
    				var item = filelist[i];
                    var itemFullPath = rootPath + "/" + item;

                    brackets.fs.stat( itemFullPath, function( statErr, statData) {

                        if( !statErr ){
                            if( statData.isDirectory() )
                                entries.push( new NativeFileSystem.DirectoryEntry( itemFullPath ) );
                            else if( statData.isFile() )
                                entries.push( new NativeFileSystem.FileEntry( itemFullPath ) );
                        }
                        else if (errorCallback) {
                            errorCallback(NativeFileSystem._nativeToFileError(statErr));
                        }

                    });

    				// exit loop if there is an error
    				if( statErr )
    					break;
                }

    			if( !statErr )
    				successCallback( entries );
    			else
    				 errorCallback(NativeFileSystem._nativeToFileError(statErr));
            }
            else if (errorCallback) {
                errorCallback(NativeFileSystem._nativeToFileError(err));
            }
        });
    };

    /** class: FileReader
     *
     * @extends {EventTarget}
     */
    NativeFileSystem.FileReader = function() {
        // Todo Ty: this classes should extend EventTarget

        // async read methods
        // IMPLEMENT LATER void readAsArrayBuffer(Blob blob);
        // IMPLEMENT LATER void readAsBinaryString(Blob blob);
        // IMPLEMENT LATER void readAsDataURL(Blob blob);

        // IMPLEMENT LATER void abort();

        // states
        this.EMPTY = 0;
        this.LOADING = 1;
        this.DONE = 2;

        // readyState is read only
        this.readyState = this.EMPTY;

        // File or Blob data
        // IMPLEMENT LATER readonly attribute any result;
        // IMPLEMENT LATER readonly attribute DOMError error;

        // event handler attributes
        this.onloadstart = null;
        this.onprogress = null;
        this.onload = null;
        this.onabort = null;
        this.onerror = null;
        this.onloadend = null;

    };

    /** readAsText
     *
     * @param {Blob} blob
     * @param {string} encoding
     */
    NativeFileSystem.FileReader.prototype.readAsText = function( blob, encoding) {
        var self = this;

        if( !encoding )
            encoding = "utf-8";

        if( this.readyState == this.LOADING )
            throw new InvalidateStateError();

        this.readyState = this.LOADING;

        if( this.onloadstart )
            this.onloadstart(); // todo params

        brackets.fs.readFile( blob._fullPath, encoding, function( err, data) {

            // TODO: the event objects passed to these event handlers is fake and incomplete right now
            var fakeEvent =
                { loaded: 0
                , total: 0
                };

            // The target for this event is the FileReader and the data/err result is stored in the FileReader
            fakeEvent.target = this;
            this.result = data;
            this.error = NativeFileSystem._nativeToFileError(err);;

            if( err ){
                this.readyState = this.DONE;
                if( self.onerror ){
                    self.onerror(fakeEvent);
                }
            }
            else{
                this.readyState = this.DONE;

                // TODO: this should be the file/blob size, but we don't have code to get that yet, so for know assume a file size of 1
                // and since we read the file in one go, assume 100% after the first read
                fakeEvent.loaded = 1;
                fakeEvent.total = 1;

                if( self.onprogress )
                    self.onprogress(fakeEvent);

                // TODO: this.onabort not currently supported since our native implementation doesn't support it
                // if( self.onabort )
                //    self.onabort(fakeEvent);

                if( self.onload )
                    self.onload( fakeEvent );

                if( self.onloadend )
                    self.onloadend();
            }

        });
    };

    /** class: Blob
     *
     * @constructor
     * param {Entry} entry
     */
    NativeFileSystem.Blob = function ( fullPath ){
        this._fullPath = fullPath;

        // IMPLEMENT LATER readonly attribute unsigned long long size;
        // IMPLEMENT LATER readonly attribute DOMString type;

        //slice Blob into byte-ranged chunks

        // IMPLEMENT LATER Blob slice(optional long long start,
        //           optional long long end,
        //           optional DOMString contentType);
    };

    /** class: File
     *
     * @constructor
     * param {Entry} entry
     * @extends {Blob}
     */
    NativeFileSystem.File = function ( entry ){
        NativeFileSystem.Blob.call( this, entry.fullPath );

        // IMPLEMENT LATER get name() { return this.entry.name; }
        // IMPLEMENT LATER get lastModifiedDate() { return } use stat to get mod date
    };

    /** class: FileError
     *
     * Implementation of HTML file API error code return class. Note that we don't
     * actually define the error codes here--we rely on the browser's built-in FileError
     * class's constants. In other words, external clients of this API should always
     * use FileError.<constant-name>, not NativeFileSystem.FileError.<constant-name>.
     *
     * @constructor
     * @param {number} code The error code to return with this FileError. Must be
     * one of the codes defined in the FileError class.
     */
    NativeFileSystem.FileError = function( code ) {
        this.code = code || 0;
    };

    // Define public API
    exports.NativeFileSystem = NativeFileSystem;
});


This directory is marked write only when tests are run. Attempts to read files here should fail.


define(function(require, exports, module) {

    function getTestRoot() {
        // /path/to/brackets/test/SpecRunner.html
        var path = window.location.href;
        path = path.substr("file://".length);
        path = path.substr(0,path.lastIndexOf("/"));

        return path;
    }

    function getTestPath(path) {
        return getTestRoot() + path;
    }

    function getBracketsSourceRoot() {
        var path = window.location.href;
        path = path.substr("file://".length).split("/");
        path = path.slice(0, length - 2);
        path.push("src");
        return path.join("/");
    }

    exports.getTestRoot             = getTestRoot;
    exports.getTestPath             = getTestPath;
    exports.getBracketsSourceRoot   = getBracketsSourceRoot;
});


/* Variables.less
 * Variables to customize the look and feel of Bootstrap
 * ----------------------------------------------------- */

// Links
@linkColor:         #0069d6;
@linkColorHover:    darken(@linkColor, 15);

// Grays
@black:             #000;
@grayDark:          lighten(@black, 25%);
@gray:              lighten(@black, 50%);
@grayLight:         lighten(@black, 75%);
@grayLighter:       lighten(@black, 90%);
@white:             #fff;

// Accent Colors
@blue:              #049CDB;
@blueDark:          #0064CD;
@green:             #46a546;
@red:               #9d261d;
@yellow:            #ffc40d;
@orange:            #f89406;
@pink:              #c3325f;
@purple:            #7a43b6;

// Baseline grid
@basefont:          13px;
@baseline:          18px;

// Griditude
// Modify the grid styles in mixins.less
@gridColumns:       16;
@gridColumnWidth:   40px;
@gridGutterWidth:   20px;
@extraSpace:        (@gridGutterWidth * 2); // For our grid calculations
@siteWidth:         (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));

// Color Scheme
// Use this to roll your own color schemes if you like (unused by Bootstrap by default)
@baseColor:         @blue;                  // Set a base color
@complement:        spin(@baseColor, 180);  // Determine a complementary color
@split1:            spin(@baseColor, 158);  // Split complements
@split2:            spin(@baseColor, -158);
@triad1:            spin(@baseColor, 135);  // Triads colors
@triad2:            spin(@baseColor, -135);
@tetra1:            spin(@baseColor, 90);   // Tetra colors
@tetra2:            spin(@baseColor, -90);
@analog1:           spin(@baseColor, 22);   // Analogs colors
@analog2:           spin(@baseColor, -22);

// More variables coming soon:
// - @basefont to @baseFontSize
// - @baseline to @baseLineHeight
// - @baseFontFamily
// - @primaryButtonColor
// - anything else? File an issue on GitHub


showOpenDialog: function (  allowMultipleSelection,

keep keep keep replace replace keep keep keep keep keep

* @param {function(...)} successCallback


/* Useful mixins */

.box {
	display: -webkit-box;
	display: -moz-box;
	display: box;
}
.hbox {
	.box;
	-webkit-box-orient: horizontal;
	-moz-box-orient: horizontal;
	box-orient: horizontal;
}
.vbox {
	.box;
	-webkit-box-orient: vertical;
	-moz-box-orient: vertical;
	box-orient: vertical;
}
.box-flex(@ratio) {
	-webkit-box-flex: @ratio;
	-moz-box-flex: @ratio;
	box-flex: @ratio;
}
.box-pack(@pack) {
	-webkit-box-pack: @pack;
	-moz-box-pack: @pack;
	box-pack: @pack;
}
.box-align(@align) {
	-webkit-box-align: @align;
	-moz-box-align: @align;
	box-align: @align;
}

.sane-box-model {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;
}

/* Variables */

/* All paddings, gutters, etc. should be multiples of this */
@base-padding: 10px;

/* Path prefix for all images used in our CSS. (Note: unlike a normal CSS file, in runtime-processed
   LESS, image URLs are relative to the .html file, NOT to the .less file) */
@img: "styles/images";

/* General styles for Brackets elements */

.panel {
	.vbox;
	.box-flex(1);

	padding: 0;
	margin: 0;
	background: #d8e0e8;
	border-right: 1px solid #aaa;
}

.toolbar {
	.hbox;
	.box-align(center);

	height: 23px;
	padding: @base-padding;
  	border-bottom: 1px solid #aaa;
	#gradient > .vertical(#eee, #ccc);
	.box-shadow(0 1px 3px 0 rgba(0, 0, 0, 0.3));
}

.modal-footer .btn.left {
    float: left;
}

/* Overall layout */

html, body {
	height: 100%;
	overflow: auto;
}

body {
	.vbox;

	.topbar {
		position: static;
	}
}

.topbar-inner {
	/* We don't want to use the default .container in here, so we need to .clearfix the children. */
	.clearfix;

	.brand {
		.sane-box-model;
		margin-left: 0;
		width: 200px;
		padding-left: @base-padding;
		padding-right: @base-padding;
	}
}

.main-view {
	.hbox;
	.box-flex(1);

	.sidebar {
		.vbox;
		width: 200px;
	}

	.content {
		.vbox;
		.box-flex(1);
	}
}

/* #main-toolbar { */
.toolbar {
	/* make sure the shadow goes above other items */
	z-index: 1;
	.title {
		font-size: 1.2em;
		font-weight: bold;
		text-shadow: 0 1px #fff;
	}
	.buttons {
		float: right;
	}
}

#editor {
	.vbox;
	.box-flex(1);

	.CodeMirror {
		.vbox;
		.box-flex(1);
	}
	.CodeMirror-scroll {
		.box;
		.box-flex(1);
	}
	.CodeMirror-lines {
		padding: @base-padding;
	}
}

/* Project panel */

#projects .toolbar {
	.picker {
		.box;
		.box-flex(1);
	}
}

#project-files-container {
	.box-flex(1);
	margin: 0;
  	padding: 0;
	overflow: auto; /* show scrollbars */

	> ul {
		margin-top: 5px;
	}
}