<commit_before>// MongoDB stuff
// Created by Fredrik A. Madsen-Malmo

// Imports
var mongo = require('mongodb').MongoClient;
var assert = require('assert');
var Promise = require('promise');

// Mongo config
var PORT = 27017 || process.env.MONGOPORT;
var HOST = 'localhost' || process.env.MONGOHOST;
var DB = 'serverstatus' || process.env.MONGODB;

var URL = 'mongodb://' + HOST + ':' + PORT + '/' + DB;

// Base function
var WEEKDAYS = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday'
];

/**
 * Connects to the database and calls the anon function provided
 * @param  {Function}  Func Anon function to call
 * @return {null}      No return value
 */
var connect = function (func) {
    mongo.connect(URL, function (err, db) {
        if (err) {
            throw err;
        }

        assert.equal(null, err);
        func(db);
    });
};

// DB functions

/**
 * Callback used for the isert function
 * @param  {Object}   err     This is the Error object that describes the error encountered
 * @param  {Object}   result  This is the result, contains all info about the insert
 * @param  {Object}   db      The database object, here I use it to close the db
 * @param  {Function} resolve This is the function to be called when the script completes
 * @param  {Function} reject  This is the function to be called if the script fails
 * @return {Object}           Resolve or Reject
 */
function insertCallback (err, result, db, resolve, reject) {
    if (err) {
        reject(err);
    }

    assert.equal(err, null);

    db.close();
    resolve(result);
}

/**
 * Insert an entry into the db
 * @param  {String}   mode  either 'temp' or 'load'; what kind of entry
 * @param  {String}    value the value to insert.
 * @return {Function} A promise with the value passed in
 */
