async

Higher-order functions and common patterns for asynchronous code

# Async.js

Async is a utility module which provides straight-forward, powerful functions
for working with asynchronous JavaScript. Although originally designed for
use with [node.js](http://nodejs.org), it can also be used directly in the
browser. Also supports [component](https://github.com/component/component).

Async provides around 20 functions that include the usual 'functional'
suspects (map, reduce, filter, each…) as well as some common patterns
for asynchronous control flow (parallel, series, waterfall…). All these
functions assume you follow the node.js convention of providing a single
callback as the last argument of your async function.

## Quick Examples

```javascript
async.map(['file1','file2','file3'], fs.stat, function(err, results){
    // results is now an array of stats for each file
});

async.filter(['file1','file2','file3'], fs.exists, function(results){
    // results now equals an array of the existing files
});

async.parallel([
    function(){ ... },
    function(){ ... }
], callback);

async.series([
    function(){ ... },
    function(){ ... }
]);
```

There are many more functions available so take a look at the docs below for a
full list. This module aims to be comprehensive, so if you feel anything is
missing please create a GitHub issue for it.

## Common Pitfalls

### Binding a context to an iterator

This section is really about bind, not about async. If you are wondering how to
make async execute your iterators in a given context, or are confused as to why
a method of another library isn't working as an iterator, study this example:

```js
// Here is a simple object with an (unnecessarily roundabout) squaring method
var AsyncSquaringLibrary = {
  squareExponent: 2,
  square: function(number, callback){
    var result = Math.pow(number, this.squareExponent);
    setTimeout(function(){
      callback(null, result);
    }, 200);
  }
};

async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result){
  // result is [NaN, NaN, NaN]
  // This fails because the `this.squareExponent` expression in the square
  // function is not evaluated in the context of AsyncSquaringLibrary, and is
  // therefore undefined.
});

async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result){
  // result is [1, 4, 9]
  // With the help of bind we can attach a context to the iterator before
  // passing it to async. Now the square function will be executed in its
  // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent`
  // will be as expected.
});
```

## Download

The source is available for download from
[GitHub](http://github.com/caolan/async).
Alternatively, you can install using Node Package Manager (npm):

    npm install async

__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 29.6kb Uncompressed

## In the Browser

So far it's been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:

```html
<script type="text/javascript" src="async.js"></script>
<script type="text/javascript">

    async.map(data, asyncProcess, function(err, results){
        alert(results);
    });

</script>
```

## Documentation

### Collections

* [each](#each)
* [map](#map)
* [filter](#filter)
* [reject](#reject)
* [reduce](#reduce)
* [detect](#detect)
* [sortBy](#sortBy)
* [some](#some)
* [every](#every)
* [concat](#concat)

### Control Flow

* [series](#series)
* [parallel](#parallel)
* [whilst](#whilst)
* [doWhilst](#doWhilst)
* [until](#until)
* [doUntil](#doUntil)
* [forever](#forever)
* [waterfall](#waterfall)
* [compose](#compose)
* [applyEach](#applyEach)
* [queue](#queue)
* [cargo](#cargo)
* [auto](#auto)
* [iterator](#iterator)
* [apply](#apply)
* [nextTick](#nextTick)
* [times](#times)
* [timesSeries](#timesSeries)

### Utils

* [memoize](#memoize)
* [unmemoize](#unmemoize)
* [log](#log)
* [dir](#dir)
* [noConflict](#noConflict)

## Collections

### each(arr, iterator, callback)

Applies an iterator function to each item in an array, in parallel.
The iterator is called with an item from the list and a callback for when it
has finished. If the iterator passes an error to this callback, the main
callback for the each function is immediately called with the error.

Note, that since this function applies the iterator to each item in parallel
there is no guarantee that the iterator functions will complete in order.

__Arguments__

* arr - An array to iterate over.
* iterator(item, callback) - A function to apply to each item in the array.
  The iterator is passed a callback(err) which must be called once it has
  completed. If no error has occured, the callback should be run without
  arguments or with an explicit null argument.
* callback(err) - A callback which is called after all the iterator functions
  have finished, or an error has occurred.

__Example__

```js
// assuming openFiles is an array of file names and saveFile is a function
// to save the modified contents of that file:

async.each(openFiles, saveFile, function(err){
    // if any of the saves produced an error, err would equal that error
});
```

---------------------------------------

### eachSeries(arr, iterator, callback)

The same as each only the iterator is applied to each item in the array in
series. The next iterator is only called once the current one has completed
processing. This means the iterator functions will complete in order.

---------------------------------------

### eachLimit(arr, limit, iterator, callback)

The same as each only no more than "limit" iterators will be simultaneously
running at any time.

Note that the items are not processed in batches, so there is no guarantee that
 the first "limit" iterator functions will complete before any others are
started.

__Arguments__

* arr - An array to iterate over.
* limit - The maximum number of iterators to run at any time.
* iterator(item, callback) - A function to apply to each item in the array.
  The iterator is passed a callback(err) which must be called once it has
  completed. If no error has occured, the callback should be run without
  arguments or with an explicit null argument.
* callback(err) - A callback which is called after all the iterator functions
  have finished, or an error has occurred.

__Example__

```js
// Assume documents is an array of JSON objects and requestApi is a
// function that interacts with a rate-limited REST api.