var insert = function (mode, value) {
    return new Promise(function (resolve, reject) {
        connect(function (db) {
            if (mode.toLowerCase() == 'temp') {
                db.collection('temp').insertOne({
                    "time": new Date(),
                    "temp": (parseFloat(value))
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else if (mode.toLowerCase() == 'load') {
                db.collection('load').insertOne({
                    "time": new Date(),
                    "load": ((parseFloat(value) / 4) * 100)
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else {
                db.close();
                reject('Invalid input');
            }
        });
    });
};

/**
 * Gets the 20 last entries of one mode
 * @param  {String} mode The type of entry to retrieve
 * @return {Function}    Returns either a resolve or reject function
 */
var realtime = function (mode) {
    var latest = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var cursor = db.collection(mode).find({  }).limit(20).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    // Push [hh:mm:ss, temp|load] to latest
                    latest.push([doc.time.toTimeString().substr(0, 8),
                                 (doc.temp || doc.load)]);
                } else {
                    resolve(latest);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the 20 last minutes
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with HH:MM and temp|load:float
 */
var minute = function (mode) {
    var minutes = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 20 && doc.time.getMinutes() == prev) {
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0, 5),
                                          (minutes[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getMinutes() != prev) {
                        count++;
                        prev = doc.time.getMinutes();
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0,5),
                                          0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(minutes);
                        db.close();
                    }
                } else {
                    resolve(minutes);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last 10 hours
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date, hour:00
 */
var hour = function(mode) {
    var hours = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 10 && doc.time.getHours() == prev) {
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        (hours[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getHours() != prev) {
                        count++;
                        prev = doc.time.getHours();
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(hours);
                        db.close();
                    }
                } else {
                    resolve(hours);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last week
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date/month
 */
var day = function(mode) {
    var days = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 7 && doc.time.getDate() == prev) {
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        (days[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getDate() != prev) {
                        count++;
                        prev = doc.time.getDate();
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(days);
                        db.close();
                    }
                } else {
                    resolve(days);
                    db.close();
                }
            });
        });
    });
};

// Exports

module.exports = {
    insert: insert,
    realtime: realtime,
    minute: minute,
    hour: hour,
    day: day
};
<commit_msg>fix float parse<commit_after>// MongoDB stuff
// Created by Fredrik A. Madsen-Malmo

// Imports
var mongo = require('mongodb').MongoClient;
var assert = require('assert');
var Promise = require('promise');

// Mongo config
var PORT = 27017 || process.env.MONGOPORT;
var HOST = 'localhost' || process.env.MONGOHOST;
var DB = 'serverstatus' || process.env.MONGODB;

var URL = 'mongodb://' + HOST + ':' + PORT + '/' + DB;

// Base function
var WEEKDAYS = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday'
];

/**
 * Connects to the database and calls the anon function provided
 * @param  {Function}  Func Anon function to call
 * @return {null}      No return value
 */
var connect = function (func) {
    mongo.connect(URL, function (err, db) {
        if (err) {
            throw err;
        }

        assert.equal(null, err);
        func(db);
    });
};

// DB functions

/**
 * Callback used for the isert function
 * @param  {Object}   err     This is the Error object that describes the error encountered
 * @param  {Object}   result  This is the result, contains all info about the insert
 * @param  {Object}   db      The database object, here I use it to close the db
 * @param  {Function} resolve This is the function to be called when the script completes
 * @param  {Function} reject  This is the function to be called if the script fails
 * @return {Object}           Resolve or Reject
 */
function insertCallback (err, result, db, resolve, reject) {
    if (err) {
        reject(err);
    }

    assert.equal(err, null);

    db.close();
    resolve(result);
}

/**
 * Insert an entry into the db
 * @param  {String}   mode  either 'temp' or 'load'; what kind of entry
 * @param  {String}    value the value to insert.
 * @return {Function} A promise with the value passed in
 */
var insert = function (mode, value) {
    return new Promise(function (resolve, reject) {
        connect(function (db) {
            if (mode.toLowerCase() == 'temp') {
                db.collection('temp').insertOne({
                    "time": new Date(),
                    "temp": (parseFloat(value.replace(',', '.')))
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else if (mode.toLowerCase() == 'load') {
                db.collection('load').insertOne({
                    "time": new Date(),
                    "load": ((parseFloat(value) / 4) * 100)
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else {
                db.close();
                reject('Invalid input');
            }
        });
    });
};

/**
 * Gets the 20 last entries of one mode
 * @param  {String} mode The type of entry to retrieve
 * @return {Function}    Returns either a resolve or reject function
 */
var realtime = function (mode) {
    var latest = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var cursor = db.collection(mode).find({  }).limit(20).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    // Push [hh:mm:ss, temp|load] to latest
                    latest.push([doc.time.toTimeString().substr(0, 8),
                                 (doc.temp || doc.load)]);
                } else {
                    resolve(latest);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the 20 last minutes
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with HH:MM and temp|load:float
 */
var minute = function (mode) {
    var minutes = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 20 && doc.time.getMinutes() == prev) {
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0, 5),
                                          (minutes[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getMinutes() != prev) {
                        count++;
                        prev = doc.time.getMinutes();
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0,5),
                                          0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(minutes);
                        db.close();
                    }
                } else {
                    resolve(minutes);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last 10 hours
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date, hour:00
 */
var hour = function(mode) {
    var hours = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 10 && doc.time.getHours() == prev) {
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        (hours[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getHours() != prev) {
                        count++;
                        prev = doc.time.getHours();
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(hours);
                        db.close();
                    }
                } else {
                    resolve(hours);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last week
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date/month
 */
var day = function(mode) {
    var days = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 7 && doc.time.getDate() == prev) {
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        (days[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getDate() != prev) {
                        count++;
                        prev = doc.time.getDate();
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(days);
                        db.close();
                    }
                } else {
                    resolve(days);
                    db.close();
                }
            });
        });
    });
};

// Exports

module.exports = {
    insert: insert,
    realtime: realtime,
    minute: minute,
    hour: hour,
    day: day
};
<|endoftext|>


<commit_before>/*!
 * datastructures-js
 * dependency container
 * Copyright(c) 2015 Eyas Ranjous <eyas@eyasranjous.info>
 * MIT Licensed
 */

'use strict';

var modules = {
    itr: require('./lib/iterators'),
    nd: require('./lib/nodes'),
    ds: require('./lib/dataStructures')
};

module.exports = (function() {

    var self = {};

    self.exportObject = function(obj) {
        return obj.export();
    };

    self.getFactory = function(module, name, args) {
        return modules[module][name].apply(null, args);
    };

    self.getHtIteratorFactory = function() {
        var iteratorFactory = this.getFactory('itr', 'iterator');
        return this.getFactory('itr', 'hashtableIterator', [iteratorFactory]);
    };

    self.getDllNodeFactory = function() {
        var llNodeFactory = this.getFactory('nd', 'linkedListNode');
        return this.getFactory('nd', 'doublyLinkedListNode', [llNodeFactory]);
    };

    self.getBstNodeFactory = function() {
        var dllNodeFactory = this.getDllNodeFactory();
        return this.getFactory('nd', 'binaryTreeNode', [dllNodeFactory]);
    };

    self.getSetFactory = function() {
        var iteratorFactory = this.getFactory('itr', 'iterator');
        return this.getFactory('ds', 'set', [iteratorFactory]);
    };

    self.getPriorityQueueFactory = function() {
        var queue = this.getFactory('ds', 'queue')();
        return this.getFactory('ds', 'priorityQueue', [queue]);
    };

    self.getLinkedListFactory = function() {
        var llNodeFactory = this.getFactory('nd', 'linkedListNode');
        return this.getFactory('ds', 'linkedList', [llNodeFactory]);
    };

    self.getDoublyLinkedListFactory = function() {
        var linkedList = this.getFactory('ds', 'linkedList')(),
            dllNodeFactory = this.getDllNodeFactory();
        return this.getFactory('ds', 'doublyLinkedList', [dllNodeFactory, linkedList]);
    };

    self.getHashtableFactory = function() {
        var htPairFactory = this.getFactory('nd', 'hashTablePair'),
            htIteratorFactory = this.getHtIteratorFactory();
        return this.getFactory('ds', 'hashtable', [htPairFactory, htIteratorFactory]);
    };

    self.getBinarySearchTreeFactory = function() {
        var bstNodeFactory = this.getBstNodeFactory();
        return this.getFactory('ds', 'binarySearchTree', [bstNodeFactory]);
    };

    return self;
}());<commit_msg>inject hashFunction into hashtable<commit_after>/*!
 * datastructures-js
 * dependency container
 * Copyright(c) 2015 Eyas Ranjous <eyas@eyasranjous.info>
 * MIT Licensed
 */

'use strict';

var modules = {
    itr: require('./lib/iterators'),
    nd: require('./lib/nodes'),
    ds: require('./lib/dataStructures'),
    hlp: require('./lib/helpers')
};

module.exports = (function() {

    var self = {};

    self.exportObject = function(obj) {
        return obj.export();
    };

    self.getFactory = function(module, name, args) {
        return modules[module][name].apply(null, args);
    };

    self.getHtIteratorFactory = function() {
        var iteratorFactory = this.getFactory('itr', 'iterator');
        return this.getFactory('itr', 'hashtableIterator', [iteratorFactory]);
    };

    self.getDllNodeFactory = function() {
        var llNodeFactory = this.getFactory('nd', 'linkedListNode');
        return this.getFactory('nd', 'doublyLinkedListNode', [llNodeFactory]);
    };

    self.getBstNodeFactory = function() {
        var dllNodeFactory = this.getDllNodeFactory();
        return this.getFactory('nd', 'binaryTreeNode', [dllNodeFactory]);
    };

    self.getSetFactory = function() {
        var iteratorFactory = this.getFactory('itr', 'iterator');
        return this.getFactory('ds', 'set', [iteratorFactory]);
    };

    self.getPriorityQueueFactory = function() {
        var queue = this.getFactory('ds', 'queue')();
        return this.getFactory('ds', 'priorityQueue', [queue]);
    };

    self.getLinkedListFactory = function() {
        var llNodeFactory = this.getFactory('nd', 'linkedListNode');
        return this.getFactory('ds', 'linkedList', [llNodeFactory]);
    };

    self.getDoublyLinkedListFactory = function() {
        var linkedList = this.getFactory('ds', 'linkedList')(),
            dllNodeFactory = this.getDllNodeFactory();
        return this.getFactory('ds', 'doublyLinkedList', [dllNodeFactory, linkedList]);
    };

    self.getHashtableFactory = function() {
        var htPairFactory = this.getFactory('nd', 'hashTablePair'),
            hashFunction = this.getFactory('hlp', 'sumCharsHash', [31, 104729]),
            htIteratorFactory = this.getHtIteratorFactory();
        return this.getFactory('ds', 'hashtable',
            [htPairFactory, htIteratorFactory, hashFunction]);
    };

    self.getBinarySearchTreeFactory = function() {
        var bstNodeFactory = this.getBstNodeFactory();
        return this.getFactory('ds', 'binarySearchTree', [bstNodeFactory]);
    };

    return self;
}());<|endoftext|>


<commit_before>/**
 * The 'id' function is essentially the "base class" for all Objective-C
 * objects that get passed around JS-land.
 */

var proto = exports.proto = Object.create(Function.prototype)
  , core  = require('./core')
  , types = require('./types')
  , SEL   = require('./sel')
  , exception = require('./exception')

/**
 * Wraps up a pointer that is expected to be a compatible Objective-C
 * object that can recieve messages.
 */
exports.wrap = function wrap (pointer) {

  // This 'id' function is syntax sugar around the msgSend function attached to
  // it. 'msgSend' is expecting the selector first, an Array of args second, so
  // this function just massages it into place and returns the result.
  function id () {
    var args = []
      , sel
    if (arguments.length === 1) {
      var arg = arguments[0]
      if (arg.constructor.name == 'String') {
        sel = arg
      } else {
        sel = []
        Object.keys(arg).forEach(function (s) {
          sel.push(s)
          args.push(arg[s])
        })
        sel.push('')
        sel = sel.join(':')
      }
    } else {
      sel = []
      var len = arguments.length
      for (var i=0; i<len; i+=2) {
        sel.push(arguments[i])
        args.push(arguments[i+1])
      }
      sel.push('')
      sel = sel.join(':')
    }
    return id.msgSend(sel, args)
  }

  // Save a reference to the pointer for use by the prototype functions
  id.pointer = pointer;
  // Morph into a MUTANT FUNCTION FREAK!!1!
  id.__proto__ = proto;
  return id;
}
// Avoid a circular dep.
core._idwrap = exports.wrap;

/**
 * A very important function that *does the message sending* between
 * Objective-C objects. When you do `array('addObject', anObject)`, this
 * `msgSend` function is the one that finally gets called to do the dirty work.
 *
 * This function accepts a String selector as the first argument, and an Array
 * of (wrapped) values that get passed to the the message. This function takes
 * care of unwrapping the passing in arguments an wrapping up the result value,
 * if necessary.
 *
 * If you wanted to monkey-patch *every* message that got sent out from an
 * object though NodObjC, this is the place to do it.
 */
proto.msgSend = function msgSend (sel, args) {
  var types = this._getTypes(sel)
    , argTypes = types[1]
    , msgSendFunc = core.get_objc_msgSend(types)
    , unwrappedArgs = core.unwrapValues([this, sel].concat(args), argTypes)
    , rtn
  try {
    rtn = msgSendFunc.apply(null, unwrappedArgs)
  } catch (e) {
    throw exception.wrap(e)
  }
  // Process the return value into a wrapped value if needed
  return core.wrapValue(rtn, types[0])
}

/**
 * Accepts a SEL and queries the current object for the return type and
 * argument types for the given selector. If current object does not implment
 * that selector, then check the superclass, and repeat recursively until
 * a subclass that responds to the selector is found, or until the base class
 * is found (in which case the current obj does not respond to 'sel' and we
 * should throw an Error).
 */
proto._getTypes = function getTypes (sel) {
  var c = this.getClass()
    , t = c._getTypesClass(sel, this.isClass)
  if (!t) throw new Error('Object does not respond to selector: '+sel);
  return t;
}

/**
 * Retrieves the wrapped Class instance for this object.
 */
proto.getClass = function getClass () {
  return exports._wrapClass(this._getClassPointer());
}

/**
 * Returns the node-ffi pointer for the class of this object.
 */
proto._getClassPointer = function getClassPointer () {
  return core.object_getClass(this.pointer)
}

/**
 * Calls 'object_getClassName()' on this object.
 */
proto.getClassName = function getClassName () {
  return core.object_getClassName(this.pointer);
}

/**
 * Dynamically changes the object's Class.
 */
proto.setClass = function setClass (newClass) {
  return exports._wrapClass(core.object_setClass(this.pointer, newClass.pointer));
}

/**
 * Walks up the inheritance chain and returns an Array of Strings of
 * superclasses.
 */
proto.ancestors = function ancestors () {
  var rtn = []
    , c = this.getClass()
  while (c) {
    rtn.push(c.getName())
    c = c.getSuperclass()
  }
  return rtn
}

proto.ivars = function ivars (maxDepth, sort) {
  var rtn = []
    , c = this.getClass()
    , md = maxDepth || 1
    , depth = 0
  while (c && depth++ < md) {
    var is = c.getInstanceVariables()
      , i = is.length
    while (i--) {
      if (!~rtn.indexOf(is[i])) rtn.push(is[i])
    }
    c = c.getSuperclass()
  }
  return sort === false ? rtn : rtn.sort()
}

/**
 * Returns an Array of Strings of the names of methods that the current object
 * will respond to. This function can iterate through the object's superclasses
 * recursively, if you specify a 'maxDepth' number argument.
 */
proto.methods = function methods (maxDepth, sort) {
  var rtn = []
    , c = this.getClass()
    , md = maxDepth || 1
    , depth = 0
  while (c && depth++ < md) {
    var ms = c.getInstanceMethods()
      , i = ms.length
    while (i--) {
      if (!~rtn.indexOf(ms[i])) rtn.push(ms[i]);
    }
    c = c.getSuperclass()
  }
  return sort === false ? rtn : rtn.sort()
}

/**
 * The id wrap's overidden toString() function proxies up to the id's
 * description method:  [[id description] UTF8String]
 */
proto.toString = function toString () {
  return this('description')('UTF8String');
}

proto.inspect = function inspect () {
  return this.toString()
}
<commit_msg>Defer 'unknown selector' errors to the Objective-C Runtime. Now that we have try/catch support this is the *correct* way to go.<commit_after>/**
 * The 'id' function is essentially the "base class" for all Objective-C
 * objects that get passed around JS-land.
 */

var proto = exports.proto = Object.create(Function.prototype)
  , core  = require('./core')
  , types = require('./types')
  , SEL   = require('./sel')
  , exception = require('./exception')

/**
 * Wraps up a pointer that is expected to be a compatible Objective-C
 * object that can recieve messages.
 */
exports.wrap = function wrap (pointer) {

  // This 'id' function is syntax sugar around the msgSend function attached to
  // it. 'msgSend' is expecting the selector first, an Array of args second, so
  // this function just massages it into place and returns the result.
  function id () {
    var args = []
      , sel
    if (arguments.length === 1) {
      var arg = arguments[0]
      if (arg.constructor.name == 'String') {
        sel = arg
      } else {
        sel = []
        Object.keys(arg).forEach(function (s) {
          sel.push(s)
          args.push(arg[s])
        })
        sel.push('')
        sel = sel.join(':')
      }
    } else {
      sel = []
      var len = arguments.length
      for (var i=0; i<len; i+=2) {
        sel.push(arguments[i])
        args.push(arguments[i+1])
      }
      sel.push('')
      sel = sel.join(':')
    }
    return id.msgSend(sel, args)
  }

  // Save a reference to the pointer for use by the prototype functions
  id.pointer = pointer;
  // Morph into a MUTANT FUNCTION FREAK!!1!
  id.__proto__ = proto;
  return id;
}
// Avoid a circular dep.
core._idwrap = exports.wrap;

/**
 * A very important function that *does the message sending* between
 * Objective-C objects. When you do `array('addObject', anObject)`, this
 * `msgSend` function is the one that finally gets called to do the dirty work.
 *
 * This function accepts a String selector as the first argument, and an Array
 * of (wrapped) values that get passed to the the message. This function takes
 * care of unwrapping the passing in arguments an wrapping up the result value,
 * if necessary.
 *
 * If you wanted to monkey-patch *every* message that got sent out from an
 * object though NodObjC, this is the place to do it.
 */
proto.msgSend = function msgSend (sel, args) {
  var types = this._getTypes(sel, args)
    , argTypes = types[1]
    , msgSendFunc = core.get_objc_msgSend(types)
    , unwrappedArgs = core.unwrapValues([this, sel].concat(args), argTypes)
    , rtn
  try {
    rtn = msgSendFunc.apply(null, unwrappedArgs)
  } catch (e) {
    throw exception.wrap(e)
  }
  // Process the return value into a wrapped value if needed
  return core.wrapValue(rtn, types[0])
}

/**
 * Accepts a SEL and queries the current object for the return type and
 * argument types for the given selector. If current object does not implment
 * that selector, then check the superclass, and repeat recursively until
 * a subclass that responds to the selector is found, or until the base class
 * is found (in which case the current obj does not respond to 'sel' and we
 * should throw an Error).
 */
proto._getTypes = function getTypes (sel, args) {
  var c = this.getClass()
    , t = c._getTypesClass(sel, this.isClass)
  if (!t) {
    // Unknown selector being send to object. This *may* still be valid, we
    // assume all args are type 'id' and return is 'id'.
    //console.error('unknown selector being sent: %s', sel)
    t = [ '@', [ '@', ':', ].concat(args.map(function () { return '@' })) ]
  }
  return t
}

/**
 * Retrieves the wrapped Class instance for this object.
 */
proto.getClass = function getClass () {
  return exports._wrapClass(this._getClassPointer());
}

/**
 * Returns the node-ffi pointer for the class of this object.
 */
proto._getClassPointer = function getClassPointer () {
  return core.object_getClass(this.pointer)
}

/**
 * Calls 'object_getClassName()' on this object.
 */
proto.getClassName = function getClassName () {
  return core.object_getClassName(this.pointer);
}

/**
 * Dynamically changes the object's Class.
 */
proto.setClass = function setClass (newClass) {
  return exports._wrapClass(core.object_setClass(this.pointer, newClass.pointer));
}

/**
 * Walks up the inheritance chain and returns an Array of Strings of
 * superclasses.
 */
proto.ancestors = function ancestors () {
  var rtn = []
    , c = this.getClass()
  while (c) {
    rtn.push(c.getName())
    c = c.getSuperclass()
  }
  return rtn
}

proto.ivars = function ivars (maxDepth, sort) {
  var rtn = []
    , c = this.getClass()
    , md = maxDepth || 1
    , depth = 0
  while (c && depth++ < md) {
    var is = c.getInstanceVariables()
      , i = is.length
    while (i--) {
      if (!~rtn.indexOf(is[i])) rtn.push(is[i])
    }
    c = c.getSuperclass()
  }
  return sort === false ? rtn : rtn.sort()
}

/**
 * Returns an Array of Strings of the names of methods that the current object
 * will respond to. This function can iterate through the object's superclasses
 * recursively, if you specify a 'maxDepth' number argument.
 */
proto.methods = function methods (maxDepth, sort) {
  var rtn = []
    , c = this.getClass()
    , md = maxDepth || 1
    , depth = 0
  while (c && depth++ < md) {
    var ms = c.getInstanceMethods()
      , i = ms.length
    while (i--) {
      if (!~rtn.indexOf(ms[i])) rtn.push(ms[i]);
    }
    c = c.getSuperclass()
  }
  return sort === false ? rtn : rtn.sort()
}

/**
 * The id wrap's overidden toString() function proxies up to the id's
 * description method:  [[id description] UTF8String]
 */
proto.toString = function toString () {
  return this('description')('UTF8String');
}

proto.inspect = function inspect () {
  return this.toString()
}
<|endoftext|>


<commit_before>GameBoyAdvanceIO = function() {
	// Video
	this.DISPCNT = 0x000;
	this.GREENSWP = 0x002;
	this.DISPSTAT = 0x004;
	this.VCOUNT = 0x006;
	this.BG0CNT = 0x008;
	this.BG1CNT = 0x00A;
	this.BG2CNT = 0x00C;
	this.BG3CNT = 0x00E;
	this.BG0HOFS = 0x010;
	this.BG0VOFS = 0x012;
	this.BG1HOFS = 0x014;
	this.BG1VOFS = 0x016;
	this.BG2HOFS = 0x018;
	this.BG2VOFS = 0x01A;
	this.BG3HOFS = 0x01C;
	this.BG3VOFS = 0x01E;
	this.BG2PA = 0x020;
	this.BG2PB = 0x022;
	this.BG2PC = 0x024;
	this.BG2PD = 0x026;
	this.BG2X_LO = 0x028;
	this.BG2X_HI = 0x02E;
	this.BG2Y_LO = 0x02C;
	this.BG2Y_HI = 0x02E;
	this.BG3PA = 0x030;
	this.BG3PB = 0x032;
	this.BG3PC = 0x034;
	this.BG3PD = 0x036;
	this.BG3X_LO = 0x038;
	this.BG3X_HI = 0x03A;
	this.BG3Y_LO = 0x03C;
	this.BG3Y_HI = 0x03E;
	this.WIN0H = 0x040;
	this.WIN1H = 0x042;
	this.WIN0V = 0x044;
	this.WIN1V = 0x046;
	this.WININ = 0x048;
	this.WINOUT = 0x04A;
	this.MOSAIC = 0x04C;
	this.BLDCNT = 0x050;
	this.BLDALPHA = 0x052;
	this.BLDY = 0x054;

	// Sound
	this.SOUND1CNT_LO = 0x060;
	this.SOUND1CNT_HI = 0x062;
	this.SOUND1CNT_X = 0x064;
	this.SOUND2CNT_LO = 0x068;
	this.SOUND2CNT_HI = 0x06C;
	this.SOUND3CNT_LO = 0x070;
	this.SOUND3CNT_HI = 0x072;
	this.SOUND3CNT_X = 0x074;
	this.SOUND4CNT_LO = 0x078;
	this.SOUND4CNT_HI = 0x07C;
	this.SOUNDCNT_L0 = 0x080;
	this.SOUNDCNT_HI = 0x082;
	this.SOUNDCNT_X = 0x084;
	this.SOUNDBIAS = 0x088;
	this.FIFO_A_LO = 0x0A0;
	this.FIFO_A_HI = 0x0A2;
	this.FIFO_B_LO = 0x0A4;
	this.FIFO_B_HI = 0x0A6;

	// DMA
	this.DMA0SAD_LO = 0x0B0;
	this.DMA0SAD_HI = 0x0B2;
	this.DMA0DAD_LO = 0x0B4;
	this.DMA0DAD_HI = 0x0B6;
	this.DMA0CNT_LO = 0x0B8;
	this.DMA0CNT_HI = 0x0BA;
	this.DMA1SAD_LO = 0x0BC;
	this.DMA1SAD_HI = 0x0BE;
	this.DMA1DAD_LO = 0x0C0;
	this.DMA1DAD_HI = 0x0C2;
	this.DMA1CNT_LO = 0x0C4;
	this.DMA1CNT_HI = 0x0C6;
	this.DMA2SAD_LO = 0x0C8;
	this.DMA2SAD_HI = 0x0CA;
	this.DMA2DAD_LO = 0x0CC;
	this.DMA2DAD_HI = 0x0CE;
	this.DMA2CNT_LO = 0x0D0;
	this.DMA2CNT_HI = 0x0D2;
	this.DMA3SAD_LO = 0x0D4;
	this.DMA3SAD_HI = 0x0D6;
	this.DMA3DAD_LO = 0x0D8;
	this.DMA3DAD_HI = 0x0DA;
	this.DMA3CNT_LO = 0x0DC;
	this.DMA3CNT_HI = 0x0DE;

	// Timers
	this.TM0CNT_LO = 0x100;
	this.TM0CNT_HI = 0x102;
	this.TM1CNT_LO = 0x104;
	this.TM1CNT_HI = 0x106;
	this.TM2CNT_LO = 0x108;
	this.TM2CNT_HI = 0x10A;
	this.TM3CNT_LO = 0x10C;
	this.TM3CNT_HI = 0x10E;

	// Keypad
	this.KEYINPUT = 0x130;
	this.KEYCNT = 0x132;

	// Interrupts, etc
	this.IE = 0x200;
	this.IF = 0x202;
	this.WAITCNT = 0x204;
	this.IME = 0x208;

	this.DEFAULT_SOUNDBIAS = 0x200;
};

GameBoyAdvanceIO.prototype.setCPU = function(cpu) {
	this.cpu = cpu;
};

GameBoyAdvanceIO.prototype.setVideo = function(video) {
	this.video = video;
};

GameBoyAdvanceIO.prototype.clear = function() {
	this.registers = new Uint16Array(this.cpu.mmu.SIZE_IO);

	this.registers[this.SOUNDBIAS >> 1] = this.DEFAULT_SOUNDBIAS;
};

GameBoyAdvanceIO.prototype.load8 = function(offset) {
	throw "Unimplmeneted unaligned I/O access";
}

GameBoyAdvanceIO.prototype.load16 = function(offset) {
	return this.loadU16(offset) >> 0;
}

GameBoyAdvanceIO.prototype.load32 = function(offset) {
	switch (offset) {
	case this.DMA0CNT_LO:
	case this.DMA1CNT_LO:
	case this.DMA2CNT_LO:
	case this.DMA3CNT_LO:
		return this.loadU16(offset | 2) << 16;
	}

	return this.loadU16(offset) | (this.loadU16(offset | 2) << 16);
};

GameBoyAdvanceIO.prototype.loadU8 = function(offset) {
	var odd = offset & 0x0001;
	var value = this.loadU16(offset & 0xFFFE);
	return (value >>> (odd << 3)) & 0xFF;
}

GameBoyAdvanceIO.prototype.loadU16 = function(offset) {
	switch (offset) {
	case this.DISPCNT:
	case this.SOUNDBIAS:
	case this.WAITCNT:
	case this.IE:
	case this.IME:
		// Handled transparently by the written registers
		break;
	case this.DISPSTAT:
		return this.registers[offset >> 1] | this.video.readDisplayStat();
	case this.DMA0CNT_HI:
	case this.DMA1CNT_HI:
	case this.DMA2CNT_HI:
	case this.DMA3CNT_HI:
		break;
	default:
		throw "Unimplemented I/O register read: 0x" + offset.toString(16);
	}
	return this.registers[offset >> 1];
};

GameBoyAdvanceIO.prototype.store16 = function(offset, value) {
	switch (offset) {
	// Video
	case this.DISPCNT:
		this.video.writeDisplayControl(value);
		break;
	case this.DISPSTAT:
		value &= this.video.DISPSTAT_MASK;
		this.video.writeDisplayStat(value);
		break;

	// Sound
	// TODO: implement sound
	case this.SOUNDCNT_LO:
		value &= 0xFF77;
		break;
	case this.SOUNDCNT_HI:
		value &= 0xFF0F;
		break;
	case this.SOUNDCNT_X:
		value &= 0x0080;
		break;

	// DMA
	case this.DMA0CNT_LO:
		this.cpu.irq.dmaSetWordCount(0, value);
		//return;
		break;
	case this.DMA0CNT_HI:
		// The DMA registers need to set the values before writing the control, as writing the
		// control can synchronously trigger a DMA transfer
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(0, value);
		break;
	case this.DMA1CNT_LO:
		this.cpu.irq.dmaSetWordCount(1, value);
		//return;
		break;
	case this.DMA1CNT_HI:
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(1, value);
		break;
	case this.DMA2CNT_LO:
		this.cpu.irq.dmaSetWordCount(2, value);
		//return;
		break;
	case this.DMA2CNT_HI:
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(2, value);
		break;
	case this.DMA3CNT_LO:
		this.cpu.irq.dmaSetWordCount(3, value);
		//return;
		break;
	case this.DMA3CNT_HI:
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(3, value);
		return;

	// Misc
	case this.IE:
		value &= 0x3FFF;
		this.cpu.irq.setInterruptsEnabled(value);
		break;
	case this.WAITCNT:
		// TODO: implement this
		value &= 0x5FFF;
		break;
	case this.IME:
		value &= 0x0001;
		this.cpu.irq.masterEnable(value);
		break;
	default:
		throw "Unimplemented I/O register write: 0x" + offset.toString(16);
	}
	this.registers[offset >> 1] = value;
};

GameBoyAdvanceIO.prototype.store32 = function(offset, value) {
	switch (offset) {
	case this.DMA0SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(0, value);
		return;
	case this.DMA0DAD_LO:
		this.cpu.irq.dmaSetDestAddress(0, value);
		return;
	case this.DMA1SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(1, value);
		return;
	case this.DMA1DAD_LO:
		this.cpu.irq.dmaSetDestAddress(1, value);
		return;
	case this.DMA2SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(2, value);
		return;
	case this.DMA2DAD_LO:
		this.cpu.irq.dmaSetDestAddress(2, value);
		return;
	case this.DMA3SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(3, value);
		return;
	case this.DMA3DAD_LO:
		this.cpu.irq.dmaSetDestAddress(3, value);
		return;
	}

	this.store16(offset, value & 0xFFFF);
	this.store16(offset + 2, value >> 16);
};
<commit_msg>Add some unimplemented sound register writes<commit_after>GameBoyAdvanceIO = function() {
	// Video
	this.DISPCNT = 0x000;
	this.GREENSWP = 0x002;
	this.DISPSTAT = 0x004;
	this.VCOUNT = 0x006;
	this.BG0CNT = 0x008;
	this.BG1CNT = 0x00A;
	this.BG2CNT = 0x00C;
	this.BG3CNT = 0x00E;
	this.BG0HOFS = 0x010;
	this.BG0VOFS = 0x012;
	this.BG1HOFS = 0x014;
	this.BG1VOFS = 0x016;
	this.BG2HOFS = 0x018;
	this.BG2VOFS = 0x01A;
	this.BG3HOFS = 0x01C;
	this.BG3VOFS = 0x01E;
	this.BG2PA = 0x020;
	this.BG2PB = 0x022;
	this.BG2PC = 0x024;
	this.BG2PD = 0x026;
	this.BG2X_LO = 0x028;
	this.BG2X_HI = 0x02E;
	this.BG2Y_LO = 0x02C;
	this.BG2Y_HI = 0x02E;
	this.BG3PA = 0x030;
	this.BG3PB = 0x032;
	this.BG3PC = 0x034;
	this.BG3PD = 0x036;
	this.BG3X_LO = 0x038;
	this.BG3X_HI = 0x03A;
	this.BG3Y_LO = 0x03C;
	this.BG3Y_HI = 0x03E;
	this.WIN0H = 0x040;
	this.WIN1H = 0x042;
	this.WIN0V = 0x044;
	this.WIN1V = 0x046;
	this.WININ = 0x048;
	this.WINOUT = 0x04A;
	this.MOSAIC = 0x04C;
	this.BLDCNT = 0x050;
	this.BLDALPHA = 0x052;
	this.BLDY = 0x054;

	// Sound
	this.SOUND1CNT_LO = 0x060;
	this.SOUND1CNT_HI = 0x062;
	this.SOUND1CNT_X = 0x064;
	this.SOUND2CNT_LO = 0x068;
	this.SOUND2CNT_HI = 0x06C;
	this.SOUND3CNT_LO = 0x070;
	this.SOUND3CNT_HI = 0x072;
	this.SOUND3CNT_X = 0x074;
	this.SOUND4CNT_LO = 0x078;
	this.SOUND4CNT_HI = 0x07C;
	this.SOUNDCNT_LO = 0x080;
	this.SOUNDCNT_HI = 0x082;
	this.SOUNDCNT_X = 0x084;
	this.SOUNDBIAS = 0x088;
	this.FIFO_A_LO = 0x0A0;
	this.FIFO_A_HI = 0x0A2;
	this.FIFO_B_LO = 0x0A4;
	this.FIFO_B_HI = 0x0A6;

	// DMA
	this.DMA0SAD_LO = 0x0B0;
	this.DMA0SAD_HI = 0x0B2;
	this.DMA0DAD_LO = 0x0B4;
	this.DMA0DAD_HI = 0x0B6;
	this.DMA0CNT_LO = 0x0B8;
	this.DMA0CNT_HI = 0x0BA;
	this.DMA1SAD_LO = 0x0BC;
	this.DMA1SAD_HI = 0x0BE;
	this.DMA1DAD_LO = 0x0C0;
	this.DMA1DAD_HI = 0x0C2;
	this.DMA1CNT_LO = 0x0C4;
	this.DMA1CNT_HI = 0x0C6;
	this.DMA2SAD_LO = 0x0C8;
	this.DMA2SAD_HI = 0x0CA;
	this.DMA2DAD_LO = 0x0CC;
	this.DMA2DAD_HI = 0x0CE;
	this.DMA2CNT_LO = 0x0D0;
	this.DMA2CNT_HI = 0x0D2;
	this.DMA3SAD_LO = 0x0D4;
	this.DMA3SAD_HI = 0x0D6;
	this.DMA3DAD_LO = 0x0D8;
	this.DMA3DAD_HI = 0x0DA;
	this.DMA3CNT_LO = 0x0DC;
	this.DMA3CNT_HI = 0x0DE;

	// Timers
	this.TM0CNT_LO = 0x100;
	this.TM0CNT_HI = 0x102;
	this.TM1CNT_LO = 0x104;
	this.TM1CNT_HI = 0x106;
	this.TM2CNT_LO = 0x108;
	this.TM2CNT_HI = 0x10A;
	this.TM3CNT_LO = 0x10C;
	this.TM3CNT_HI = 0x10E;

	// Keypad
	this.KEYINPUT = 0x130;
	this.KEYCNT = 0x132;

	// Interrupts, etc
	this.IE = 0x200;
	this.IF = 0x202;
	this.WAITCNT = 0x204;
	this.IME = 0x208;

	this.DEFAULT_SOUNDBIAS = 0x200;
};

GameBoyAdvanceIO.prototype.setCPU = function(cpu) {
	this.cpu = cpu;
};

GameBoyAdvanceIO.prototype.setVideo = function(video) {
	this.video = video;
};

GameBoyAdvanceIO.prototype.clear = function() {
	this.registers = new Uint16Array(this.cpu.mmu.SIZE_IO);

	this.registers[this.SOUNDBIAS >> 1] = this.DEFAULT_SOUNDBIAS;
};

GameBoyAdvanceIO.prototype.load8 = function(offset) {
	throw "Unimplmeneted unaligned I/O access";
}

GameBoyAdvanceIO.prototype.load16 = function(offset) {
	return this.loadU16(offset) >> 0;
}

GameBoyAdvanceIO.prototype.load32 = function(offset) {
	switch (offset) {
	case this.DMA0CNT_LO:
	case this.DMA1CNT_LO:
	case this.DMA2CNT_LO:
	case this.DMA3CNT_LO:
		return this.loadU16(offset | 2) << 16;
	}

	return this.loadU16(offset) | (this.loadU16(offset | 2) << 16);
};

GameBoyAdvanceIO.prototype.loadU8 = function(offset) {
	var odd = offset & 0x0001;
	var value = this.loadU16(offset & 0xFFFE);
	return (value >>> (odd << 3)) & 0xFF;
}

GameBoyAdvanceIO.prototype.loadU16 = function(offset) {
	switch (offset) {
	case this.DISPCNT:
	case this.SOUNDBIAS:
	case this.WAITCNT:
	case this.IE:
	case this.IME:
		// Handled transparently by the written registers
		break;
	case this.DISPSTAT:
		return this.registers[offset >> 1] | this.video.readDisplayStat();
	case this.DMA0CNT_HI:
	case this.DMA1CNT_HI:
	case this.DMA2CNT_HI:
	case this.DMA3CNT_HI:
		break;
	default:
		throw "Unimplemented I/O register read: 0x" + offset.toString(16);
	}
	return this.registers[offset >> 1];
};

GameBoyAdvanceIO.prototype.store8 = function(offset, value) {
	switch (offset) {
	case this.SOUND1CNT_HI | 1:
	case this.SOUND2CNT_LO | 1:
	case this.SOUND3CNT_HI:
	case this.SOUND4CNT_LO | 1:
		break;
	case this.SOUND1CNT_X | 1:
	case this.SOUND2CNT_HI | 1:
		value &= 0xC7;
		break;
	case this.SOUND1CNT_LO:
		value &= 0x7F;
		break;
	case this.SOUND3CNT_LO:
	case this.SOUND3CNT_HI | 1:
		value &= 0xE0;
		break;
	case this.SOUND4CNT_HI | 1:
		value &= 0xC0;
		break;
	case this.SOUNDCNT_LO:
		value &= 0x77;
		break;
	case this.SOUNDCNT_X:
		value &= 0x80;
		break;
	case this.SOUNDBIAS | 1:
		value &= 0xC3;
		break;
	default:
		throw "Unimplemented 8-bit I/O register write: 0x" + offset.toString(16);
	}

	if (offset & 1) {
		value <<= 8;
		value |= (this.registers[offset >> 1] & 0x00FF);
	}
	this.registers[offset >> 1] = value;
};

GameBoyAdvanceIO.prototype.store16 = function(offset, value) {
	switch (offset) {
	// Video
	case this.DISPCNT:
		this.video.writeDisplayControl(value);
		break;
	case this.DISPSTAT:
		value &= this.video.DISPSTAT_MASK;
		this.video.writeDisplayStat(value);
		break;

	// Sound
	// TODO: implement sound
	case this.SOUNDCNT_LO:
		value &= 0xFF77;
		break;
	case this.SOUNDCNT_HI:
		value &= 0xFF0F;
		break;
	case this.SOUNDCNT_X:
		value &= 0x0080;
		break;

	// DMA
	case this.DMA0CNT_LO:
		this.cpu.irq.dmaSetWordCount(0, value);
		//return;
		break;
	case this.DMA0CNT_HI:
		// The DMA registers need to set the values before writing the control, as writing the
		// control can synchronously trigger a DMA transfer
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(0, value);
		break;
	case this.DMA1CNT_LO:
		this.cpu.irq.dmaSetWordCount(1, value);
		//return;
		break;
	case this.DMA1CNT_HI:
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(1, value);
		break;
	case this.DMA2CNT_LO:
		this.cpu.irq.dmaSetWordCount(2, value);
		//return;
		break;
	case this.DMA2CNT_HI:
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(2, value);
		break;
	case this.DMA3CNT_LO:
		this.cpu.irq.dmaSetWordCount(3, value);
		//return;
		break;
	case this.DMA3CNT_HI:
		this.registers[offset >> 1] = value & 0xFFE0;
		this.cpu.irq.dmaWriteControl(3, value);
		return;

	// Misc
	case this.IE:
		value &= 0x3FFF;
		this.cpu.irq.setInterruptsEnabled(value);
		break;
	case this.WAITCNT:
		// TODO: implement this
		value &= 0x5FFF;
		break;
	case this.IME:
		value &= 0x0001;
		this.cpu.irq.masterEnable(value);
		break;
	default:
		throw "Unimplemented I/O register write: 0x" + offset.toString(16);
	}
	this.registers[offset >> 1] = value;
};

GameBoyAdvanceIO.prototype.store32 = function(offset, value) {
	switch (offset) {
	case this.DMA0SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(0, value);
		return;
	case this.DMA0DAD_LO:
		this.cpu.irq.dmaSetDestAddress(0, value);
		return;
	case this.DMA1SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(1, value);
		return;
	case this.DMA1DAD_LO:
		this.cpu.irq.dmaSetDestAddress(1, value);
		return;
	case this.DMA2SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(2, value);
		return;
	case this.DMA2DAD_LO:
		this.cpu.irq.dmaSetDestAddress(2, value);
		return;
	case this.DMA3SAD_LO:
		this.cpu.irq.dmaSetSourceAddress(3, value);
		return;
	case this.DMA3DAD_LO:
		this.cpu.irq.dmaSetDestAddress(3, value);
		return;
	}

	this.store16(offset, value & 0xFFFF);
	this.store16(offset + 2, value >> 16);
};
<|endoftext|>


<commit_before>
(function(exports, undefined){

var proto = function(obj){
    return Object.prototype.toString.apply(obj);
};

var fallback = function(obj){
    return (/\[.* (.*)\]/i).exec(proto(obj))[1].toLowerCase();
};

var Checks = {
    UserTypes: {},
    BaseTypes: {
        'null': function(obj){
            return null === obj;
        },

        'undefined': function(obj){
            return undefined === obj;
        },

        'boolean': function(obj){
            return proto(obj) === '[object Boolean]';
        },

        'string': function(obj){
            return proto(obj) === '[object String]';
        },

        'number': function(obj){
            return proto(obj) === '[object Number]';
        },

        'array': function(obj){
            return proto(obj) === '[object Array]';
        },

        'function': function(obj){
            return proto(obj) === '[object Function]';
        },

        'object': function(obj){
            return proto(obj) === '[object Object]';
        }
    },
    DOMTypes: {
        'element': function(element){
            return element.nodeType === 1;
        },
        'textnode': function(element){
            return element.nodeType === 3;
        },
        'comment': function(element){
            return element.nodeType === 8;
        },
        'document': function(element){
            return element.nodeType === 9;
        },
        'fragment': function(element){
            return element.nodeType === 11;
        }
    }
};

exports.is = function(obj, type){
    if (arguments.length === 2){
        if (null === type) type = 'null';
        if (undefined == type) type = 'undefined';

        var comparitor = Checks.UserTypes[type] || Checks.DOMTypes[type.toLowerCase()] || Checks.BaseTypes[type.toLowerCase()];
        if (comparitor) return comparitor(obj);

        throw new Error('"' +type + '" is not supported by is.');
    } else {
        for (type in Checks.UserTypes)
            if (Checks.UserTypes[type](obj)) return type;

        if (obj && obj.nodeType !== undefined){
            for (type in Checks.DOMTypes)
                if (Checks.DOMTypes[type](obj)) return type;
        }

        for (type in Checks.BaseTypes)
            if (Checks.BaseTypes[type](obj)) return type;

        return fallback(obj);
    }
};

exports.is.add = function(type, comparitor){
    Checks.UserTypes[type] = comparitor;
};

exports.is.remove = function(type){
    delete Checks.UserTypes[type];
};

})(window);
<commit_msg>Added short hand way of checking multiple checks<commit_after>
(function(exports, undefined){

var proto = function(obj){
    return Object.prototype.toString.apply(obj);
};

var fallback = function(obj){
    return (/\[.* (.*)\]/i).exec(proto(obj))[1].toLowerCase();
};

var Checks = {
    UserTypes: {},
    BaseTypes: {
        'null': function(obj){
            return null === obj;
        },
        'undefined': function(obj){
            return undefined === obj;
        }
    },
    DOMTypes: {}
};

var addMultiple = function(pairs, check, addTo){
    for (var type in pairs){
        (function(type, property){
            addTo[type] = function(obj){ return check(obj, property); };
        })(type, pairs[type]);
    }
};

// Add aditional base types
addMultiple({
    'boolean': '[object Boolean]',
    'string': '[object String]',
    'number': '[object Number]',
    'array': '[object Array]',
    'function': '[object Function]',
    'object': '[object Object]'
}, function(obj, type){
    return proto(obj) === type;
}, Checks.BaseTypes);

// Add aditional base types
addMultiple({
    'element': 1,
    'textnode': 3,
    'comment': 8,
    'document': 9,
    'fragment': 11
}, function(element, nodeType){
    return element && element.nodeType === nodeType;
}, Checks.DOMTypes);

exports.is = function(obj, type){
    if (arguments.length === 2){
        if (null === type) type = 'null';
        if (undefined == type) type = 'undefined';

        var comparitor = Checks.UserTypes[type] || Checks.DOMTypes[type.toLowerCase()] || Checks.BaseTypes[type.toLowerCase()];
        if (comparitor) return comparitor(obj);

        throw new Error('"' +type + '" is not supported by is.');
    } else {
        for (type in Checks.UserTypes)
            if (Checks.UserTypes[type](obj)) return type;

        if (obj && obj.nodeType !== undefined){
            for (type in Checks.DOMTypes)
                if (Checks.DOMTypes[type](obj)) return type;
        }

        for (type in Checks.BaseTypes)
            if (Checks.BaseTypes[type](obj)) return type;

        return fallback(obj);
    }
};

exports.is.add = function(type, comparitor){
    Checks.UserTypes[type] = comparitor;
};

exports.is.remove = function(type){
    delete Checks.UserTypes[type];
};

})(window);
<|endoftext|>


<commit_before>    var portalFG;
	var portalBG;
    var groupFG;
	var groupBG;
    var nextQueryParamsFG;
    var queryParamsFG;
	var nextQueryParamsBG;
    var queryParamsBG;

	var item1, item2;
	var displayOptions = {
      numItemsPerPage: 6,
      group: {
        "group": "67fb524bd2e24c80bf2b972b4ce5aa95"
      },
      portalUrl: 'http://www.arcgis.com'
    };

	require([
	"dojo/parser",
	"dojo/ready",
	"dojo/dom",
	"dojo/dom-construct",
	"dojo/_base/array",
	"dijit/registry",
	"dojo/on",
  "dojo/query",
  "dojo/dom-prop",
	"esri/arcgis/Portal",
	"esri/config",
	"esri/lang",
	"esri/IdentityManager",
  "dojox/widget/ColorPicker", //adding color picker from dojo to replace jQuery spectrum
	"dijit/form/RadioButton",
	"dojox/lang/aspect"
  ],function(
	parser,
	ready,
	dom,
	domConstruct,
	array,
	registry,
	on,
  query,
  domProp,
	arcgisPortal,
	config,
	esriLang,
	IdentityManager,
  ColorPicker,
	RadioButton,
	dojoLang
  ) {

    ready(function() {
	  parser.parse();
	  esriConfig.defaults.io.proxyUrl = "/proxy/proxy.ashx"
	  esriConfig.defaults.io.alwaysUseProxy = false;

      portalFG = new arcgisPortal.Portal(displayOptions.portalUrl);
	  portalBG = new arcgisPortal.Portal(displayOptions.portalUrl);

      on(portalBG, 'ready', loadPortal);
      on(portalFG, 'ready', loadForegrounds);

	  on(dom.byId('next'), "click", getNext);
	  on(dom.byId('prev'), "click", getPrevious);
	  on(dom.byId('nextForegroundButton'), "click", getNextForeground);
	  on(dom.byId('prevForegroundButton'), "click", getPreviousForeground);

    var colorPicker = new ColorPicker({}, "colorPicker"); //summon the colorpicker

    on(dom.byId("backgroundUpload"), "change", function(){ //uncheck the radio buttons when an image is uploaded
      query(".backgroundGrid").query("input[type=radio]").attr("checked", false);
    });
    on(dom.byId("foregroundUpload"), "change", function(){
      query(".foregroundGrid").query("input[type=radio]").attr("checked", false);
    });

      dojox.lang.aspect.advise(portalFG, "queryItems", {
        afterReturning: function (queryItemsPromise) {
          queryItemsPromise.then(function (result) {
            nextQueryParamsFG = result.nextQueryParams;
            queryParamsFG = result.queryParams;
          });
        }
      });
	  dojox.lang.aspect.advise(portalBG, "queryItems", {
        afterReturning: function (queryItemsPromise) {
          queryItemsPromise.then(function (result) {
            nextQueryParamsBG = result.nextQueryParams;
            queryParamsBG = result.queryParams;
          });
        }
      });

    });

    function loadPortal() { //loads the thumbnails for the backgrounds
        var params = {
          q: 'id: 67fb524bd2e24c80bf2b972b4ce5aa95' //insert group id for background images here
        };
        portalBG.queryGroups(params).then(function(groups){
        //get group title and thumbnail url
        if (groups.results.length == 1) {
          groupBG = groups.results[0];
          if (groupBG.thumbnailUrl) {
            dojo.create('img', {
              src: groupBG.thumbnailUrl,
              width: 64,
              height: 64,
              alt: groupBG.title
            }, dojo.byId('groupThumbnail'));
          }

          dojo.byId('groupTitle').innerHTML = "Thumbnail Maker";//group.title + "

";
          dojo.byId('sidebar').innerHTML = "Select two images (a background and foreground) and fill out the form.";//group.snippet;

          //Retrieve the web maps and applications from the group and display
          var params = {
            q: ' type: Image',
            num: displayOptions.numItemsPerPage
          };
          groupBG.queryItems(params).then(updateGrid);
        }
      });
    }

    function loadForegrounds() { //loads the thumbnails for the foregrounds
        var params = {
          //q: 'title: ' + displayOptions.group.title + ' AND owner:' + displayOptions.group.owner
          q: 'id: f8836a4c1ca6438a89c5b39dfbd41d42' //insert group id for foreground images here
        };
        portalFG.queryGroups(params).then(function(groups){
        //get group title and thumbnail url
        if (groups.results.length == 1) {
          groupFG = groups.results[0];
          if (groupFG.thumbnailUrl) {
            dojo.create('img', {
              src: groupFG.thumbnailUrl,
              width: 64,
              height: 64,
              alt: groupFG.title
            }, dojo.byId('groupThumbnailForegrounds'));
          }

          //Retrieve the web maps and applications from the group and display
          var params = {
            q: ' type: Image',
            num: displayOptions.numItemsPerPage
          };
          groupFG.queryItems(params).then(updateGridForForegrounds);
        }
      });
    }
  });

function updateGrid(queryResponse) { //for backgrounds
  //update the gallery to get the next page of items

  var galleryList = dojo.byId('galleryList');
  dojo.empty(galleryList);  //empty the gallery to remove existing items

   //navigation buttons
  (queryResponse.results.length < 6) ? esri.hide(dojo.byId('next')) : esri.show(dojo.byId('next'));
  (queryResponse.queryParams.start > 1) ? esri.show(dojo.byId('prev')) : esri.hide(dojo.byId('prev'));
  //Build the thumbnails for each item the thumbnail when clicked will display the web map in a template or the web application
  var frag = document.createDocumentFragment();
  dojo.forEach(queryResponse.results, function (item) {
    if (item.id) {
      var url = (item.type === 'Web Map') ?
        displayOptions.templateUrl + '?webmap=' + item.id + '&theme=' + displayOptions.themeName :
        item.itemDataUrl;

      var li = dojo.create('li', {}, frag);
      var a = dojo.create('label', {
        //href: url,
        class: "backgroundGrid",
        target: '_blank',
        //innerHTML: '

' + item.tags.toString() + '

' + item.title + '

<input type="radio" name="rdoThumbBG"/> Use this.
'
        innerHTML: '
' + item.title + '
<input type="radio" name="rdoThumbBG" value="' + item.itemDataUrl + '"/>
'
      }, li);
    }
  });
  dojo.place(frag, galleryList);
}

function updateGridForForegrounds(queryResponse) {
  //update the gallery to get the next page of items

  var galleryList = dojo.byId('galleryListForeground');
  dojo.empty(galleryList);  //empty the gallery to remove existing items

   //navigation buttons
  (queryResponse.results.length < 6) ? esri.hide(dojo.byId('nextForegroundButton')) : esri.show(dojo.byId('nextForegroundButton'));
  (queryResponse.queryParams.start > 1) ? esri.show(dojo.byId('prevForegroundButton')) : esri.hide(dojo.byId('prevForegroundButton'));

  //Build the thumbnails for each item the thumbnail when clicked will display the web map in a template or the web application
  var frag = document.createDocumentFragment();
  dojo.forEach(queryResponse.results, function (item) {
    if (item.id) {
      //var url = (item.type === 'Web Map') ?
      //  displayOptions.templateUrl + '?webmap=' + item.id + '&theme=' + displayOptions.themeName :
      //  item.itemDataUrl;

      var li = dojo.create('li', {}, frag);
      var a = dojo.create('label', {
        //href: url,
        class: "foregroundGrid",
        target: '_blank',
        //innerHTML: '

' + item.tags.toString() + '

' + item.title + '

<input type="radio" name="rdoThumbBG"/> Use this.
'
        innerHTML: '
' + item.title + '
<input type="radio" name="rdoThumbFG" value="' + item.itemDataUrl + '"/>
'
      }, li);
    }
  });
  dojo.place(frag, galleryList);
}

function getNext() {
  if (nextQueryParamsBG.start > -1) {
    groupBG.queryItems(nextQueryParamsBG).then(updateGrid);
  }
}

function getPrevious() {
  if (nextQueryParamsBG.start !== 1) { //we aren't at the beginning keep querying.
    var params = queryParamsBG;
    params.start = params.start - params.num;
    groupBG.queryItems(params).then(updateGrid);
  }
}

function getNextForeground() {
  if (nextQueryParamsFG.start > -1) {
    groupFG.queryItems(nextQueryParamsFG).then(updateGridForForegrounds);
  }
}

function getPreviousForeground() {
  if (nextQueryParamsFG.start !== 1) { //we aren't at the beginning keep querying.
    var params = queryParamsFG;
    params.start = params.start - params.num;
    groupFG.queryItems(params).then(updateGridForForegrounds);
  }
}

	function submitForm() {
		require(["dojo/dom"], function(dom){
			with(dom.byId('fgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);
			return false;
        });
		with(dojo.byId('bgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);
		with(dojo.byId('fgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);

		var imageFG, imageBG;
		var promises, uploadResults;

		if (dojo.byId('backgroundUpload').files.length > 0) {
			var layerUrl = "http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/uploads/upload";
			var layersRequestBG = esri.request({
			  url: layerUrl,
			  form: dojo.byId("bgForm"),
			  handleAs: "json",
			  callbackParamName: "callback"
			},{usePost: true});
			imageBG = layersRequestBG;
		}
		if (dojo.byId('foregroundUpload').files.length > 0) {
			var layerUrl = "http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/uploads/upload";
			var layersRequestFG = esri.request({
			  url: layerUrl,
			  form: dojo.byId("fgForm"),
			  handleAs: "json",
			  callbackParamName: "callback"
			},{usePost: true});
			imageFG = layersRequestFG;
		}

		require(["dojo/promise/all"], function(all) {
			promises = new all([imageBG, imageFG]);
			promises.then(handleQueryResults);

			function handleQueryResults(results) {
				console.log(results);
				uploadResults = results;
				require(["esri/tasks/Geoprocessor"], function(Geoprocessor) {
					var gp = new Geoprocessor("http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/Generate%20Thumb");
					require(["esri/tasks/DataFile"], function(DataFile) {
					var dataFile1 = new DataFile();
					var dataFile2 = new DataFile();
					dataFile1.itemID = uploadResults[0].item.itemID;
					dataFile2.itemID = uploadResults[1].item.itemID;
					var params = {"ItemText": "The rain in spain", "FontSize": "15", "TextColor": "#FF0000", "Align": "Left", "SelectedFont": "DejaVuSansMono-Bold.ttf", "ULX": "0", "ULY": "90", "LRX": "165", "LRY": "133", "BackgroundImage": dataFile1, "ForegroundImage": dataFile2};
					gp.submitJob(params, completeCallback, statusCallback);
					function statusCallback(jobInfo){
						console.log(jobInfo.jobStatus);
					}
					function completeCallback(jobInfo) {
						console.log(jobInfo);
						gp.getResultData(jobInfo.jobId, "OutputImage", function(result){
							console.log(result);
						});
					}
					});
				});
			}
		});
	}

function submitForm() {
	//with(dojo.byId('myform'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);
	if (dojo.byId('backgroundUpload').files.length > 0) {
		//var theForm = dojo.create("form");
		var layerUrl = "http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/uploads/upload";
		var layersRequestBG = esri.request({
		  url: layerUrl,
		  //form: { f: "json", file: dojo.byId('backgroundUpload'), description: "BG Upload" },
		  form: dojo.byId("bgForm"),
		  handleAs: "json",
		  callbackParamName: "callback"
		},{usePost: true});
		layersRequestBG.then(
		  function(response) {
			console.log("Success: ", response);
		}, function(error) {
			console.log("Error: ", error.message);
		});
	}
	if (dojo.byId('foregroundUpload').files.length > 0) {
		//var theForm = dojo.create("form");
		var layerUrl = "http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/uploads/upload";
		var layersRequestFG = esri.request({
		  url: layerUrl,
		  //form: { f: "json", file: dojo.byId('backgroundUpload'), description: "BG Upload" },
		  form: dojo.byId("fgForm"),
		  handleAs: "json",
		  callbackParamName: "callback"
		},{usePost: true});
		layersRequestFG.then(
		  function(response) {
			console.log("Success: ", response);
		}, function(error) {
			console.log("Error: ", error.message);
		});
	}
}
<commit_msg>More on submitting to the thumbnail service<commit_after>    var portalFG;
	var portalBG;
    var groupFG;
	var groupBG;
    var nextQueryParamsFG;
    var queryParamsFG;
	var nextQueryParamsBG;
    var queryParamsBG;
	var thumbnailGeneratorURL = "http://nwdemo1-int.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer";

	var item1, item2;
	var displayOptions = {
      numItemsPerPage: 6,
      group: {
        "group": "67fb524bd2e24c80bf2b972b4ce5aa95"
      },
      portalUrl: 'http://www.arcgis.com'
    };

	require([
	"dojo/parser",
	"dojo/ready",
	"dojo/dom",
	"dojo/dom-construct",
	"dojo/_base/array",
	"dijit/registry",
	"dojo/on",
  "dojo/query",
  "dojo/dom-prop",
	"esri/arcgis/Portal",
	"esri/config",
	"esri/lang",
	"esri/IdentityManager",
  "dojox/widget/ColorPicker", //adding color picker from dojo to replace jQuery spectrum
	"dijit/form/RadioButton",
	"dojox/lang/aspect"
  ],function(
	parser,
	ready,
	dom,
	domConstruct,
	array,
	registry,
	on,
  query,
  domProp,
	arcgisPortal,
	config,
	esriLang,
	IdentityManager,
  ColorPicker,
	RadioButton,
	dojoLang
  ) {

    ready(function() {
	  parser.parse();
	  esriConfig.defaults.io.proxyUrl = "/proxy/proxy.ashx"
	  esriConfig.defaults.io.alwaysUseProxy = false;

      portalFG = new arcgisPortal.Portal(displayOptions.portalUrl);
	  portalBG = new arcgisPortal.Portal(displayOptions.portalUrl);

      on(portalBG, 'ready', loadPortal);
      on(portalFG, 'ready', loadForegrounds);

	  on(dom.byId('next'), "click", getNext);
	  on(dom.byId('prev'), "click", getPrevious);
	  on(dom.byId('nextForegroundButton'), "click", getNextForeground);
	  on(dom.byId('prevForegroundButton'), "click", getPreviousForeground);

    var colorPicker = new ColorPicker({}, "colorPicker"); //summon the colorpicker

    on(dom.byId("backgroundUpload"), "change", function(){ //uncheck the radio buttons when an image is uploaded
      query(".backgroundGrid").query("input[type=radio]").attr("checked", false);
    });
    on(dom.byId("foregroundUpload"), "change", function(){
      query(".foregroundGrid").query("input[type=radio]").attr("checked", false);
    });

      dojox.lang.aspect.advise(portalFG, "queryItems", {
        afterReturning: function (queryItemsPromise) {
          queryItemsPromise.then(function (result) {
            nextQueryParamsFG = result.nextQueryParams;
            queryParamsFG = result.queryParams;
          });
        }
      });
	  dojox.lang.aspect.advise(portalBG, "queryItems", {
        afterReturning: function (queryItemsPromise) {
          queryItemsPromise.then(function (result) {
            nextQueryParamsBG = result.nextQueryParams;
            queryParamsBG = result.queryParams;
          });
        }
      });

    });

    function loadPortal() { //loads the thumbnails for the backgrounds
        var params = {
          q: 'id: 67fb524bd2e24c80bf2b972b4ce5aa95' //insert group id for background images here
        };
        portalBG.queryGroups(params).then(function(groups){
        //get group title and thumbnail url
        if (groups.results.length == 1) {
          groupBG = groups.results[0];
          if (groupBG.thumbnailUrl) {
            dojo.create('img', {
              src: groupBG.thumbnailUrl,
              width: 64,
              height: 64,
              alt: groupBG.title
            }, dojo.byId('groupThumbnail'));
          }

          dojo.byId('groupTitle').innerHTML = "Thumbnail Maker";//group.title + "

";
          dojo.byId('sidebar').innerHTML = "Select two images (a background and foreground) and fill out the form.";//group.snippet;

          //Retrieve the web maps and applications from the group and display
          var params = {
            q: ' type: Image',
            num: displayOptions.numItemsPerPage
          };
          groupBG.queryItems(params).then(updateGrid);
        }
      });
    }

    function loadForegrounds() { //loads the thumbnails for the foregrounds
        var params = {
          //q: 'title: ' + displayOptions.group.title + ' AND owner:' + displayOptions.group.owner
          q: 'id: f8836a4c1ca6438a89c5b39dfbd41d42' //insert group id for foreground images here
        };
        portalFG.queryGroups(params).then(function(groups){
        //get group title and thumbnail url
        if (groups.results.length == 1) {
          groupFG = groups.results[0];
          if (groupFG.thumbnailUrl) {
            dojo.create('img', {
              src: groupFG.thumbnailUrl,
              width: 64,
              height: 64,
              alt: groupFG.title
            }, dojo.byId('groupThumbnailForegrounds'));
          }

          //Retrieve the web maps and applications from the group and display
          var params = {
            q: ' type: Image',
            num: displayOptions.numItemsPerPage
          };
          groupFG.queryItems(params).then(updateGridForForegrounds);
        }
      });
    }
  });

function updateGrid(queryResponse) { //for backgrounds
  //update the gallery to get the next page of items

  var galleryList = dojo.byId('galleryList');
  dojo.empty(galleryList);  //empty the gallery to remove existing items

   //navigation buttons
  (queryResponse.results.length < 6) ? esri.hide(dojo.byId('next')) : esri.show(dojo.byId('next'));
  (queryResponse.queryParams.start > 1) ? esri.show(dojo.byId('prev')) : esri.hide(dojo.byId('prev'));
  //Build the thumbnails for each item the thumbnail when clicked will display the web map in a template or the web application
  var frag = document.createDocumentFragment();
  dojo.forEach(queryResponse.results, function (item) {
    if (item.id) {
      var url = (item.type === 'Web Map') ?
        displayOptions.templateUrl + '?webmap=' + item.id + '&theme=' + displayOptions.themeName :
        item.itemDataUrl;

      var li = dojo.create('li', {}, frag);
      var a = dojo.create('label', {
        //href: url,
        class: "backgroundGrid",
        target: '_blank',
        //innerHTML: '

' + item.tags.toString() + '

' + item.title + '

<input type="radio" name="rdoThumbBG"/> Use this.
'
        innerHTML: '
' + item.title + '
<input type="radio" name="rdoThumbBG" value="' + item.itemDataUrl + '"/>
'
      }, li);
    }
  });
  dojo.place(frag, galleryList);
}

function updateGridForForegrounds(queryResponse) {
  //update the gallery to get the next page of items

  var galleryList = dojo.byId('galleryListForeground');
  dojo.empty(galleryList);  //empty the gallery to remove existing items

   //navigation buttons
  (queryResponse.results.length < 6) ? esri.hide(dojo.byId('nextForegroundButton')) : esri.show(dojo.byId('nextForegroundButton'));
  (queryResponse.queryParams.start > 1) ? esri.show(dojo.byId('prevForegroundButton')) : esri.hide(dojo.byId('prevForegroundButton'));

  //Build the thumbnails for each item the thumbnail when clicked will display the web map in a template or the web application
  var frag = document.createDocumentFragment();
  dojo.forEach(queryResponse.results, function (item) {
    if (item.id) {
      //var url = (item.type === 'Web Map') ?
      //  displayOptions.templateUrl + '?webmap=' + item.id + '&theme=' + displayOptions.themeName :
      //  item.itemDataUrl;

      var li = dojo.create('li', {}, frag);
      var a = dojo.create('label', {
        //href: url,
        class: "foregroundGrid",
        target: '_blank',
        //innerHTML: '

' + item.tags.toString() + '

' + item.title + '

<input type="radio" name="rdoThumbBG"/> Use this.
'
        innerHTML: '
' + item.title + '
<input type="radio" name="rdoThumbFG" value="' + item.itemDataUrl + '"/>
'
      }, li);
    }
  });
  dojo.place(frag, galleryList);
}

function getNext() {
  if (nextQueryParamsBG.start > -1) {
    groupBG.queryItems(nextQueryParamsBG).then(updateGrid);
  }
}

function getPrevious() {
  if (nextQueryParamsBG.start !== 1) { //we aren't at the beginning keep querying.
    var params = queryParamsBG;
    params.start = params.start - params.num;
    groupBG.queryItems(params).then(updateGrid);
  }
}

function getNextForeground() {
  if (nextQueryParamsFG.start > -1) {
    groupFG.queryItems(nextQueryParamsFG).then(updateGridForForegrounds);
  }
}

function getPreviousForeground() {
  if (nextQueryParamsFG.start !== 1) { //we aren't at the beginning keep querying.
    var params = queryParamsFG;
    params.start = params.start - params.num;
    groupFG.queryItems(params).then(updateGridForForegrounds);
  }
}

	function submitForm() {
		require(["dojo/dom"], function(dom){
			with(dom.byId('fgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);
			return false;
        });
		with(dojo.byId('bgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);
		with(dojo.byId('fgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);

		var imageFG, imageBG;
		var promises, uploadResults;

		if (dojo.byId('backgroundUpload').files.length > 0) {
			var layerUrl = "http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/uploads/upload";
			var layersRequestBG = esri.request({
			  url: layerUrl,
			  form: dojo.byId("bgForm"),
			  handleAs: "json",
			  callbackParamName: "callback"
			},{usePost: true});
			imageBG = layersRequestBG;
		}
		if (dojo.byId('foregroundUpload').files.length > 0) {
			var layerUrl = "http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/uploads/upload";
			var layersRequestFG = esri.request({
			  url: layerUrl,
			  form: dojo.byId("fgForm"),
			  handleAs: "json",
			  callbackParamName: "callback"
			},{usePost: true});
			imageFG = layersRequestFG;
		}

		require(["dojo/promise/all"], function(all) {
			promises = new all([imageBG, imageFG]);
			promises.then(handleQueryResults);

			function handleQueryResults(results) {
				console.log(results);
				uploadResults = results;
				require(["esri/tasks/Geoprocessor"], function(Geoprocessor) {
					var gp = new Geoprocessor("http://nwdemo1.esri.com/arcgis/rest/services/GP/GenerateThumb/GPServer/Generate%20Thumb");
					require(["esri/tasks/DataFile"], function(DataFile) {
					var dataFile1 = new DataFile();
					var dataFile2 = new DataFile();
					dataFile1.itemID = uploadResults[0].item.itemID;
					dataFile2.itemID = uploadResults[1].item.itemID;
					var params = {"ItemText": "The rain in spain", "FontSize": "15", "TextColor": "#FF0000", "Align": "Left", "SelectedFont": "DejaVuSansMono-Bold.ttf", "ULX": "0", "ULY": "90", "LRX": "165", "LRY": "133", "BackgroundImage": dataFile1, "ForegroundImage": dataFile2};
					gp.submitJob(params, completeCallback, statusCallback);
					function statusCallback(jobInfo){
						console.log(jobInfo.jobStatus);
					}
					function completeCallback(jobInfo) {
						console.log(jobInfo);
						gp.getResultData(jobInfo.jobId, "OutputImage", function(result){
							console.log(result);
						});
					}
					});
				});
			}
		});
	}

	function submitForm() {
		require(["dojo/dom"], function(dom){
			with(dom.byId('fgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);
			return false;
        });
		with(dojo.byId('bgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);
		with(dojo.byId('fgForm'))with(elements[0])with(elements[checked?0:1])alert(name+'='+value);

		var imageFG, imageBG;
		var promises, uploadResults;
		var imageFGfromUser = false;
		var imageBGfromUser = false;

		if (dojo.byId('backgroundUpload').files.length > 0) {
			imageBGfromUser = true;
			var layerUrl = thumbnailGeneratorURL + "/uploads/upload";
			var layersRequestBG = esri.request({
			  url: layerUrl,
			  form: dojo.byId("bgForm"),
			  handleAs: "json",
			  callbackParamName: "callback"
			},{usePost: true});
			imageBG = layersRequestBG;
		} else {
			imageBG = null;
		}

		if (dojo.byId('foregroundUpload').files.length > 0) {
			imageFGfromUser = true;
			var layerUrl = thumbnailGeneratorURL + "/uploads/upload";
			var layersRequestFG = esri.request({
			  url: layerUrl,
			  form: dojo.byId("fgForm"),
			  handleAs: "json",
			  callbackParamName: "callback"
			},{usePost: true});
			imageFG = layersRequestFG;
		} else {
			imageFG = null;
		}

		require(["dojo/promise/all"], function(all) {
			var images = [];
			if (imageBG)
				images.push(imageBG);
			if (imageFG)
				images.push(imageFG);

			if (images.length > 0) {
				promises = new all(images);
				promises.then(handleUploadsIfNecessary);
			} else {
				require(["esri/tasks/DataFile"], function(DataFile) {
					var dataFile1b = new DataFile();
					var dataFile2b = new DataFile();
					dataFile1b.url = "http://www.arcgis.com/sharing/rest/content/items/ee46269702be4e6cb18a4bff6309f484/data";
					dataFile2b.url = "http://www.arcgis.com/sharing/rest/content/items/c6d885522576422aa68bf861df230c3a/data";
					handleQueryResults([dataFile1b, dataFile2b]);
				});
			}

			function handleUploadsIfNecessary(results) {
				require(["esri/tasks/DataFile"], function(DataFile) {
					var dataFile1a = new DataFile();
					var dataFile2a = new DataFile();
					dataFile1a.itemID = results[0].item.itemID;
					dataFile2a.itemID = results[1].item.itemID;
					handleQueryResults([dataFile1a, dataFile2a]);
				});
			}

			function handleQueryResults(results) {
				//console.log(results);
				//uploadResults = results;
				require(["esri/tasks/Geoprocessor"], function(Geoprocessor) {
					var gp = new Geoprocessor(thumbnailGeneratorURL + "/Generate%20Thumb");
					//require(["esri/tasks/DataFile"], function(DataFile) {
					//var dataFile1 = new DataFile();
					//var dataFile2 = new DataFile();
					//dataFile1.itemID = uploadResults[0].item.itemID;
					//dataFile2.itemID = uploadResults[1].item.itemID;
					var params = {"ItemText": "The rain in spain falls mainly in the plains", "FontSize": "15", "TextColor": "#FF0000", "Align": "Left", "SelectedFont": "DejaVuSansMono-Bold.ttf", "ULX": "0", "ULY": "90", "LRX": "165", "LRY": "133", "BackgroundImage": results[0], "ForegroundImage": results[1]};
					gp.submitJob(params, completeCallback, statusCallback);
					function statusCallback(jobInfo){
						console.log(jobInfo.jobStatus);
					}
					function completeCallback(jobInfo) {
						console.log(jobInfo);
						gp.getResultData(jobInfo.jobId, "OutputImage", function(result){
							console.log(result);
						});
					}
					//});
				});
			}
		});
	}
<|endoftext|>


<commit_before>!(function (root, undefined) {
    "use strict"

    // help function
    var _isArray = Array.isArray || function(obj) {
        return Object.prototype.toString.call(obj) === '[object Array]'
    }

    // 'this' hook for template using
    var Hook = function (data) { this.stack = [data] } // context stack

    // value getter
    Hook.prototype.get = function (scope) {
        var val, pcount = 0, stack = this.stack
        var scopes = scope.replace(/\s/g, '') // clear empty
                        .replace(/^(\.\.\/)+/, function (all, one) {
                            pcount = all.length / one.length // parent path count
                            return ''
                        })
                        .split('.')

        // get context
        if (scopes[0] === '') { // . 'this' context
            if (scopes[1] === '') scopes.shift() // '.'.split('.') = ['', ''] ?
            val = stack[stack.length-1 -pcount]
        } else { // search context with specified scope
            for (var i=stack.length-1 - pcount; i>=0; i--) {
                if (typeof (val=stack[i][scopes[0]]) !== 'undefined') break
            }
        }

        for (var i=1, len=scopes.length; i<len; i++) {
            if (typeof val === 'undefined') return // undefined
            val = val[scopes[i]]
        } // get nested value

        return val
    }

    // escape HTML chars http://www.w3.org/TR/html4/charset.html#h-5.3.2
    var escapes = { '<': '<', '>': '>', '&': '&', '"': '"' }
    Hook.prototype.print = function (scope, escape) { // print string and escape
        var val = this.get(scope)
        if (typeof val === 'undefined') return '' // placeholder
        return !escape ? val : (val +'').replace(/[<>&"]/g, function (char) {
            return escapes[char] // escape
        })
    }

    // iterate Non-Empty list or use Non-False value
    Hook.prototype.use = function (val, reverse, iterator) {
        if (reverse) {
            if (!val || (_isArray(val) && val.length === 0)) {
                iterator.call(this)
            }
        } else {
            var list = val ? _isArray(val) ? val : [val] : []
            for (var i=0, len=list.length; i<len; i++) {
                this.stack.push(list[i])
                iterator.call(this)
                this.stack.pop()
            }
        }
    }

    // core
    function compile(source) {
        var body = "var out = '" +source
            .replace(/\\/g, "\\\\") // escape \
            .replace(/'/g, "\\'")   // escape '
            .replace(/\{\{(.+?)\}\}/g, function (a, scope) { // block
                var reverse = false, escape = true
                switch (scope[0]) {
                case '^':   // if not
                    reverse = true
                case '#':   // if/each/TODO helper
                    return "'; this.use('" +scope.slice(1) +"', " +reverse
                           +", function () { out += '"
                case '/':   // close
                    return "'; }); out += '"
                case '!':   // comments
                    return ""
                //case '>':   // TODO partials
                case '&':   // print unescape
                    scope = scope.slice(1)
                    escape = false
                default :   // print escape
                    return "' +this.print('" +scope +"', " +escape +") +'"
                }
            })
            .replace(/\n/g, "\\n") // escape cr
            +"'; return out"

        var compiled = new Function(body)
        var template = function (data) {
            return compiled.call(new Hook(data))
        }
        return template.render = template // render api
    }

    // compile api
    compile.compile = compile

    // exports
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = compile // CommonJS
    } else if (typeof define === 'function' && define.amd) {
        define('lt', compile)   // AMD
    } else {
        root['lt'] = compile    // <script>
    }
})(this)
<commit_msg>get value by self fn<commit_after>!(function (root, undefined) {
    "use strict"

    // help function
    var _isArray = Array.isArray || function(obj) {
        return Object.prototype.toString.call(obj) === '[object Array]'
    }

    // 'this' hook for template using
    var Hook = function (data) { this.stack = [data] } // context stack

    // value getter
    Hook.prototype.get = function (scope) {
        var val, pcount = 0, stack = this.stack
        var scopes = scope.replace(/\s/g, '') // clear empty
                        .replace(/^(\.\.\/)+/, function (all, one) {
                            pcount = all.length / one.length // parent path count
                            return ''
                        })
                        .split('.')

        // get context
        if (scopes[0] === '') { // . 'this' context
            if (scopes[1] === '') scopes.shift() // '.'.split('.') = ['', ''] ?
            val = stack[stack.length-1 -pcount]
        } else { // search context with specified scope
            for (var i=stack.length-1 - pcount; i>=0; i--) {
                if (typeof (val=stack[i][scopes[0]]) !== 'undefined') break
            }
        }

        for (var i=1, len=scopes.length; i<len; i++) {
            if (typeof val === 'undefined') return // undefined
            val = val[scopes[i]]
        } // get nested value

        return val
    }

    // escape HTML chars http://www.w3.org/TR/html4/charset.html#h-5.3.2
    var escapes = { '<': '<', '>': '>', '&': '&', '"': '"' }
    Hook.prototype.print = function (scope, escape) { // print string and escape
        var val = this.get(scope)
        if (typeof val === 'undefined') return '' // placeholder
        return !escape ? val : (val +'').replace(/[<>&"]/g, function (char) {
            return escapes[char] // escape
        })
    }

    // iterate Non-Empty list or use Non-False value
    Hook.prototype.use = function (scope, reverse, iterator) {
        var val = this.get(scope)
        if (reverse) {
            if (!val || (_isArray(val) && val.length === 0)) {
                iterator.call(this)
            }
        } else {
            var list = val ? _isArray(val) ? val : [val] : []
            for (var i=0, len=list.length; i<len; i++) {
                this.stack.push(list[i])
                iterator.call(this)
                this.stack.pop()
            }
        }
    }

    // core
    function compile(source) {
        var body = "var out = '" +source
            .replace(/\\/g, "\\\\") // escape \
            .replace(/'/g, "\\'")   // escape '
            .replace(/\{\{(.+?)\}\}/g, function (a, scope) { // block
                var reverse = false, escape = true
                switch (scope[0]) {
                case '^':   // if not
                    reverse = true
                case '#':   // if/each/TODO lambdas/TODO helper
                    return "'; this.use('" +scope.slice(1) +"', " +reverse
                           +", function () { out += '"
                case '/':   // close
                    return "'; }); out += '"
                case '!':   // comments
                    return ""
                //case '>':   // TODO partials
                case '&':   // print unescape
                    scope = scope.slice(1)
                    escape = false
                default :   // print escape
                    return "' +this.print('" +scope +"', " +escape +") +'"
                }
            })
            .replace(/\n/g, "\\n") // escape cr
            +"'; return out"

        var compiled = new Function(body)
        var template = function (data) {
            return compiled.call(new Hook(data))
        }
        return template.render = template // render api
    }

    // compile api
    compile.compile = compile

    // exports
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = compile // CommonJS
    } else if (typeof define === 'function' && define.amd) {
        define('lt', compile)   // AMD
    } else {
        root['lt'] = compile    // <script>
    }
})(this)
<|endoftext|>


<commit_before>let mongoose = require('mongoose');
let Schema = mongoose.Schema;

let LineSchema = new Schema({
  _id: {
    type: String,
    required: true,
    trim: true
  },
  name: {
    type: String,
    required: true,
    trim: true
  },
  type: {
    type: String,
    required: true,
    trim: true
  },
  day: Boolean
});

module.exports = mongoose.model('Line', LineSchema);<commit_msg>line type enum<commit_after>let mongoose = require('mongoose');
let Schema = mongoose.Schema;

let LineSchema = new Schema({
  _id: {
    type: String,
    required: true,
    trim: true
  },
  name: {
    type: String,
    required: true,
    trim: true
  },
  type: {
    type: String,
    required: true,
    enum: ['bus', 'tram']
  },
  day: Boolean
});

module.exports = mongoose.model('Line', LineSchema);<|endoftext|>


<commit_before>import { Component, PropTypes } from "react";
import { graphql } from "react-apollo";
import { connect } from "react-redux";
import gql from "graphql-tag";

import Authorized from "../../../blocks/authorzied";
import { header as headerActions } from "../../../store";

import Layout from "./Layout";
import Details from "./Details";

const FILTER_QUERY = gql`
  query GetFilterContent {
    family: currentFamily {
      person { photo, nickName, firstName, lastName, id: entityId }
    }
  }
`;
const withFilter = graphql(FILTER_QUERY, { name: "filter" });

const TRANSACTIONS_QUERY = gql`
  query GetTransactions($limit: Int, $skip: Int, $people: [Int], $start: String, $end: String) {
    transactions(
      limit: $limit,
      skip: $skip,
      people: $people,
      start: $start,
      end: $end,
      cache: false
    ) {
      id
      date
      status
      summary
      person { firstName, lastName, photo }
      details {
        id
        amount
        account { id, name }
      }
    }
  }
`;
const withTransactions = graphql(TRANSACTIONS_QUERY, {
  options: () => ({
    variables: { limit: 20, skip: 0, people: [], start: "", end: "" },
    forceFetch: true,
  }),
});

@withFilter
@connect()
@withTransactions
class Template extends Component {

  static propTypes = {
    data: PropTypes.shape({
      loading: PropTypes.bool,
      transactions: PropTypes.array,
      refetch: PropTypes.func,
    }),
    filter: PropTypes.shape({
      family: PropTypes.array,
    }),
    dispatch: PropTypes.func,
  }

  state = {
    offset: 0,
    shouldUpdate: true,
    done: false,
    loaded: true,
    start: "",
    end: "",
    people: [],
    transactions: [], // XXX remove after refetchMore has landed in apollo-client
  }

  componentWillMount() {
    // coming back to this page with data in the store
    if (!this.props.data.loading && this.props.data.transactions) {
      this.setState({ transactions: this.props.data.transactions });
    }
  }

  componentDidMount() {
    if (process.env.NATIVE) {
      const item = { title: "Giving History" };
      this.props.dispatch(headerActions.set(item));
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.data.loading && !nextProps.data.loading && !this.state.transactions.length) {
      this.setState({ transactions: nextProps.data.transactions });
    }
  }

  paginate = () => {
    this.props.data.refetch({
      limit: 20,
      skip: this.state.offset + 20,
      people: this.state.people,
      start: this.state.start,
      end: this.state.end,
    })
      .then(({ data }) => {
        const { transactions } = data;
        let done = false;
        if (transactions.length < 20) done = true;
        this.setState({
          transactions: this.state.transactions.concat(transactions),
          offset: this.state.offset + 20,
          done,
        });
      });
  }

  changeFamily = (people) => {
    this.setState({ loaded: false });
    this.props.data.refetch({
      start: this.state.start,
      end: this.state.end,
      limit: 20,
      skip: 0,
      people,
    })
      .then((response) => {
        if (!response || !response.data) return;
        const { transactions } = response.data;
        this.setState({
          offset: 0,
          done: transactions.length < 20,
          loaded: true,
          transactions,
          people,
        });
      });
  }

  changeDates = (start, end) => {
    this.setState({ loaded: false });
    this.props.data.refetch({
      people: this.state.people,
      limit: 20,
      skip: 0,
      start,
      end,
    })
      .then((response) => {
        if (!response || !response.data) return;
        const { transactions } = response.data;
        this.setState({
          offset: 0,
          done: transactions.length < 20,
          loaded: true,
          transactions,
          start,
          end,
        });
      });
  }

  render() {
    return (
      <Layout
        paginate={this.paginate}
        state={this.state}
        transactions={this.state.transactions}
        family={this.props.filter.family || []}
        alive
        ready={!this.props.data.loading}
        reloading={!this.state.loaded}
        done={this.state.done}
        changeFamily={this.changeFamily}
        changeDates={this.changeDates}
      />
    );
  }
}

const Routes = [
  {
    path: "history",
    component: Authorized,
    indexRoute: { component: Template },
    childRoutes: [
      {
        path: ":id",
        component: Details,
      },
    ],
  },
];

export default {
  Template,
  Routes,
};
<commit_msg>reordered decorators<commit_after>import { Component, PropTypes } from "react";
import { graphql } from "react-apollo";
import { connect } from "react-redux";
import gql from "graphql-tag";

import Authorized from "../../../blocks/authorzied";
import { header as headerActions } from "../../../store";

import Layout from "./Layout";
import Details from "./Details";

const FILTER_QUERY = gql`
  query GetFilterContent {
    family: currentFamily {
      person { photo, nickName, firstName, lastName, id: entityId }
    }
  }
`;
const withFilter = graphql(FILTER_QUERY, { name: "filter" });

const TRANSACTIONS_QUERY = gql`
  query GetTransactions($limit: Int, $skip: Int, $people: [Int], $start: String, $end: String) {
    transactions(
      limit: $limit,
      skip: $skip,
      people: $people,
      start: $start,
      end: $end,
      cache: false
    ) {
      id
      date
      status
      summary
      person { firstName, lastName, photo }
      details {
        id
        amount
        account { id, name }
      }
    }
  }
`;
const withTransactions = graphql(TRANSACTIONS_QUERY, {
  options: () => ({
    variables: { limit: 20, skip: 0, people: [], start: "", end: "" },
    forceFetch: true,
  }),
});

@connect()
@withFilter
@withTransactions
class Template extends Component {

  static propTypes = {
    data: PropTypes.shape({
      loading: PropTypes.bool,
      transactions: PropTypes.array,
      refetch: PropTypes.func,
    }),
    filter: PropTypes.shape({
      family: PropTypes.array,
    }),
    dispatch: PropTypes.func,
  }

  state = {
    offset: 0,
    shouldUpdate: true,
    done: false,
    loaded: true,
    start: "",
    end: "",
    people: [],
    transactions: [], // XXX remove after refetchMore has landed in apollo-client
  }

  componentWillMount() {
    // coming back to this page with data in the store
    if (!this.props.data.loading && this.props.data.transactions) {
      this.setState({ transactions: this.props.data.transactions });
    }
  }

  componentDidMount() {
    if (process.env.NATIVE) {
      const item = { title: "Giving History" };
      this.props.dispatch(headerActions.set(item));
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.data.loading && !nextProps.data.loading && !this.state.transactions.length) {
      this.setState({ transactions: nextProps.data.transactions });
    }
  }

  paginate = () => {
    this.props.data.refetch({
      limit: 20,
      skip: this.state.offset + 20,
      people: this.state.people,
      start: this.state.start,
      end: this.state.end,
    })
      .then(({ data }) => {
        const { transactions } = data;
        let done = false;
        if (transactions.length < 20) done = true;
        this.setState({
          transactions: this.state.transactions.concat(transactions),
          offset: this.state.offset + 20,
          done,
        });
      });
  }

  changeFamily = (people) => {
    this.setState({ loaded: false });
    this.props.data.refetch({
      start: this.state.start,
      end: this.state.end,
      limit: 20,
      skip: 0,
      people,
    })
      .then((response) => {
        if (!response || !response.data) return;
        const { transactions } = response.data;
        this.setState({
          offset: 0,
          done: transactions.length < 20,
          loaded: true,
          transactions,
          people,
        });
      });
  }

  changeDates = (start, end) => {
    this.setState({ loaded: false });
    this.props.data.refetch({
      people: this.state.people,
      limit: 20,
      skip: 0,
      start,
      end,
    })
      .then((response) => {
        if (!response || !response.data) return;
        const { transactions } = response.data;
        this.setState({
          offset: 0,
          done: transactions.length < 20,
          loaded: true,
          transactions,
          start,
          end,
        });
      });
  }

  render() {
    return (
      <Layout
        paginate={this.paginate}
        state={this.state}
        transactions={this.state.transactions}
        family={this.props.filter.family || []}
        alive
        ready={!this.props.data.loading}
        reloading={!this.state.loaded}
        done={this.state.done}
        changeFamily={this.changeFamily}
        changeDates={this.changeDates}
      />
    );
  }
}

const Routes = [
  {
    path: "history",
    component: Authorized,
    indexRoute: { component: Template },
    childRoutes: [
      {
        path: ":id",
        component: Details,
      },
    ],
  },
];

export default {
  Template,
  Routes,
};
<|endoftext|>