async.eachLimit(documents, 20, requestApi, function(err){
    // if any of the saves produced an error, err would equal that error
});
```

---------------------------------------

### map(arr, iterator, callback)

Produces a new array of values by mapping each value in the given array through
the iterator function. The iterator is called with an item from the array and a
callback for when it has finished processing. The callback takes 2 arguments,
an error and the transformed item from the array. If the iterator passes an
error to this callback, the main callback for the map function is immediately
called with the error.

Note, that since this function applies the iterator to each item in parallel
there is no guarantee that the iterator functions will complete in order, however
the results array will be in the same order as the original array.

__Arguments__

* arr - An array to iterate over.
* iterator(item, callback) - A function to apply to each item in the array.
  The iterator is passed a callback(err, transformed) which must be called once
  it has completed with an error (which can be null) and a transformed item.
* callback(err, results) - A callback which is called after all the iterator
  functions have finished, or an error has occurred. Results is an array of the
  transformed items from the original array.

__Example__

```js
async.map(['file1','file2','file3'], fs.stat, function(err, results){
    // results is now an array of stats for each file
});
```

---------------------------------------

### mapSeries(arr, iterator, callback)

The same as map only the iterator is applied to each item in the array in
series. The next iterator is only called once the current one has completed
processing. The results array will be in the same order as the original.

---------------------------------------

### mapLimit(arr, limit, iterator, callback)

The same as map only no more than "limit" iterators will be simultaneously
running at any time.

Note that the items are not processed in batches, so there is no guarantee that
 the first "limit" iterator functions will complete before any others are
started.

__Arguments__

* arr - An array to iterate over.
* limit - The maximum number of iterators to run at any time.
* iterator(item, callback) - A function to apply to each item in the array.
  The iterator is passed a callback(err, transformed) which must be called once
  it has completed with an error (which can be null) and a transformed item.
* callback(err, results) - A callback which is called after all the iterator
  functions have finished, or an error has occurred. Results is an array of the
  transformed items from the original array.

__Example__

```js
async.map(['file1','file2','file3'], 1, fs.stat, function(err, results){
    // results is now an array of stats for each file
});
```

---------------------------------------

### filter(arr, iterator, callback)

__Alias:__ select

Returns a new array of all the values which pass an async truth test.
_The callback for each iterator call only accepts a single argument of true or
false, it does not accept an error argument first!_ This is in-line with the
way node libraries work with truth tests like fs.exists. This operation is
performed in parallel, but the results array will be in the same order as the
original.

__Arguments__

* arr - An array to iterate over.
* iterator(item, callback) - A truth test to apply to each item in the array.
  The iterator is passed a callback(truthValue) which must be called with a
  boolean argument once it has completed.
* callback(results) - A callback which is called after all the iterator
  functions have finished.

__Example__

```js
async.filter(['file1','file2','file3'], fs.exists, function(results){
    // results now equals an array of the existing files
});
```

---------------------------------------

### filterSeries(arr, iterator, callback)

__alias:__ selectSeries

The same as filter only the iterator is applied to each item in the array in
series. The next iterator is only called once the current one has completed
processing. The results array will be in the same order as the original.

---------------------------------------

### reject(arr, iterator, callback)

The opposite of filter. Removes values that pass an async truth test.

---------------------------------------

### rejectSeries(arr, iterator, callback)

The same as reject, only the iterator is applied to each item in the array
in series.

---------------------------------------

### reduce(arr, memo, iterator, callback)

__aliases:__ inject, foldl

Reduces a list of values into a single value using an async iterator to return
each successive step. Memo is the initial state of the reduction. This
function only operates in series. For performance reasons, it may make sense to
split a call to this function into a parallel map, then use the normal
Array.prototype.reduce on the results. This function is for situations where
each step in the reduction needs to be async, if you can get the data before
reducing it then it's probably a good idea to do so.

__Arguments__

* arr - An array to iterate over.
* memo - The initial state of the reduction.
* iterator(memo, item, callback) - A function applied to each item in the
  array to produce the next step in the reduction. The iterator is passed a
  callback(err, reduction) which accepts an optional error as its first
  argument, and the state of the reduction as the second. If an error is
  passed to the callback, the reduction is stopped and the main callback is
  immediately called with the error.
* callback(err, result) - A callback which is called after all the iterator
  functions have finished. Result is the reduced value.

__Example__

```js
async.reduce([1,2,3], 0, function(memo, item, callback){
    // pointless async:
    process.nextTick(function(){
        callback(null, memo + item)
    });
}, function(err, result){
    // result is now equal to the last value of memo, which is 6
});
```

---------------------------------------

### reduceRight(arr, memo, iterator, callback)

__Alias:__ foldr

Same as reduce, only operates on the items in the array in reverse order.

---------------------------------------

### detect(arr, iterator, callback)

Returns the first value in a list that passes an async truth test. The
iterator is applied in parallel, meaning the first iterator to return true will
fire the detect callback with that result. That means the result might not be
the first item in the original array (in terms of order) that passes the test.

If order within the original array is important then look at detectSeries.

__Arguments__

* arr - An array to iterate over.
* iterator(item, callback) - A truth test to apply to each item in the array.
  The iterator is passed a callback(truthValue) which must be called with a
  boolean argument once it has completed.
* callback(result) - A callback which is called as soon as any iterator returns
  true, or after all the iterator functions have finished. Result will be
  the first item in the array that passes the truth test (iterator) or the
  value undefined if none passed.

__Example__

```js
async.detect(['file1','file2','file3'], fs.exists, function(result){
    // result now equals the first file in the list that exists
});
```

---------------------------------------

### detectSeries(arr, iterator, callback)

The same as detect, only the iterator is applied to each item in the array
in series. This means the result is always the first in the original array (in
terms of array order) that passes the truth test.

---------------------------------------

### sortBy(arr, iterator, callback)

Sorts a list by the results of running each value through an async iterator.

__Arguments__

* arr - An array to iterate over.
* iterator(item, callback) - A function to apply to each item in the array.
  The iterator is passed a callback(err, sortValue) which must be called once it
  has completed with an error (which can be null) and a value to use as the sort
  criteria.
* callback(err, results) - A callback which is called after all the iterator
  functions have finished, or an error has occurred. Results is the items from
  the original array sorted by the values returned by the iterator calls.

__Example__

```js
async.sortBy(['file1','file2','file3'], function(file, callback){
    fs.stat(file, function(err, stats){
        callback(err, stats.mtime);
    });
}, function(err, results){
    // results is now the original array of files sorted by
    // modified date
});
```

---------------------------------------

### some(arr, iterator, callback)

__Alias:__ any

Returns true if at least one element in the array satisfies an async test.
_The callback for each iterator call only accepts a single argument of true or
false, it does not accept an error argument first!_ This is in-line with the
way node libraries work with truth tests like fs.exists. Once any iterator
call returns true, the main callback is immediately called.

__Arguments__

* arr - An array to iterate over.
* iterator(item, callback) - A truth test to apply to each item in the array.
  The iterator is passed a callback(truthValue) which must be called with a
  boolean argument once it has completed.
* callback(result) - A callback which is called as soon as any iterator returns
  true, or after all the iterator functions have finished. Result will be
  either true or false depending on the values of the async tests.

__Example__

```js
async.some(['file1','file2','file3'], fs.exists, function(result){
    // if result is true then at least one of the files exists
});
```

---------------------------------------

### every(arr, iterator, callback)

__Alias:__ all

Returns true if every element in the array satisfies an async test.
_The callback for each iterator call only accepts a single argument of true or
false, it does not accept an error argument first!_ This is in-line with the
way node libraries work with truth tests like fs.exists.

__Arguments__

* arr - An array to iterate over.
* iterator(item, callback) - A truth test to apply to each item in the array.
  The iterator is passed a callback(truthValue) which must be called with a
  boolean argument once it has completed.
* callback(result) - A callback which is called after all the iterator
  functions have finished. Result will be either true or false depending on
  the values of the async tests.

__Example__

```js
async.every(['file1','file2','file3'], fs.exists, function(result){
    // if result is true then every file exists
});
```

---------------------------------------

### concat(arr, iterator, callback)

Applies an iterator to each item in a list, concatenating the results. Returns the
concatenated list. The iterators are called in parallel, and the results are
concatenated as they return. There is no guarantee that the results array will
be returned in the original order of the arguments passed to the iterator function.

__Arguments__

* arr - An array to iterate over
* iterator(item, callback) - A function to apply to each item in the array.
  The iterator is passed a callback(err, results) which must be called once it
  has completed with an error (which can be null) and an array of results.
* callback(err, results) - A callback which is called after all the iterator
  functions have finished, or an error has occurred. Results is an array containing
  the concatenated results of the iterator function.

__Example__

```js
async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){
    // files is now a list of filenames that exist in the 3 directories
});
```

---------------------------------------

### concatSeries(arr, iterator, callback)

Same as async.concat, but executes in series instead of parallel.

## Control Flow

### series(tasks, [callback])

Run an array of functions in series, each one running once the previous
function has completed. If any functions in the series pass an error to its
callback, no more functions are run and the callback for the series is
immediately called with the value of the error. Once the tasks have completed,
the results are passed to the final callback as an array.

It is also possible to use an object instead of an array. Each property will be
run as a function and the results will be passed to the final callback as an object
instead of an array. This can be a more readable way of handling results from
async.series.

__Arguments__

* tasks - An array or object containing functions to run, each function is passed
  a callback(err, result) it must call on completion with an error (which can
  be null) and an optional result value.
* callback(err, results) - An optional callback to run once all the functions
  have completed. This function gets a results array (or object) containing all
  the result arguments passed to the task callbacks.

__Example__

```js
async.series([
    function(callback){
        // do some stuff ...
        callback(null, 'one');
    },
    function(callback){
        // do some more stuff ...
        callback(null, 'two');
    }
],
// optional callback
function(err, results){
    // results is now equal to ['one', 'two']
});

// an example using an object instead of an array
async.series({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: function(callback){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }
},
function(err, results) {
    // results is now equal to: {one: 1, two: 2}
});
```

---------------------------------------

### parallel(tasks, [callback])

Run an array of functions in parallel, without waiting until the previous
function has completed. If any of the functions pass an error to its
callback, the main callback is immediately called with the value of the error.
Once the tasks have completed, the results are passed to the final callback as an
array.

It is also possible to use an object instead of an array. Each property will be
run as a function and the results will be passed to the final callback as an object
instead of an array. This can be a more readable way of handling results from
async.parallel.

__Arguments__

* tasks - An array or object containing functions to run, each function is passed
  a callback(err, result) it must call on completion with an error (which can
  be null) and an optional result value.
* callback(err, results) - An optional callback to run once all the functions
  have completed. This function gets a results array (or object) containing all
  the result arguments passed to the task callbacks.

__Example__

```js
async.parallel([
    function(callback){
        setTimeout(function(){
            callback(null, 'one');
        }, 200);
    },
    function(callback){
        setTimeout(function(){
            callback(null, 'two');
        }, 100);
    }
],
// optional callback
function(err, results){
    // the results array will equal ['one','two'] even though
    // the second function had a shorter timeout.
});

// an example using an object instead of an array
async.parallel({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: function(callback){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }
},
function(err, results) {
    // results is now equals to: {one: 1, two: 2}
});
```

---------------------------------------

### parallelLimit(tasks, limit, [callback])

The same as parallel only the tasks are executed in parallel with a maximum of "limit"
tasks executing at any time.

Note that the tasks are not executed in batches, so there is no guarantee that
the first "limit" tasks will complete before any others are started.

__Arguments__

* tasks - An array or object containing functions to run, each function is passed
  a callback(err, result) it must call on completion with an error (which can
  be null) and an optional result value.
* limit - The maximum number of tasks to run at any time.
* callback(err, results) - An optional callback to run once all the functions
  have completed. This function gets a results array (or object) containing all
  the result arguments passed to the task callbacks.

---------------------------------------

### whilst(test, fn, callback)

Repeatedly call fn, while test returns true. Calls the callback when stopped,
or an error occurs.

__Arguments__

* test() - synchronous truth test to perform before each execution of fn.
* fn(callback) - A function to call each time the test passes. The function is
  passed a callback(err) which must be called once it has completed with an
  optional error argument.
* callback(err) - A callback which is called after the test fails and repeated
  execution of fn has stopped.

__Example__

```js
var count = 0;

async.whilst(
    function () { return count < 5; },
    function (callback) {
        count++;
        setTimeout(callback, 1000);
    },
    function (err) {
        // 5 seconds have passed
    }
);
```

---------------------------------------

### doWhilst(fn, test, callback)

The post check version of whilst. To reflect the difference in the order of operations `test` and `fn` arguments are switched. `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.

---------------------------------------

### until(test, fn, callback)

Repeatedly call fn, until test returns true. Calls the callback when stopped,
or an error occurs.

The inverse of async.whilst.

---------------------------------------

### doUntil(fn, test, callback)

Like doWhilst except the test is inverted. Note the argument ordering differs from `until`.

---------------------------------------

### forever(fn, callback)

Calls the asynchronous function 'fn' repeatedly, in series, indefinitely.
If an error is passed to fn's callback then 'callback' is called with the
error, otherwise it will never be called.

---------------------------------------

### waterfall(tasks, [callback])

Runs an array of functions in series, each passing their results to the next in
the array. However, if any of the functions pass an error to the callback, the
next function is not executed and the main callback is immediately called with
the error.

__Arguments__

* tasks - An array of functions to run, each function is passed a
  callback(err, result1, result2, ...) it must call on completion. The first
  argument is an error (which can be null) and any further arguments will be
  passed as arguments in order to the next task.
* callback(err, [results]) - An optional callback to run once all the functions
  have completed. This will be passed the results of the last task's callback.

__Example__

```js
async.waterfall([
    function(callback){
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback){
        callback(null, 'three');
    },
    function(arg1, callback){
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
   // result now equals 'done'
});
```

---------------------------------------

### compose(fn1, fn2...)

Creates a function which is a composition of the passed asynchronous
functions. Each function consumes the return value of the function that
follows. Composing functions f(), g() and h() would produce the result of
f(g(h())), only this version uses callbacks to obtain the return values.

Each function is executed with the `this` binding of the composed function.

__Arguments__

* functions... - the asynchronous functions to compose

__Example__

```js
function add1(n, callback) {
    setTimeout(function () {
        callback(null, n + 1);
    }, 10);
}

function mul3(n, callback) {
    setTimeout(function () {
        callback(null, n * 3);
    }, 10);
}

var add1mul3 = async.compose(mul3, add1);

add1mul3(4, function (err, result) {
   // result now equals 15
});
```

---------------------------------------

### applyEach(fns, args..., callback)

Applies the provided arguments to each function in the array, calling the
callback after all functions have completed. If you only provide the first
argument then it will return a function which lets you pass in the
arguments as if it were a single function call.

__Arguments__

* fns - the asynchronous functions to all call with the same arguments
* args... - any number of separate arguments to pass to the function
* callback - the final argument should be the callback, called when all
  functions have completed processing

__Example__

```js
async.applyEach([enableSearch, updateSchema], 'bucket', callback);

// partial application example:
async.each(
    buckets,
    async.applyEach([enableSearch, updateSchema]),
    callback
);
```

---------------------------------------

### applyEachSeries(arr, iterator, callback)

The same as applyEach only the functions are applied in series.

---------------------------------------

### queue(worker, concurrency)

Creates a queue object with the specified concurrency. Tasks added to the
queue will be processed in parallel (up to the concurrency limit). If all
workers are in progress, the task is queued until one is available. Once
a worker has completed a task, the task's callback is called.

__Arguments__

* worker(task, callback) - An asynchronous function for processing a queued
  task, which must call its callback(err) argument when finished, with an
  optional error as an argument.
* concurrency - An integer for determining how many worker functions should be
  run in parallel.

__Queue objects__

The queue object returned by this function has the following properties and
methods:

* length() - a function returning the number of items waiting to be processed.
* concurrency - an integer for determining how many worker functions should be
  run in parallel. This property can be changed after a queue is created to
  alter the concurrency on-the-fly.
* push(task, [callback]) - add a new task to the queue, the callback is called
  once the worker has finished processing the task.
  instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.
* unshift(task, [callback]) - add a new task to the front of the queue.
* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued
* empty - a callback that is called when the last item from the queue is given to a worker
* drain - a callback that is called when the last item from the queue has returned from the worker

__Example__

```js
// create a queue object with concurrency 2

var q = async.queue(function (task, callback) {
    console.log('hello ' + task.name);
    callback();
}, 2);

// assign a callback
q.drain = function() {
    console.log('all items have been processed');
}

// add some items to the queue

q.push({name: 'foo'}, function (err) {
    console.log('finished processing foo');
});
q.push({name: 'bar'}, function (err) {
    console.log('finished processing bar');
});

// add some items to the queue (batch-wise)

q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {
    console.log('finished processing bar');
});

// add some items to the front of the queue

q.unshift({name: 'bar'}, function (err) {
    console.log('finished processing bar');
});
```

---------------------------------------

### cargo(worker, [payload])

Creates a cargo object with the specified payload. Tasks added to the
cargo will be processed altogether (up to the payload limit). If the
worker is in progress, the task is queued until it is available. Once
the worker has completed some tasks, each callback of those tasks is called.

__Arguments__

* worker(tasks, callback) - An asynchronous function for processing an array of
  queued tasks, which must call its callback(err) argument when finished, with
  an optional error as an argument.
* payload - An optional integer for determining how many tasks should be
  processed per round; if omitted, the default is unlimited.

__Cargo objects__

The cargo object returned by this function has the following properties and
methods:

* length() - a function returning the number of items waiting to be processed.
* payload - an integer for determining how many tasks should be
  process per round. This property can be changed after a cargo is created to
  alter the payload on-the-fly.
* push(task, [callback]) - add a new task to the queue, the callback is called
  once the worker has finished processing the task.
  instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.
* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued
* empty - a callback that is called when the last item from the queue is given to a worker
* drain - a callback that is called when the last item from the queue has returned from the worker

__Example__

```js
// create a cargo object with payload 2

var cargo = async.cargo(function (tasks, callback) {
    for(var i=0; i<tasks.length; i++){
      console.log('hello ' + tasks[i].name);
    }
    callback();
}, 2);

// add some items

cargo.push({name: 'foo'}, function (err) {
    console.log('finished processing foo');
});
cargo.push({name: 'bar'}, function (err) {
    console.log('finished processing bar');
});
cargo.push({name: 'baz'}, function (err) {
    console.log('finished processing baz');
});
```

---------------------------------------

### auto(tasks, [callback])

Determines the best order for running functions based on their requirements.
Each function can optionally depend on other functions being completed first,
and each function is run as soon as its requirements are satisfied. If any of
the functions pass an error to their callback, that function will not complete
(so any other functions depending on it will not run) and the main callback
will be called immediately with the error. Functions also receive an object
containing the results of functions which have completed so far.

Note, all functions are called with a results object as a second argument,
so it is unsafe to pass functions in the tasks object which cannot handle the
extra argument. For example, this snippet of code:

```js
async.auto({
  readData: async.apply(fs.readFile, 'data.txt', 'utf-8');
}, callback);
```

will have the effect of calling readFile with the results object as the last
argument, which will fail:

```js
fs.readFile('data.txt', 'utf-8', cb, {});
```

Instead, wrap the call to readFile in a function which does not forward the
results object:

```js
async.auto({
  readData: function(cb, results){
    fs.readFile('data.txt', 'utf-8', cb);
  }
}, callback);
```

__Arguments__

* tasks - An object literal containing named functions or an array of
  requirements, with the function itself the last item in the array. The key
  used for each function or array is used when specifying requirements. The
  function receives two arguments: (1) a callback(err, result) which must be
  called when finished, passing an error (which can be null) and the result of
  the function's execution, and (2) a results object, containing the results of
  the previously executed functions.
* callback(err, results) - An optional callback which is called when all the
  tasks have been completed. The callback will receive an error as an argument
  if any tasks pass an error to their callback. Results will always be passed
	but if an error occurred, no other tasks will be performed, and the results
	object will only contain partial results.

__Example__

```js
async.auto({
    get_data: function(callback){
        // async code to get some data
    },
    make_folder: function(callback){
        // async code to create a directory to store a file in
        // this is run at the same time as getting the data
    },
    write_file: ['get_data', 'make_folder', function(callback){
        // once there is some data and the directory exists,
        // write the data to a file in the directory
        callback(null, filename);
    }],
    email_link: ['write_file', function(callback, results){
        // once the file is written let's email a link to it...
        // results.write_file contains the filename returned by write_file.
    }]
});
```

This is a fairly trivial example, but to do this using the basic parallel and
series functions would look like this:

```js
async.parallel([
    function(callback){
        // async code to get some data
    },
    function(callback){
        // async code to create a directory to store a file in
        // this is run at the same time as getting the data
    }
],
function(err, results){
    async.series([
        function(callback){
            // once there is some data and the directory exists,
            // write the data to a file in the directory
        },
        function(callback){
            // once the file is written let's email a link to it...
        }
    ]);
});
```

For a complicated series of async tasks using the auto function makes adding
new tasks much easier and makes the code more readable.

---------------------------------------

### iterator(tasks)

Creates an iterator function which calls the next function in the array,
returning a continuation to call the next one after that. It's also possible to
'peek' the next iterator by doing iterator.next().

This function is used internally by the async module but can be useful when
you want to manually control the flow of functions in series.

__Arguments__

* tasks - An array of functions to run.

__Example__

```js
var iterator = async.iterator([
    function(){ sys.p('one'); },
    function(){ sys.p('two'); },
    function(){ sys.p('three'); }
]);

node> var iterator2 = iterator();
'one'
node> var iterator3 = iterator2();
'two'
node> iterator3();
'three'
node> var nextfn = iterator2.next();
node> nextfn();
'three'
```

---------------------------------------

### apply(function, arguments..)

Creates a continuation function with some arguments already applied, a useful
shorthand when combined with other control flow functions. Any arguments
passed to the returned function are added to the arguments originally passed
to apply.

__Arguments__

* function - The function you want to eventually apply all arguments to.
* arguments... - Any number of arguments to automatically apply when the
  continuation is called.

__Example__

```js
// using apply

async.parallel([
    async.apply(fs.writeFile, 'testfile1', 'test1'),
    async.apply(fs.writeFile, 'testfile2', 'test2'),
]);

// the same process without using apply

async.parallel([
    function(callback){
        fs.writeFile('testfile1', 'test1', callback);
    },
    function(callback){
        fs.writeFile('testfile2', 'test2', callback);
    }
]);
```

It's possible to pass any number of additional arguments when calling the
continuation:

```js
node> var fn = async.apply(sys.puts, 'one');
node> fn('two', 'three');
one
two
three
```

---------------------------------------

### nextTick(callback)

Calls the callback on a later loop around the event loop. In node.js this just
calls process.nextTick, in the browser it falls back to setImmediate(callback)
if available, otherwise setTimeout(callback, 0), which means other higher priority
events may precede the execution of the callback.

This is used internally for browser-compatibility purposes.

__Arguments__

* callback - The function to call on a later loop around the event loop.

__Example__

```js
var call_order = [];
async.nextTick(function(){
    call_order.push('two');
    // call_order now equals ['one','two']
});
call_order.push('one')
```

### times(n, callback)

Calls the callback n times and accumulates results in the same manner
you would use with async.map.

__Arguments__

* n - The number of times to run the function.
* callback - The function to call n times.

__Example__

```js
// Pretend this is some complicated async factory
var createUser = function(id, callback) {
  callback(null, {
    id: 'user' + id
  })
}
// generate 5 users
async.times(5, function(n, next){
    createUser(n, function(err, user) {
      next(err, user)
    })
}, function(err, users) {
  // we should now have 5 users
});
```

### timesSeries(n, callback)

The same as times only the iterator is applied to each item in the array in
series. The next iterator is only called once the current one has completed
processing. The results array will be in the same order as the original.

## Utils

### memoize(fn, [hasher])

Caches the results of an async function. When creating a hash to store function
results against, the callback is omitted from the hash and an optional hash
function can be used.

The cache of results is exposed as the `memo` property of the function returned
by `memoize`.

__Arguments__

* fn - the function you to proxy and cache results from.
* hasher - an optional function for generating a custom hash for storing
  results, it has all the arguments applied to it apart from the callback, and
  must be synchronous.

__Example__

```js
var slow_fn = function (name, callback) {
    // do something
    callback(null, result);
};
var fn = async.memoize(slow_fn);

// fn can now be used as if it were slow_fn
fn('some name', function () {
    // callback
});
```

### unmemoize(fn)

Undoes a memoized function, reverting it to the original, unmemoized
form. Comes handy in tests.

__Arguments__

* fn - the memoized function

### log(function, arguments)

Logs the result of an async function to the console. Only works in node.js or
in browsers that support console.log and console.error (such as FF and Chrome).
If multiple arguments are returned from the async function, console.log is
called on each argument in order.

__Arguments__

* function - The function you want to eventually apply all arguments to.
* arguments... - Any number of arguments to apply to the function.

__Example__

```js
var hello = function(name, callback){
    setTimeout(function(){
        callback(null, 'hello ' + name);
    }, 1000);
};
```
```js
node> async.log(hello, 'world');
'hello world'
```

---------------------------------------

### dir(function, arguments)

Logs the result of an async function to the console using console.dir to
display the properties of the resulting object. Only works in node.js or
in browsers that support console.dir and console.error (such as FF and Chrome).
If multiple arguments are returned from the async function, console.dir is
called on each argument in order.

__Arguments__

* function - The function you want to eventually apply all arguments to.
* arguments... - Any number of arguments to apply to the function.

__Example__

```js
var hello = function(name, callback){
    setTimeout(function(){
        callback(null, {hello: name});
    }, 1000);
};
```
```js
node> async.dir(hello, 'world');
{hello: 'world'}
```

---------------------------------------

### noConflict()

Changes the value of async back to its original value, returning a reference to the
async object.


* @param {int} scrollTop Top of scroll position

* @param {int} scrollLeft Left of scroll position

* @param {int} offsetTop Top of scroller element

* @param {int} scrollWidth Width of the tree container


ProjectModel.prototype.setScrollerInfo = function (scrollTop, scrollLeft, offsetTop) {

* Returns the encoded Base URL of the currently loaded project, or empty string if no project

* is open (during startup, or running outside of app shell).

keep keep keep keep replace replace keep keep keep keep keep

ProjectModel.prototype.setScrollerInfo = function (scrollWidth, scrollTop, scrollLeft, offsetTop) {

this._viewModel.setSelectionScrollerInfo(scrollWidth, scrollTop, scrollLeft, offsetTop);

/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*global define, $*/
/*unittests: FileTreeView*/

/**
 * This is the view layer (template) for the file tree in the sidebar. It takes a FileTreeViewModel
 * and renders it to the given element using React. User actions are signaled via an ActionCreator
 * (in the Flux sense).
 */
define(function (require, exports, module) {
    "use strict";

    var React             = require("thirdparty/react"),
        Immutable         = require("thirdparty/immutable"),
        _                 = require("thirdparty/lodash"),
        FileUtils         = require("file/FileUtils"),
        FileTreeViewModel = require("project/FileTreeViewModel"),
        ViewUtils         = require("utils/ViewUtils"),
        KeyEvent          = require("utils/KeyEvent");

    var DOM = React.DOM;

    /**
     * @private
     * @type {Immutable.Map}
     *
     * Stores the file tree extensions for adding classes and icons. The keys of the map
     * are the "categories" of the extensions and values are vectors of the callback functions.
     */
    var _extensions = Immutable.Map();

    // Constants

    // Time range from first click to second click to invoke renaming.
    var CLICK_RENAME_MINIMUM  = 500,
        RIGHT_MOUSE_BUTTON    = 2,
        LEFT_MOUSE_BUTTON     = 0;

    /**
     * @private
     *
     * Returns the name of a file without its extension.
     *
     * @param {string} fullname The complete name of the file (not including the rest of the path)
     * @param {string} extension The file extension
     * @return {string} The fullname without the extension
     */
    function _getName(fullname, extension) {
        return extension !== "" ? fullname.substring(0, fullname.length - extension.length - 1) : fullname;
    }

    /**
     * Mixin that allows a component to compute the full path to its directory entry.
     */
    var pathComputer = {
        /**
         * Computes the full path of the file represented by this input.
         */
        myPath: function () {
            var result = this.props.parentPath + this.props.name;

            // Add trailing slash for directories
            if (!FileTreeViewModel.isFile(this.props.entry) && _.last(result) !== "/") {
                result += "/";
            }

            return result;
        }
    };

    /**
     * This is a mixin that provides rename input behavior. It is responsible for taking keyboard input
     * and invoking the correct action based on that input.
     */
    var renameBehavior = {
        /**
         * If the user presses enter or escape, we either successfully complete or cancel, respectively,
         * the rename or create operation that is underway.
         */
        handleKeyDown: function (e) {
            if (e.keyCode === KeyEvent.DOM_VK_ESCAPE) {
                this.props.actions.cancelRename();
            } else if (e.keyCode === KeyEvent.DOM_VK_RETURN) {
                this.props.actions.performRename();
            }
        },

        /**
         * The rename or create operation can be completed or canceled by actions outside of
         * this component, so we keep the model up to date by sending every update via an action.
         */
        handleKeyUp: function () {
            this.props.actions.setRenameValue(this.refs.name.getDOMNode().value.trim());
        }
    };

    /**
     * @private
     *
     * Gets an appropriate width given the text provided.
     *
     * @param {string} text Text to measure
     * @return {int} Width to use
     */
    function _measureText(text) {
        var measuringElement = $("<div />", { css : { "position" : "absolute", "top" : "-200px", "left" : ("-1000px"), "visibility" : "hidden" } }).appendTo("body");
        measuringElement.text("pW" + text);
        var width = measuringElement.width();
        measuringElement.remove();
        return width;
    }

    /**
     * @private
     *
     * This component presents an input field to the user for renaming a file.
     *
     * Props:
     * * parentPath: the full path of the directory containing this file
     * * name: the name of the file, including the extension
     * * actions: the action creator responsible for communicating actions the user has taken
     */
    var fileRenameInput = React.createClass({
        mixins: [renameBehavior],

        /**
         * When this component is displayed, we scroll it into view and select the portion
         * of the filename that excludes the extension.
         */
        componentDidMount: function () {
            var fullname = this.props.name,
                extension = FileUtils.getSmartFileExtension(fullname);

            var node = this.refs.name.getDOMNode();
            node.setSelectionRange(0, _getName(fullname, extension).length);
            ViewUtils.scrollElementIntoView($("#project-files-container"), $(node), true);
        },

        render: function () {
            var width = _measureText(this.props.name);

            return DOM.input({
                className: "jstree-rename-input " + this.props.fileClasses,
                type: "text",
                defaultValue: this.props.name,
                autoFocus: true,
                onKeyDown: this.handleKeyDown,
                onKeyUp: this.handleKeyUp,
                style: {
                    width: width
                },
                ref: "name"
            });
        }
    });

    /**
     * @private
     *
     * This mixin handles right click (or control click on Mac) action to make a file
     * the "context" object for performing operations like rename.
     */
    var contextSettable = {

        /**
         * Send matching mouseDown events to the action creator as a setContext action.
         */
        handleMouseDown: function (e) {
            if (e.button === RIGHT_MOUSE_BUTTON ||
                    (this.props.platform === "mac" && e.button === LEFT_MOUSE_BUTTON && e.ctrlKey)) {
                this.props.actions.setContext(this.myPath());
                return false;
            }
        }
    };

    /**
     * @private
     *
     * Returns true if the value is defined (used in `.filter`)
     *
     * @param {Object} value value to test
     * @return {boolean} true if value is defined
     */
    function isDefined(value) {
        return value !== undefined;
    }

    /**
     * Mixin for components that support the "icons" and "addClass" extension points.
     * `fileNode` and `directoryNode` support this.
     */
    var extendable = {

        /**
         * Calls the icon providers to get the collection of icons (most likely just one) for
         * the current file or directory.
         *
         * @return {Array.<ReactComponent>} icon components to render
         */
        getIcons: function () {
            var result,
                extensions = this.props.extensions;

            if (extensions && extensions.get("icons")) {
                var data = this.getDataForExtension();
                result = extensions.get("icons").map(function (callback) {
                    try {
                        var result = callback(data);
                        if (!React.isValidComponent(result)) {
                            result = React.DOM.span({
                                dangerouslySetInnerHTML: {
                                    __html: $(result)[0].outerHTML
                                }
                            });
                        }
                        return result;
                    } catch (e) {
                        console.warn("Exception thrown in FileTreeView icon provider:", e);
                    }
                }).filter(isDefined).toArray();
            }

            if (!result || result.length === 0) {
                result = [DOM.ins({
                    className: "jstree-icon"
                }, " ")];
            }
            return result;
        },

        /**
         * Calls the addClass providers to get the classes (in string form) to add for the current
         * file or directory.
         *
         * @param {string} classes Initial classes for this node
         * @return {string} classes for the current node
         */
        getClasses: function (classes) {
            var extensions = this.props.extensions;

            if (extensions && extensions.get("addClass")) {
                var data = this.getDataForExtension();
                classes = classes + " " + extensions.get("addClass").map(function (callback) {
                    try {
                        return callback(data);
                    } catch (e) {
                        console.warn("Exception thrown in FileTreeView addClass provider:", e);
                    }
                }).filter(isDefined).toArray().join(" ");
            }

            return classes;
        }
    };

    /**
     * @private
     *
     * Component to display a file in the tree.
     *
     * Props:
     * * parentPath: the full path of the directory containing this file
     * * name: the name of the file, including the extension
     * * entry: the object with the relevant metadata for the file (whether it's selected or is the context file)
     * * actions: the action creator responsible for communicating actions the user has taken
     * * extensions: registered extensions for the file tree
     * * forceRender: causes the component to run render
     */
    var fileNode = React.createClass({
        mixins: [contextSettable, pathComputer, extendable],

        /**
         * Ensures that we always have a state object.
         */
        getInitialState: function () {
            return {
                clickTimer: null
            };
        },

        /**
         * Thanks to immutable objects, we can just do a start object identity check to know
         * whether or not we need to re-render.
         */
        shouldComponentUpdate: function (nextProps, nextState) {
            return nextProps.forceRender ||
                this.props.entry !== nextProps.entry ||
                this.props.extensions !== nextProps.extensions;
        },

        /**
         * If this node is newly selected, scroll it into view. Also, move the selection or
         * context boxes as appropriate.
         */
        componentDidUpdate: function (prevProps, prevState) {
            var wasSelected = prevProps.entry.get("selected"),
                isSelected  = this.props.entry.get("selected");

            if (isSelected && !wasSelected) {
                // TODO: This shouldn't really know about project-files-container
                // directly. It is probably the case that our React tree should actually
                // start with project-files-container instead of just the interior of
                // project-files-container and then the file tree will be one self-contained
                // functional unit.
                ViewUtils.scrollElementIntoView($("#project-files-container"), $(this.getDOMNode()), true);
            } else if (!isSelected && wasSelected && this.state.clickTimer !== null) {
                this.clearTimer();
            }
        },

        clearTimer: function () {
            if (this.state.clickTimer !== null) {
                window.clearTimeout(this.state.clickTimer);
                this.setState({
                    clickTimer: null
                });
            }
        },

        startRename: function () {
            if (!this.props.entry.get("rename")) {
                this.props.actions.startRename(this.myPath());
            }
            this.clearTimer();
        },

        /**
         * When the user clicks on the node, we'll either select it or, if they've clicked twice
         * with a bit of delay in between, we'll invoke the `startRename` action.
         */
        handleClick: function (e) {
            // If we're renaming, allow the click to go through to the rename input.
            if (this.props.entry.get("rename")) {
                return true;
            }

            if (e.button !== LEFT_MOUSE_BUTTON) {
                return;
            }

            if (this.props.entry.get("selected")) {
                if (this.state.clickTimer === null && !this.props.entry.get("rename")) {
                    var timer = window.setTimeout(this.startRename, CLICK_RENAME_MINIMUM);
                    this.setState({
                        clickTimer: timer
                    });
                }
            } else {
                this.props.actions.setSelected(this.myPath());
            }
            return false;
        },

        /**
         * When the user double clicks, we will select this file and add it to the working
         * set (via the `selectInWorkingSet` action.)
         */
        handleDoubleClick: function () {
            if (!this.props.entry.get("rename")) {
                if (this.state.clickTimer !== null) {
                    this.clearTimer();
                }
                this.props.actions.selectInWorkingSet(this.myPath());
            }
        },

        /**
         * Create the data object to pass to extensions.
         *
         * @return {{name: {string}, isFile: {boolean}, fullPath: {string}}} Data for extensions
         */
        getDataForExtension: function () {
            return {
                name: this.props.name,
                isFile: true,
                fullPath: this.myPath()
            };
        },

        render: function () {
            var fullname = this.props.name,
                extension = FileUtils.getSmartFileExtension(fullname),
                name = _getName(fullname, extension);

            if (extension) {
                extension = DOM.span({
                    className: "extension"
                }, "." + extension);
            }

            var nameDisplay,
                cx = React.addons.classSet;

            var fileClasses = cx({
                'jstree-clicked selected-node': this.props.entry.get("selected"),
                'context-node': this.props.entry.get("context")
            });

            if (this.props.entry.get("rename")) {
                nameDisplay = fileRenameInput({
                    actions: this.props.actions,
                    entry: this.props.entry,
                    name: this.props.name,
                    parentPath: this.props.parentPath,
                    fileClasses: fileClasses
                });
            } else {
                // Need to flatten the argument list because getIcons returns an array
                var aArgs = _.flatten([{
                    href: "#",
                    className: fileClasses
                }, this.getIcons(), name, extension], true);
                nameDisplay = DOM.a.apply(DOM.a, aArgs);
            }

            return DOM.li({
                className: this.getClasses("jstree-leaf"),
                onClick: this.handleClick,
                onMouseDown: this.handleMouseDown,
                onDoubleClick: this.handleDoubleClick
            },
                DOM.ins({
                    className: "jstree-icon"
                }, " "),
                nameDisplay);
        }
    });

    /**
     * @private
     *
     * Creates a comparison function for sorting a directory's contents with directories
     * appearing before files.
     *
     * We're sorting the keys of the directory (the names) based partly on the values,
     * so we use a closure to capture the map itself so that we can look up the
     * values as needed.
     *
     * @param {Immutable.Map} contents The directory's contents
     * @return {function(string,string)} Comparator that sorts directories first.
     */
    function _buildDirsFirstComparator(contents) {
        function _dirsFirstCompare(a, b) {
            var aIsFile = FileTreeViewModel.isFile(contents.get(a)),
                bIsFile = FileTreeViewModel.isFile(contents.get(b));

            if (!aIsFile && bIsFile) {
                return -1;
            } else if (aIsFile && !bIsFile) {
                return 1;
            } else {
                return FileUtils.compareFilenames(a, b);
            }
        }
        return _dirsFirstCompare;
    }

    /**
     * @private
     *
     * Sort a directory either alphabetically or with subdirectories listed first.
     *
     * @param {Immutable.Map} contents the directory's contents
     * @param {boolean} dirsFirst true to sort subdirectories first
     * @return {Immutable.Map} sorted mapping
     */
    function _sortDirectoryContents(contents, dirsFirst) {
        if (dirsFirst) {
            return contents.keySeq().sort(_buildDirsFirstComparator(contents));
        } else {
            return contents.keySeq().sort(FileUtils.compareFilenames);
        }
    }

    // Forward references to keep JSLint happy.
    var directoryNode, directoryContents;

    /**
     * @private
     *
     * Component that provides the input for renaming a directory.
     *
     * Props:
     * * parentPath: the full path of the directory containing this file
     * * name: the name of the file, including the extension
     * * actions: the action creator responsible for communicating actions the user has taken
     */
    var directoryRenameInput = React.createClass({
        mixins: [renameBehavior],

        render: function () {
            var width = _measureText(this.props.name);

            return DOM.input({
                className: "jstree-rename-input",
                type: "text",
                defaultValue: this.props.name,
                autoFocus: true,
                onKeyDown: this.handleKeyDown,
                onKeyUp: this.handleKeyUp,
                ref: "name",
                style: {
                    width: width
                }
            });
        }
    });

    /**
     * @private
     *
     * Displays a directory (but not its contents) in the tree.
     *
     * Props:
     * * parentPath: the full path of the directory containing this file
     * * name: the name of the directory
     * * entry: the object with the relevant metadata for the file (whether it's selected or is the context file)
     * * actions: the action creator responsible for communicating actions the user has taken
     * * sortDirectoriesFirst: whether the directories should be displayed first when listing the contents of a directory
     * * extensions: registered extensions for the file tree
     * * forceRender: causes the component to run render
     */
    directoryNode = React.createClass({
        mixins: [contextSettable, pathComputer, extendable],

        /**
         * We need to update this component if the sort order changes or our entry object
         * changes. Thanks to immutability, if any of the directory contents change, our
         * entry object will change.
         */
        shouldComponentUpdate: function (nextProps, nextState) {
            return nextProps.forceRender ||
                this.props.entry !== nextProps.entry ||
                this.props.sortDirectoriesFirst !== nextProps.sortDirectoriesFirst ||
                this.props.extensions !== nextProps.extensions;
        },

        /**
         * If you click on a directory, it will toggle between open and closed.
         */
        handleClick: function (event) {
            if (event.button !== LEFT_MOUSE_BUTTON) {
                return;
            }

            var isOpen = this.props.entry.get("open"),
                setOpen = isOpen ? false : true;

            if (event.metaKey || event.ctrlKey) {
                // ctrl-alt-click toggles this directory and its children
                if (event.altKey) {
                    if (setOpen) {
                        // when opening, we only open the immediate children because
                        // opening a whole subtree could be really slow (consider
                        // a `node_modules` directory, for example).
                        this.props.actions.toggleSubdirectories(this.myPath(), setOpen);
                        this.props.actions.setDirectoryOpen(this.myPath(), setOpen);
                    } else {
                        // When closing, we recursively close the whole subtree.
                        this.props.actions.closeSubtree(this.myPath());
                    }
                } else {
                    // ctrl-click toggles the sibling directories
                    this.props.actions.toggleSubdirectories(this.props.parentPath, setOpen);
                }
            } else {
                // directory toggle with no modifier
                this.props.actions.setDirectoryOpen(this.myPath(), setOpen);
            }
            return false;
        },

        /**
         * Create the data object to pass to extensions.
         *
         * @return {{name: {string}, isFile: {boolean}, fullPath: {string}}} Data for extensions
         */
        getDataForExtension: function () {
            return {
                name: this.props.name,
                isFile: false,
                fullPath: this.myPath()
            };
        },

        render: function () {
            var entry = this.props.entry,
                nodeClass,
                childNodes,
                children = entry.get("children"),
                isOpen = entry.get("open"),
                directoryClasses = "";

            if (isOpen && children) {
                nodeClass = "open";
                childNodes = directoryContents({
                    parentPath: this.myPath(),
                    contents: children,
                    extensions: this.props.extensions,
                    actions: this.props.actions,
                    forceRender: this.props.forceRender,
                    platform: this.props.platform,
                    sortDirectoriesFirst: this.props.sortDirectoriesFirst
                });
            } else {
                nodeClass = "closed";
            }

            if (this.props.entry.get("selected")) {
                directoryClasses += " jstree-clicked sidebar-selection";
            }

            if (entry.get("context")) {
                directoryClasses += " context-node";
            }

            var nameDisplay;
            if (entry.get("rename")) {
                nameDisplay = directoryRenameInput({
                    actions: this.props.actions,
                    entry: this.props.entry,
                    name: this.props.name,
                    parentPath: this.props.parentPath
                });
            } else {
                // Need to flatten the arguments because getIcons returns an array
                var aArgs = _.flatten([{
                    href: "#",
                    className: directoryClasses
                }, this.getIcons(), this.props.name], true);
                nameDisplay = DOM.a.apply(DOM.a, aArgs);
            }

            return DOM.li({
                className: this.getClasses("jstree-" + nodeClass),
                onClick: this.handleClick,
                onMouseDown: this.handleMouseDown
            },
                DOM.ins({
                    className: "jstree-icon"
                }, " "),
                nameDisplay,
                childNodes);
        }
    });

    /**
     * @private
     *
     * Displays the contents of a directory.
     *
     * Props:
     * * isRoot: whether this directory is the root of the tree
     * * parentPath: the full path of the directory containing this file
     * * contents: the map of name/child entry pairs for this directory
     * * actions: the action creator responsible for communicating actions the user has taken
     * * sortDirectoriesFirst: whether the directories should be displayed first when listing the contents of a directory
     * * extensions: registered extensions for the file tree
     * * forceRender: causes the component to run render
     */
    directoryContents = React.createClass({

        /**
         * Need to re-render if the sort order or the contents change.
         */
        shouldComponentUpdate: function (nextProps, nextState) {
            return nextProps.forceRender ||
                this.props.contents !== nextProps.contents ||
                this.props.sortDirectoriesFirst !== nextProps.sortDirectoriesFirst ||
                this.props.extensions !== nextProps.extensions;
        },

        render: function () {
            var extensions = this.props.extensions,
                iconClass = extensions && extensions.get("icons") ? "jstree-icons" : "jstree-no-icons",
                ulProps = this.props.isRoot ? {
                    className: "jstree-brackets jstree-no-dots " + iconClass
                } : null;

            var contents = this.props.contents,
                namesInOrder = _sortDirectoryContents(contents, this.props.sortDirectoriesFirst);

            return DOM.ul(ulProps, namesInOrder.map(function (name) {
                var entry = contents.get(name);

                if (FileTreeViewModel.isFile(entry)) {
                    return fileNode({
                        parentPath: this.props.parentPath,
                        name: name,
                        entry: entry,
                        actions: this.props.actions,
                        extensions: this.props.extensions,
                        forceRender: this.props.forceRender,
                        platform: this.props.platform,
                        key: name
                    });
                } else {
                    return directoryNode({
                        parentPath: this.props.parentPath,
                        name: name,
                        entry: entry,
                        actions: this.props.actions,
                        extensions: this.props.extensions,
                        sortDirectoriesFirst: this.props.sortDirectoriesFirst,
                        forceRender: this.props.forceRender,
                        platform: this.props.platform,
                        key: name
                    });
                }
            }.bind(this)).toArray());
        }
    });

    /**
     * Displays the absolutely positioned box for the selection or context in the
     * file tree. Its position is determined by passed-in info about the scroller in which
     * the tree resides and the top of the selected node (as reported by the node itself).
     *
     * Props:
     * * selectionViewInfo: Immutable.Map with width, scrollTop, scrollLeft and offsetTop for the tree container
     * * visible: should this be visible now
     * * widthAdjustment: if this box should not fill the entire width, pass in a positive number here which is subtracted from the width in selectionViewInfo
     */
    var fileSelectionBox = React.createClass({

        /**
         * Sets up initial state.
         */
        getInitialState: function () {
            return {
                initialScroll: 0
            };
        },

        /**
         * When the component has updated in the DOM, reposition it to where the currently
         * selected node is located now.
         */
        componentDidUpdate: function () {
            if (!this.props.visible) {
                return;
            }

            var node = this.getDOMNode(),
                selectedNode = $(node.parentNode).find(this.props.selectedClassName),
                selectionViewInfo = this.props.selectionViewInfo;

            if (selectedNode.length === 0) {
                return;
            }

            node.style.top = selectedNode.offset().top - selectionViewInfo.get("offsetTop") + selectionViewInfo.get("scrollTop") - selectedNode.position().top + "px";
        },

        render: function () {
            var selectionViewInfo = this.props.selectionViewInfo;

            return DOM.div({
                style: {
                    overflow: "auto",
                    left: selectionViewInfo.get("scrollLeft"),
                    width: selectionViewInfo.get("width") - this.props.widthAdjustment,
                    display: this.props.visible ? "block" : "none"
                },
                className: this.props.className
            });
        }
    });

    /**
     * @private
     *
     * This is the root component of the file tree.
     *
     * Props:
     * * treeData: the root of the tree (an Immutable.Map with the contents of the project root)
     * * sortDirectoriesFirst: whether the directories should be displayed first when listing the contents of a directory
     * * parentPath: the full path of the directory containing this file
     * * actions: the action creator responsible for communicating actions the user has taken
     * * extensions: registered extensions for the file tree
     * * forceRender: causes the component to run render
     */
    var fileTreeView = React.createClass({

        /**
         * Update for any change in the tree data or directory sorting preference.
         */
        shouldComponentUpdate: function (nextProps, nextState) {
            return nextProps.forceRender ||
                this.props.treeData !== nextProps.treeData ||
                this.props.sortDirectoriesFirst !== nextProps.sortDirectoriesFirst ||
                this.props.extensions !== nextProps.extensions ||
                this.props.selectionViewInfo !== nextProps.selectionViewInfo;
        },

        render: function () {
            var selectionBackground = fileSelectionBox({
                ref: "selectionBackground",
                selectionViewInfo: this.props.selectionViewInfo,
                className: "filetree-selection",
                visible: this.props.selectionViewInfo.get("hasSelection"),
                widthAdjustment: 0,
                selectedClassName: ".selected-node",
                forceUpdate: true
            }),
                contextBackground = fileSelectionBox({
                    ref: "contextBackground",
                    selectionViewInfo: this.props.selectionViewInfo,
                    className: "filetree-context",
                    visible: this.props.selectionViewInfo.get("hasContext"),
                    widthAdjustment: 0,
                    selectedClassName: ".context-node",
                    forceUpdate: true
                });

            return DOM.div(
                null,
                selectionBackground,
                contextBackground,
                directoryContents({
                    isRoot: true,
                    parentPath: this.props.parentPath,
                    sortDirectoriesFirst: this.props.sortDirectoriesFirst,
                    contents: this.props.treeData,
                    extensions: this.props.extensions,
                    actions: this.props.actions,
                    forceRender: this.props.forceRender,
                    platform: this.props.platform
                })
            );
        }
    });

    /**
     * Renders the file tree to the given element.
     *
     * @param {DOMNode|jQuery} element Element in which to render this file tree
     * @param {FileTreeViewModel} viewModel the data container
     * @param {Directory} projectRoot Directory object from which the fullPath of the project root is extracted
     * @param {ActionCreator} actions object with methods used to communicate events that originate from the user
     * @param {boolean} forceRender Run render on the entire tree (useful if an extension has new data that it needs rendered)
     * @param {string} platform mac, win, linux
     */
    function render(element, viewModel, projectRoot, actions, forceRender, platform) {
        if (!projectRoot) {
            return;
        }

        React.renderComponent(fileTreeView({
            treeData: viewModel.treeData,
            selectionViewInfo: viewModel.selectionViewInfo,
            sortDirectoriesFirst: viewModel.sortDirectoriesFirst,
            parentPath: projectRoot.fullPath,
            actions: actions,
            extensions: _extensions,
            platform: platform,
            forceRender: forceRender
        }),
              element);
    }

    /**
     * @private
     *
     * Add an extension for the given category (icons, addClass).
     *
     * @param {string} category Category to which the extension is being added
     * @param {function} callback The extension function itself
     */
    function _addExtension(category, callback) {
        if (!callback || typeof callback !== "function") {
            console.error("Attempt to add FileTreeView", category, "extension without a callback function");
            return;
        }
        var callbackList = _extensions.get(category);
        if (!callbackList) {
            callbackList = Immutable.Vector();
        }
        callbackList = callbackList.push(callback);
        _extensions = _extensions.set(category, callbackList);
    }

    /**
     * Adds an icon provider. The icon provider is a function which takes a data object and
     * returns a React.DOM.ins instance for the icons within the tree. The callback can
     * alternatively return a string, DOM node or a jQuery object for the ins node to be added.
     *
     * The data object contains:
     *
     * * `name`: the file or directory name
     * * `fullPath`: full path to the file or directory
     * * `isFile`: true if it's a file, false if it's a directory
     */
    function addIconProvider(callback) {
        _addExtension("icons", callback);
    }

    /**
     * Adds an additional classes provider which can return classes that should be added to a
     * given file or directory in the tree.
     *
     * The data object contains:
     *
     * * `name`: the file or directory name
     * * `fullPath`: full path to the file or directory
     * * `isFile`: true if it's a file, false if it's a directory
     */
    function addClassesProvider(callback) {
        _addExtension("addClass", callback);
    }

    // Private API for testing
    exports._sortFormattedDirectory = _sortDirectoryContents;
    exports._fileNode = fileNode;
    exports._directoryNode = directoryNode;
    exports._directoryContents = directoryContents;
    exports._fileTreeView = fileTreeView;

    // Public API
    exports.addIconProvider = addIconProvider;
    exports.addClassesProvider = addClassesProvider;
    exports.render = render;
});


mime

A comprehensive library for mime-type mapping

# mime

Comprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community.

## Install

Install with [npm](http://github.com/isaacs/npm):

    npm install mime

## API - Queries

### mime.lookup(path)
Get the mime type associated with a file, if no mime type is found `application/octet-stream` is returned. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.').  E.g.

    var mime = require('mime');

    mime.lookup('/path/to/file.txt');         // => 'text/plain'
    mime.lookup('file.txt');                  // => 'text/plain'
    mime.lookup('.TXT');                      // => 'text/plain'
    mime.lookup('htm');                       // => 'text/html'

### mime.default_type
Sets the mime type returned when `mime.lookup` fails to find the extension searched for. (Default is `application/octet-stream`.)

### mime.extension(type)
Get the default extension for `type`

    mime.extension('text/html');                 // => 'html'
    mime.extension('application/octet-stream');  // => 'bin'

### mime.charsets.lookup()

Map mime-type to charset

    mime.charsets.lookup('text/plain');        // => 'UTF-8'

(The logic for charset lookups is pretty rudimentary.  Feel free to suggest improvements.)

## API - Defining Custom Types

The following APIs allow you to add your own type mappings within your project.  If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types).

### mime.define()

Add custom mime/extension mappings

    mime.define({
        'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'],
        'application/x-my-type': ['x-mt', 'x-mtt'],
        // etc ...
    });

    mime.lookup('x-sft');                 // => 'text/x-some-format'

The first entry in the extensions array is returned by `mime.extension()`. E.g.

    mime.extension('text/x-some-format'); // => 'x-sf'

### mime.load(filepath)

Load mappings from an Apache ".types" format file

    mime.load('./my_project.types');

The .types file format is simple -  See the `types` dir for examples.


/* Test comment */
define(function (require, exports, module) {
    var bar = require("modules/bar"),
        Bar = require("modules/Bar"),
        Baz = require("modules/Baz");

    function callbar() {

        bar();

    }

}


/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, describe, it, spyOn, expect, beforeEach, afterEach, $ */

define(function (require, exports, module) {
    'use strict';

    var EditorManager    = require("editor/EditorManager"),
        ViewStateManager = require("view/ViewStateManager"),
        SpecRunnerUtils  = require("spec/SpecRunnerUtils");

    describe("EditorManager", function () {
        var pane, testEditor, testDoc, $fakeContentDiv, $fakeHolder;
        beforeEach(function () {
            // Normally the editor holder would be created inside a "content" div, which is
            // used in the available height calculation. We create a fake content div just to
            // hold the height, and we'll place the editor holder in it.
            $fakeContentDiv = $("
")
                .css("height", "200px")
                .appendTo(document.body);

            $fakeHolder = SpecRunnerUtils.createMockElement()
                                        .css("width", "1000px")
                                        .attr("id", "hidden-editors")
                                        .appendTo($fakeContentDiv);

            pane = SpecRunnerUtils.createMockPane($fakeHolder);
            testDoc = SpecRunnerUtils.createMockDocument("");
        });
        afterEach(function () {
            $fakeHolder.remove();
            $fakeHolder = null;

            $fakeContentDiv.remove();
            $fakeContentDiv = null;

            SpecRunnerUtils.destroyMockEditor(testDoc);
            testEditor = null;
            testDoc = null;
            pane = null;
            ViewStateManager.reset();
        });

        describe("Create Editors", function () {

            it("should create a new editor for a document and add it to a pane", function () {
                spyOn(pane, "addView");
                EditorManager.openDocument(testDoc, pane);
                expect(pane.addView).toHaveBeenCalled();
            });
            it("should use an existing editor for a document and show the editor", function () {
                spyOn(pane, "addView");
                spyOn(pane, "showView");
                var editor = SpecRunnerUtils.createEditorInstance(testDoc, pane.$el);
                EditorManager.openDocument(testDoc, pane);
                expect(pane.addView).toHaveBeenCalled();
                expect(pane.showView).toHaveBeenCalled();
                expect(pane.addView.calls[0].args[0]).toEqual(editor);
            });
        });
    });
    describe("ViewStateManager", function () {
        var pane, testEditor, testDoc, $fakeContentDiv, $fakeHolder;
        beforeEach(function () {
            // Normally the editor holder would be created inside a "content" div, which is
            // used in the available height calculation. We create a fake content div just to
            // hold the height, and we'll place the editor holder in it.
            $fakeContentDiv = $("
")
                .css("height", "200px")
                .appendTo(document.body);

            $fakeHolder = SpecRunnerUtils.createMockElement()
                                        .css("width", "1000px")
                                        .attr("id", "hidden-editors")
                                        .appendTo($fakeContentDiv);

            pane = SpecRunnerUtils.createMockPane($fakeHolder);
            testDoc = SpecRunnerUtils.createMockDocument("");
        });
        afterEach(function () {
            $fakeHolder.remove();
            $fakeHolder = null;

            $fakeContentDiv.remove();
            $fakeContentDiv = null;

            SpecRunnerUtils.destroyMockEditor(testDoc);
            testEditor = null;
            testDoc = null;
            pane = null;
            ViewStateManager.reset();
        });
        describe("Save/Restore View State", function () {
            it("should remember a file's view state", function () {
                ViewStateManager.addViewStates({ a: "1234" });
                expect(ViewStateManager.getViewState({fullPath: "a"})).toEqual("1234");
                ViewStateManager.addViewStates({ b: "Jeff was here" });
                expect(ViewStateManager.getViewState({fullPath: "B"})).toBeUndefined();
                expect(ViewStateManager.getViewState({fullPath: "b"})).toEqual("Jeff was here");
            });
            it("should extend the view state cache", function () {
                ViewStateManager.addViewStates({ a: "1234" });
                ViewStateManager.addViewStates({ b: "5678" });
                expect(ViewStateManager.getViewState({fullPath: "a"})).toEqual("1234");
                expect(ViewStateManager.getViewState({fullPath: "b"})).toEqual("5678");
            });
            it("should reset the view state cache", function () {
                ViewStateManager.addViewStates({ a: "1234" });
                ViewStateManager.addViewStates({ b: "5678" });
                ViewStateManager.reset();
                expect(ViewStateManager.getViewState({fullPath: "a"})).toBeUndefined();
                expect(ViewStateManager.getViewState({fullPath: "b"})).toBeUndefined();
            });
            it("should update the view state cache", function () {
                var myView = {
                    getFile: function () {
                        return {
                            fullPath: "a"
                        };
                    },
                    getViewState: function () {
                        return "1234";
                    }
                };
                ViewStateManager.updateViewState(myView);
                expect(ViewStateManager.getViewState({fullPath: "a"})).toEqual("1234");
            });
        });
    });
});


, sequelizeErrors = require('../../errors')

, dataTypes = require('../../data-types');

ConnectionManager = function(dialect, sequelize) {

'use strict';

/* jshint -W030 */
var chai = require('chai')
  , expect = chai.expect
  , Support = require(__dirname + '/../../support')
  , dialect = Support.getTestDialect()
  , config = require(__dirname + '/../../../config/config')
  , DataTypes = require(__dirname + '/../../../../lib/data-types')
  , _ = require('lodash');

if (dialect.match(/^postgres/)) {
  describe('[POSTGRES Specific] Sequelize', function() {
    it('should correctly parse the moment based timezone', function() {
      var options = _.extend(this.sequelize.options, { timezone: 'Asia/Kolkata', timestamps: true });
      var sequelize = Support.createSequelizeInstance(options);

      var tzTable = sequelize.define('tz_table', { foo: DataTypes.STRING });
      return tzTable.sync({force: true}).then(function() {
        return tzTable.create({foo: 'test'}).then(function(row) {
          expect(row).to.be.not.null;
        }).catch(function(e) {
          expect(e).to.be.null;
        });
      })
    });
  });
}


'use strict';

var Utils = require('./../utils')
  , Helpers = require('./helpers')
  , _ = require('lodash')
  , Association = require('./base')
  , util = require('util');

/**
 * One-to-one association
 *
 * In the API reference below, replace `Association` with the actual name of your association, e.g. for `User.hasOne(Project)` the getter will be `user.getProject()`.
 * This is almost the same as `belongsTo` with one exception. The foreign key will be defined on the target model.
 *
 * @mixin HasOne
 */
var HasOne = function(srcModel, targetModel, options) {
  Association.call(this);

  this.associationType = 'HasOne';
  this.source = srcModel;
  this.target = targetModel;
  this.options = options;
  this.isSingleAssociation = true;
  this.isSelfAssociation = (this.source === this.target);
  this.as = this.options.as;
  this.foreignKeyAttribute = {};

  if (this.as) {
    this.isAliased = true;
    this.options.name = {
      singular: this.as
    };
  } else {
    this.as = this.target.options.name.singular;
    this.options.name = this.target.options.name;
  }

  if (_.isObject(this.options.foreignKey)) {
    this.foreignKeyAttribute = this.options.foreignKey;
    this.foreignKey = this.foreignKeyAttribute.name || this.foreignKeyAttribute.fieldName;
  } else if (this.options.foreignKey) {
    this.foreignKey = this.options.foreignKey;
  }

  if (!this.foreignKey) {
    this.foreignKey = Utils.camelizeIf(
      [
        Utils.underscoredIf(Utils.singularize(this.source.name), this.target.options.underscored),
        this.source.primaryKeyAttribute
      ].join('_'),
      !this.source.options.underscored
    );
  }

  this.sourceIdentifier = this.source.primaryKeyAttribute;
  this.associationAccessor = this.as;
  this.options.useHooks = options.useHooks;

  if (this.target.rawAttributes[this.foreignKey]) {
    this.identifierField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey;
  }

  // Get singular name, trying to uppercase the first letter, unless the model forbids it
  var singular = Utils.uppercaseFirst(this.options.name.singular);

  this.accessors = {
    /**
     * Get the associated instance.
     *
     * @param {Object} [options]
     * @param {String|Boolean} [options.scope] Apply a scope on the related model, or remove its default scope by passing false
     * @param {String} [options.schema] Apply a schema on the related model
     * @return {Promise<Instance>}
     * @method getAssociation
     */
    get: 'get' + singular,
    /**
     * Set the associated model.
     *
     * @param {Instance|String|Number} [newAssociation] An instance or the primary key of an instance to associate with this. Pass `null` or `undefined` to remove the association.
     * @param {Object} [options] Options passed to getAssociation and `target.save`
     * @return {Promise}
     * @method setAssociation
     */
    set: 'set' + singular,
    /**
     * Create a new instance of the associated model and associate it with this.
     *
     * @param {Object} [values]
     * @param {Object} [options] Options passed to `target.create` and setAssociation.
     * @return {Promise}
     * @method createAssociation
     */
    create: 'create' + singular
  };
};

util.inherits(HasOne, Association);

// the id is in the target table
HasOne.prototype.injectAttributes = function() {
  var newAttributes = {}
    , keyType = this.source.rawAttributes[this.source.primaryKeyAttribute].type;

  newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, {
    type: this.options.keyType || keyType,
    allowNull : true
  });
  Utils.mergeDefaults(this.target.rawAttributes, newAttributes);

  this.identifierField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey;

  if (this.options.constraints !== false) {
    var target = this.target.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey];
    this.options.onDelete = this.options.onDelete || (target.allowNull ? 'SET NULL' : 'CASCADE');
    this.options.onUpdate = this.options.onUpdate || 'CASCADE';
  }

  Helpers.addForeignKeyConstraints(this.target.rawAttributes[this.foreignKey], this.source, this.target, this.options);

  // Sync attributes and setters/getters to Model prototype
  this.target.refreshAttributes();

  Helpers.checkNamingCollision(this);

  return this;
};

HasOne.prototype.injectGetter = function(instancePrototype) {
  var association = this;

  instancePrototype[this.accessors.get] = function(options) {
    var where = {};
    where[association.foreignKey] = this.get(association.sourceIdentifier);

    options = association.target.__optClone(options) || {};

    options.where = {
      $and: [
        options.where,
        where
      ]
    };

    if (options.limit === undefined) options.limit = null;

    var model = association.target;
    if (options.hasOwnProperty('scope')) {
      if (!options.scope) {
        model = model.unscoped();
      } else {
        model = model.scope(options.scope);
      }
    }

    if (options.hasOwnProperty('schema')) {
      model = model.schema(options.schema, options.schemaDelimiter);
    }

    return model.find(options);
  };

  return this;
};

HasOne.prototype.injectSetter = function(instancePrototype) {
  var association = this;

  instancePrototype[this.accessors.set] = function(associatedInstance, options) {
    var instance = this;

    options = options || {};
    options.scope = false;
    return instance[association.accessors.get](options).then(function(oldInstance) {
      if (oldInstance) {
        oldInstance[association.foreignKey] = null;
        return oldInstance.save(_.extend({}, options, {
          fields: [association.foreignKey],
          allowNull: [association.foreignKey],
          association: true
        }));
      }
    }).then(function() {
      if (associatedInstance) {
        if (!(associatedInstance instanceof association.target.Instance)) {
          var tmpInstance = {};
          tmpInstance[association.target.primaryKeyAttribute] = associatedInstance;
          associatedInstance = association.target.build(tmpInstance, {
            isNewRecord: false
          });
        }
        associatedInstance.set(association.foreignKey, instance.get(association.sourceIdentifier));
        return associatedInstance.save(options);
      }
      return null;
    });
  };

  return this;
};

HasOne.prototype.injectCreator = function(instancePrototype) {
  var association = this;

  instancePrototype[this.accessors.create] = function(values, options) {
    var instance = this;
    values = values || {};
    options = options || {};

    values[association.foreignKey] = instance.get(association.sourceIdentifier);
    if (options.fields) options.fields.push(association.foreignKey);
    return association.target.create(values, options);
  };

  return this;
};

module.exports = HasOne;