<commit_before>var util = require('../util');
var u = require('azure-mobile-apps/src/auth/user');
var sql = require('mssql');

var api = {

    all: function (req, res, next) {
        console.log('In: api/register');
        return next();
    },

    get: function (req, res, next) {
    	console.log('in GET');
    },

    post: function (req, res, next) {
    	console.log('in POST');
        var connection = new sql.Connection(util.sqlConfiguration);
        connection.connect(function(err) {
            if (err) {console.log('control point 0'); console.log(isError); res.sendStatus(500); return; }
            console.log('control point 1');
            var transaction = new sql.Transaction(connection);
            console.log('control point 2');
            transaction.begin(function(err) {
            console.log('control point 3');
                if (err) { console.log('control point 4'); transaction.rollback(); return; }
	            console.log('control point 5');
                var rolledback = false;
	            console.log('control point 6');
                transaction.on('rollback', function(aborted) { console.log('control point 7'); rolledback = true; res.sendStatus(500); });
            	console.log('control point 8');
                var sqlRequest = new sql.Request(transaction);
            	console.log('control point 9');
                var _userId = '';
            	console.log('control point 10');
                var queryString = 'SELECT id FROM Users WHERE sid=@sid;';
            	console.log('control point 11');
                var preparedStatement_0 = new sql.PreparedStatement(connection);
            	console.log('control point X');
                //transaction.on('commit', function(succeeded) { preparedStatement_0.unprepare(); res.sendStatus(200); });
                //transaction.on('rollback', function(aborted) { rolledback = true; preparedStatement_0.unprepare(); res.sendStatus(500); });
            	console.log('control point 12');
                preparedStatement_0.input('sid', sql.NVarChar);
            	console.log('control point 13');
                preparedStatement_0.prepare(queryString, function(err) {
            		console.log('control point 14');
                    if (err) { console.log('control point 15'); transaction.rollback(); return; }
            		console.log('control point 16');
                    preparedStatement_0.execute({ sid: req.azureMobile.user.id },
                        function(err, recordset, affected) {
                        	console.log('control point 17');
                            if (err) {console.log('control point 18'); transaction.rollback(); return; }
                            if (recordset) {console.log('control point 19'); transaction.commit(); return; }
							console.log('control point 20');
                            var preparedStatement_1 = new sql.PreparedStatement(connection);
							console.log('control point 21');
                            /*
			                transaction.on('commit', function(succeeded) {
			                	preparedStatement_0.unprepare();
			                	preparedStatement_1.unprepare();
			                	res.sendStatus(200);
			                });
			                transaction.on('rollback', function(aborted) {
			                	rolledback = true;
			                	preparedStatement_0.unprepare();
			                	preparedStatement_1.unprepare();
			                	res.sendStatus(500);
			                });
			                */
                            queryString = 'INSERT INTO Users (sid) values (@sid);';
							console.log('control point 22');
			                preparedStatement_1.input('sid', sql.NVarChar);
							console.log('control point 23');
			                preparedStatement_1.prepare(queryString, function(err) {
			                	console.log('control point 24');
			                    if (err) { console.log('control point 25'); transaction.rollback(); return; }
								console.log('control point 26');
			                    preparedStatement_1.execute({ sid: req.azureMobile.user.id },
			                        function(err, recordset, affected) {
			                        	console.log('control point 27');
					                    if (err) { console.log('control point X'); transaction.rollback(); return; }
			                        	console.log('control point 28');
					                    transaction.commit();
			                        	console.log('control point 29');
			                        }
		                        );
			                });
                        }
                    );
                 });
                console.log('control point 30');
                transaction.rollback();
            	console.log('control point 31');
            });
        });

    	// FORMER
    	/*
        var query = {
            sql: 'INSERT INTO Terulias(title, subject, schedule, privacy) VALUES (@title, @subject, @schedule, @privacy)',
            parameters: [
                {name: 'title', value: req.body.title || ""},
                {name: 'subject', value: req.body.subject || ""},
                {name: 'schedule', value: req.body.schedule || "0"},
                {name: 'privacy', value: req.body.privacy || "0"},
            ]
        };
        console.log(query);
        var query1 = {
            sql: 'SELECT id FROM Users WHERE sid=@userSid',
            parameters: [
                {name: 'userSid', value: req.azureMobile.user.id }
            ]
        };
        console.log(query1);
        var query2 = {
            sql: 'SELECT id FROM Roles WHERE roleName=@roleName',
            parameters: [
                {name: 'roleName', value: 'admin' }
            ]
        };
        console.log(query2);
        var query3 = {
            sql: 'INSERT INTO Members(tertulia, usr, role) VALUES (@tertuliaId, @usrId, @roleId)',
            parameters: [
                {name: 'tertuliaId', value: req.body.title || ""},
                {name: 'usrId', value: req.body.subject || ""},
                {name: 'roleId', value: req.body.schedule || "0"},
            ]
        };
        console.log(query3);
        res.sendStatus(200);
        return next();
        */
    }
};

api.access = 'authenticated';
module.exports = api;
<commit_msg>another<commit_after>var util = require('../util');
var u = require('azure-mobile-apps/src/auth/user');
var sql = require('mssql');

var api = {

    all: function (req, res, next) {
        console.log('In: api/register');
        return next();
    },

    get: function (req, res, next) {
    	console.log('in GET');
    },

    post: function (req, res, next) {
    	console.log('in POST');
        var connection = new sql.Connection(util.sqlConfiguration);
        connection.connect(function(err) {
            if (err) {console.log('control point 0'); console.log(isError); res.sendStatus(500); return; }
            console.log('control point 1');
            var transaction = new sql.Transaction(connection);
            console.log('control point 2');
            transaction.begin(function(err) {
            console.log('control point 3');
                if (err) { console.log('control point 4'); transaction.rollback(); return; }
	            console.log('control point 5');
                var rolledback = false;
	            console.log('control point 6');
                transaction.on('rollback', function(aborted) { console.log('control point 7'); rolledback = true; res.sendStatus(500); });
            	console.log('control point 8');
                var sqlRequest = new sql.Request(transaction);
            	console.log('control point 9');
                var _userId = '';
            	console.log('control point 10');
                var queryString = 'SELECT id FROM Users WHERE sid=@sid;';
            	console.log('control point 11');
                var preparedStatement_0 = new sql.PreparedStatement(connection);
            	console.log('control point 12');
                //transaction.on('commit', function(succeeded) { preparedStatement_0.unprepare(); res.sendStatus(200); });
                //transaction.on('rollback', function(aborted) { rolledback = true; preparedStatement_0.unprepare(); res.sendStatus(500); });
            	console.log('control point 13');
                preparedStatement_0.input('sid', sql.NVarChar);
            	console.log('control point 14');
                preparedStatement_0.prepare(queryString, function(err) {
            		console.log('control point 15');
                    if (err) { console.log('control point 16'); transaction.rollback(); return; }
            		console.log('control point 17');
                    preparedStatement_0.execute({ sid: req.azureMobile.user.id },
                        function(err, recordset, affected) {
                        	console.log('control point 18');
                            if (err) {console.log('control point 19'); transaction.rollback(); return; }
                            if (recordset) {console.log('control point 20'); transaction.commit(); return; }
							console.log('control point 21');
                            var preparedStatement_1 = new sql.PreparedStatement(connection);
							console.log('control point 22');
                            /*
			                transaction.on('commit', function(succeeded) {
			                	preparedStatement_0.unprepare();
			                	preparedStatement_1.unprepare();
			                	res.sendStatus(200);
			                });
			                transaction.on('rollback', function(aborted) {
			                	rolledback = true;
			                	preparedStatement_0.unprepare();
			                	preparedStatement_1.unprepare();
			                	res.sendStatus(500);
			                });
			                */
                            queryString = 'INSERT INTO Users (sid) values (@sid);';
							console.log('control point 23');
			                preparedStatement_1.input('sid', sql.NVarChar);
							console.log('control point 24');
			                preparedStatement_1.prepare(queryString, function(err) {
			                	console.log('control point 25');
			                    if (err) { console.log('control point 26'); transaction.rollback(); return; }
								console.log('control point 27');
			                    preparedStatement_1.execute({ sid: req.azureMobile.user.id },
			                        function(err, recordset, affected) {
			                        	console.log('control point 28');
					                    if (err) { console.log('control point X'); transaction.rollback(); return; }
			                        	console.log('control point 29');
					                    transaction.commit();
			                        	console.log('control point 30');
			                        }
		                        );
			                });
                        }
                    );
                 });
                console.log('control point 31');
                transaction.rollback();
            	console.log('control point 32');
            });
        });

    	// FORMER
    	/*
        var query = {
            sql: 'INSERT INTO Terulias(title, subject, schedule, privacy) VALUES (@title, @subject, @schedule, @privacy)',
            parameters: [
                {name: 'title', value: req.body.title || ""},
                {name: 'subject', value: req.body.subject || ""},
                {name: 'schedule', value: req.body.schedule || "0"},
                {name: 'privacy', value: req.body.privacy || "0"},
            ]
        };
        console.log(query);
        var query1 = {
            sql: 'SELECT id FROM Users WHERE sid=@userSid',
            parameters: [
                {name: 'userSid', value: req.azureMobile.user.id }
            ]
        };
        console.log(query1);
        var query2 = {
            sql: 'SELECT id FROM Roles WHERE roleName=@roleName',
            parameters: [
                {name: 'roleName', value: 'admin' }
            ]
        };
        console.log(query2);
        var query3 = {
            sql: 'INSERT INTO Members(tertulia, usr, role) VALUES (@tertuliaId, @usrId, @roleId)',
            parameters: [
                {name: 'tertuliaId', value: req.body.title || ""},
                {name: 'usrId', value: req.body.subject || ""},
                {name: 'roleId', value: req.body.schedule || "0"},
            ]
        };
        console.log(query3);
        res.sendStatus(200);
        return next();
        */
    }
};

api.access = 'authenticated';
module.exports = api;
<|endoftext|>


<commit_before>/**
 * Resize detection strategy that injects objects to elements in order to detect resize events.
 * Heavily inspired by: http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/
 */

"use strict";

var browserDetector = require("../browser-detector");

module.exports = function(options) {
    options             = options || {};
    var reporter        = options.reporter;
    var batchProcessor  = options.batchProcessor;
    var getState        = options.stateHandler.getState;

    if(!reporter) {
        throw new Error("Missing required dependency: reporter.");
    }

    /**
     * Adds a resize event listener to the element.
     * @public
     * @param {element} element The element that should have the listener added.
     * @param {function} listener The listener callback to be called for each resize event of the element. The element will be given as a parameter to the listener callback.
     */
    function addListener(element, listener) {
        if(!getObject(element)) {
            throw new Error("Element is not detectable by this strategy.");
        }

        function listenerProxy() {
            listener(element);
        }

        if(browserDetector.isIE(8)) {
            //IE 8 does not support object, but supports the resize event directly on elements.
            getState(element).object = {
                proxy: listenerProxy
            };
            element.attachEvent("onresize", listenerProxy);
        } else {
            var object = getObject(element);
            object.contentDocument.defaultView.addEventListener("resize", listenerProxy);
        }
    }

    /**
     * Makes an element detectable and ready to be listened for resize events. Will call the callback when the element is ready to be listened for resize changes.
     * @private
     * @param {object} options Optional options object.
     * @param {element} element The element to make detectable
     * @param {function} callback The callback to be called when the element is ready to be listened for resize changes. Will be called with the element as first parameter.
     */
    function makeDetectable(options, element, callback) {
        if (!callback) {
            callback = element;
            element = options;
            options = null;
        }

        options = options || {};
        var debug = options.debug;

        function injectObject(element, callback) {
            var OBJECT_STYLE = "display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; padding: 0; margin: 0; opacity: 0; z-index: -1000; pointer-events: none;";

            //The target element needs to be positioned (everything except static) so the absolute positioned object will be positioned relative to the target element.

            // Position altering may be performed directly or on object load, depending on if style resolution is possible directly or not.
            var positionCheckPerformed = false;

            // The element may not yet be attached to the DOM, and therefore the style object may be empty in some browsers.
            // Since the style object is a reference, it will be updated as soon as the element is attached to the DOM.
            var style = window.getComputedStyle(element);
            var width = element.offsetWidth;
            var height = element.offsetHeight;

            getState(element).startSize = {
                width: width,
                height: height
            };

            function mutateDom() {
                function alterPositionStyles() {
                    if(style.position === "static") {
                        element.style.position = "relative";

                        var removeRelativeStyles = function(reporter, element, style, property) {
                            function getNumericalValue(value) {
                                return value.replace(/[^-\d\.]/g, "");
                            }

                            var value = style[property];

                            if(value !== "auto" && getNumericalValue(value) !== "0") {
                                reporter.warn("An element that is positioned static has style." + property + "=" + value + " which is ignored due to the static positioning. The element will need to be positioned relative, so the style." + property + " will be set to 0. Element: ", element);
                                element.style[property] = 0;
                            }
                        };

                        //Check so that there are no accidental styles that will make the element styled differently now that is is relative.
                        //If there are any, set them to 0 (this should be okay with the user since the style properties did nothing before [since the element was positioned static] anyway).
                        removeRelativeStyles(reporter, element, style, "top");
                        removeRelativeStyles(reporter, element, style, "right");
                        removeRelativeStyles(reporter, element, style, "bottom");
                        removeRelativeStyles(reporter, element, style, "left");
                    }
                }

                function onObjectLoad() {
                    // The object has been loaded, which means that the element now is guaranteed to be attached to the DOM.
                    if (!positionCheckPerformed) {
                        alterPositionStyles();
                    }

                    /*jshint validthis: true */

                    function getDocument(element, callback) {
                        //Opera 12 seem to call the object.onload before the actual document has been created.
                        //So if it is not present, poll it with an timeout until it is present.
                        //TODO: Could maybe be handled better with object.onreadystatechange or similar.
                        if(!element.contentDocument) {
                            setTimeout(function checkForObjectDocument() {
                                getDocument(element, callback);
                            }, 100);

                            return;
                        }

                        callback(element.contentDocument);
                    }

                    //Mutating the object element here seems to fire another load event.
                    //Mutating the inner document of the object element is fine though.
                    var objectElement = this;

                    //Create the style element to be added to the object.
                    getDocument(objectElement, function onObjectDocumentReady(objectDocument) {
                        //Notify that the element is ready to be listened to.
                        callback(element);
                    });
                }

                // The element may be detached from the DOM, and some browsers does not support style resolving of detached elements.
                // The alterPositionStyles needs to be delayed until we know the element has been attached to the DOM (which we are sure of when the onObjectLoad has been fired), if style resolution is not possible.
                if (style.position !== "") {
                    alterPositionStyles(style);
                    positionCheckPerformed = true;
                }

                //Add an object element as a child to the target element that will be listened to for resize events.
                var object = document.createElement("object");
                object.style.cssText = OBJECT_STYLE;
                object.tabIndex = -1;
                object.type = "text/html";
                object.onload = onObjectLoad;

                //Safari: This must occur before adding the object to the DOM.
                //IE: Does not like that this happens before, even if it is also added after.
                if(!browserDetector.isIE()) {
                    object.data = "about:blank";
                }

                element.appendChild(object);
                getState(element).object = object;

                //IE: This must occur after adding the object to the DOM.
                if(browserDetector.isIE()) {
                    object.data = "about:blank";
                }
            }

            if(batchProcessor) {
                batchProcessor.add(mutateDom);
            } else {
                mutateDom();
            }
        }

        if(browserDetector.isIE(8)) {
            //IE 8 does not support objects properly. Luckily they do support the resize event.
            //So do not inject the object and notify that the element is already ready to be listened to.
            //The event handler for the resize event is attached in the utils.addListener instead.
            callback(element);
        } else {
            injectObject(element, callback);
        }
    }

    /**
     * Returns the child object of the target element.
     * @private
     * @param {element} element The target element.
     * @returns The object element of the target.
     */
    function getObject(element) {
        return getState(element).object;
    }

    function uninstall(element) {
        if(browserDetector.isIE(8)) {
            element.detachEvent("onresize", getState(element).object.proxy);
        } else {
            element.removeChild(getObject(element));
        }
        delete getState(element).object;
    }

    return {
        makeDetectable: makeDetectable,
        addListener: addListener,
        uninstall: uninstall
    };
};
<commit_msg>Add guard clause for uninstall method in object strategy.<commit_after>/**
 * Resize detection strategy that injects objects to elements in order to detect resize events.
 * Heavily inspired by: http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/
 */

"use strict";

var browserDetector = require("../browser-detector");

module.exports = function(options) {
    options             = options || {};
    var reporter        = options.reporter;
    var batchProcessor  = options.batchProcessor;
    var getState        = options.stateHandler.getState;

    if(!reporter) {
        throw new Error("Missing required dependency: reporter.");
    }

    /**
     * Adds a resize event listener to the element.
     * @public
     * @param {element} element The element that should have the listener added.
     * @param {function} listener The listener callback to be called for each resize event of the element. The element will be given as a parameter to the listener callback.
     */
    function addListener(element, listener) {
        if(!getObject(element)) {
            throw new Error("Element is not detectable by this strategy.");
        }

        function listenerProxy() {
            listener(element);
        }

        if(browserDetector.isIE(8)) {
            //IE 8 does not support object, but supports the resize event directly on elements.
            getState(element).object = {
                proxy: listenerProxy
            };
            element.attachEvent("onresize", listenerProxy);
        } else {
            var object = getObject(element);
            object.contentDocument.defaultView.addEventListener("resize", listenerProxy);
        }
    }

    /**
     * Makes an element detectable and ready to be listened for resize events. Will call the callback when the element is ready to be listened for resize changes.
     * @private
     * @param {object} options Optional options object.
     * @param {element} element The element to make detectable
     * @param {function} callback The callback to be called when the element is ready to be listened for resize changes. Will be called with the element as first parameter.
     */
    function makeDetectable(options, element, callback) {
        if (!callback) {
            callback = element;
            element = options;
            options = null;
        }

        options = options || {};
        var debug = options.debug;

        function injectObject(element, callback) {
            var OBJECT_STYLE = "display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; padding: 0; margin: 0; opacity: 0; z-index: -1000; pointer-events: none;";

            //The target element needs to be positioned (everything except static) so the absolute positioned object will be positioned relative to the target element.

            // Position altering may be performed directly or on object load, depending on if style resolution is possible directly or not.
            var positionCheckPerformed = false;

            // The element may not yet be attached to the DOM, and therefore the style object may be empty in some browsers.
            // Since the style object is a reference, it will be updated as soon as the element is attached to the DOM.
            var style = window.getComputedStyle(element);
            var width = element.offsetWidth;
            var height = element.offsetHeight;

            getState(element).startSize = {
                width: width,
                height: height
            };

            function mutateDom() {
                function alterPositionStyles() {
                    if(style.position === "static") {
                        element.style.position = "relative";

                        var removeRelativeStyles = function(reporter, element, style, property) {
                            function getNumericalValue(value) {
                                return value.replace(/[^-\d\.]/g, "");
                            }

                            var value = style[property];

                            if(value !== "auto" && getNumericalValue(value) !== "0") {
                                reporter.warn("An element that is positioned static has style." + property + "=" + value + " which is ignored due to the static positioning. The element will need to be positioned relative, so the style." + property + " will be set to 0. Element: ", element);
                                element.style[property] = 0;
                            }
                        };

                        //Check so that there are no accidental styles that will make the element styled differently now that is is relative.
                        //If there are any, set them to 0 (this should be okay with the user since the style properties did nothing before [since the element was positioned static] anyway).
                        removeRelativeStyles(reporter, element, style, "top");
                        removeRelativeStyles(reporter, element, style, "right");
                        removeRelativeStyles(reporter, element, style, "bottom");
                        removeRelativeStyles(reporter, element, style, "left");
                    }
                }

                function onObjectLoad() {
                    // The object has been loaded, which means that the element now is guaranteed to be attached to the DOM.
                    if (!positionCheckPerformed) {
                        alterPositionStyles();
                    }

                    /*jshint validthis: true */

                    function getDocument(element, callback) {
                        //Opera 12 seem to call the object.onload before the actual document has been created.
                        //So if it is not present, poll it with an timeout until it is present.
                        //TODO: Could maybe be handled better with object.onreadystatechange or similar.
                        if(!element.contentDocument) {
                            setTimeout(function checkForObjectDocument() {
                                getDocument(element, callback);
                            }, 100);

                            return;
                        }

                        callback(element.contentDocument);
                    }

                    //Mutating the object element here seems to fire another load event.
                    //Mutating the inner document of the object element is fine though.
                    var objectElement = this;

                    //Create the style element to be added to the object.
                    getDocument(objectElement, function onObjectDocumentReady(objectDocument) {
                        //Notify that the element is ready to be listened to.
                        callback(element);
                    });
                }

                // The element may be detached from the DOM, and some browsers does not support style resolving of detached elements.
                // The alterPositionStyles needs to be delayed until we know the element has been attached to the DOM (which we are sure of when the onObjectLoad has been fired), if style resolution is not possible.
                if (style.position !== "") {
                    alterPositionStyles(style);
                    positionCheckPerformed = true;
                }

                //Add an object element as a child to the target element that will be listened to for resize events.
                var object = document.createElement("object");
                object.style.cssText = OBJECT_STYLE;
                object.tabIndex = -1;
                object.type = "text/html";
                object.onload = onObjectLoad;

                //Safari: This must occur before adding the object to the DOM.
                //IE: Does not like that this happens before, even if it is also added after.
                if(!browserDetector.isIE()) {
                    object.data = "about:blank";
                }

                element.appendChild(object);
                getState(element).object = object;

                //IE: This must occur after adding the object to the DOM.
                if(browserDetector.isIE()) {
                    object.data = "about:blank";
                }
            }

            if(batchProcessor) {
                batchProcessor.add(mutateDom);
            } else {
                mutateDom();
            }
        }

        if(browserDetector.isIE(8)) {
            //IE 8 does not support objects properly. Luckily they do support the resize event.
            //So do not inject the object and notify that the element is already ready to be listened to.
            //The event handler for the resize event is attached in the utils.addListener instead.
            callback(element);
        } else {
            injectObject(element, callback);
        }
    }

    /**
     * Returns the child object of the target element.
     * @private
     * @param {element} element The target element.
     * @returns The object element of the target.
     */
    function getObject(element) {
        return getState(element).object;
    }

    function uninstall(element) {
        var object = getObject(element);
        if(browserDetector.isIE(8)) {
            element.detachEvent("onresize", object.proxy);
        } else {
            if(object) {
              element.removeChild(object);
            }
        }
        delete getState(element).object;
    }

    return {
        makeDetectable: makeDetectable,
        addListener: addListener,
        uninstall: uninstall
    };
};
<|endoftext|>


<commit_before>// FIXME: To all ye that enter here, be weary of Buffers, Arrays and Hex interchanging between the outpoints

var assert = require('assert')
var Address = require('./address')
var BigInteger = require('bigi')
var bufferutils = require('./bufferutils')
var Script = require('./script')
var convert = require('./convert')
var crypto = require('./crypto')
var ECKey = require('./eckey')
var ecdsa = require('./ecdsa')

var DEFAULT_SEQUENCE = 0xffffffff

function Transaction(doc) {
  if (!(this instanceof Transaction)) { return new Transaction(doc) }
  this.version = 1
  this.locktime = 0
  this.ins = []
  this.outs = []

  if (doc) {
    if (typeof doc == "string" || Array.isArray(doc)) {
      doc = Transaction.fromBuffer(doc)
    }

    if (doc.hash) this.hash = doc.hash;
    if (doc.version) this.version = doc.version;
    if (doc.locktime) this.locktime = doc.locktime;
    if (doc.ins && doc.ins.length) {
      doc.ins.forEach(function(input) {
        this.addInput(new TransactionIn(input))
      }, this)
    }

    if (doc.outs && doc.outs.length) {
      doc.outs.forEach(function(output) {
        this.addOutput(new TransactionOut(output))
      }, this)
    }

    this.hash = this.hash || this.getHash()
  }
}

/**
 * Create a new txin.
 *
 * Can be called with any of:
 *
 * - An existing TransactionIn object
 * - A transaction and an index
 * - A transaction hash and an index
 * - A single string argument of the form txhash:index
 *
 * Note that this method does not sign the created input.
 */
Transaction.prototype.addInput = function (tx, outIndex) {
  if (arguments[0] instanceof TransactionIn) {
    this.ins.push(arguments[0])
    return
  }

  var hash
  if (arguments[0].length > 65) {
    var args = arguments[0].split(':')
    hash = args[0]
    outIndex = parseInt(args[1])

  } else {
    hash = typeof tx === "string" ? tx : tx.hash
  }

  this.ins.push(new TransactionIn({
    outpoint: {
      hash: hash,
      index: outIndex
    },
    script: new Script()
  }))
}

/**
 * Create a new txout.
 *
 * Can be called with:
 *
 * i) An existing TransactionOut object
 * ii) An address object or a string address, and a value
 * iii) An address:value string
 *
 * FIXME: This is a bit convoluted
 */
Transaction.prototype.addOutput = function (address, value) {
  if (arguments[0] instanceof TransactionOut) {
    this.outs.push(arguments[0])
    return
  }

  if (typeof address === 'string') {
    if (arguments[0].indexOf(':') >= 0) {
      var args = arguments[0].split(':')
      address = args[0]
      value = parseInt(args[1])
    }

    address = Address.fromBase58Check(address)
  }

  this.outs.push(new TransactionOut({
    value: value,
    script: address.toScriptPubKey(),
    address: address // TODO: Remove me
  }))
}

Transaction.prototype.toBuffer = function () {
  var txInSize = this.ins.reduce(function(a, x) {
    return a + (40 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
  }, 0)

  var txOutSize = this.outs.reduce(function(a, x) {
    return a + (8 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
  }, 0)

  var buffer = new Buffer(
    8 +
    bufferutils.varIntSize(this.ins.length) +
    bufferutils.varIntSize(this.outs.length) +
    txInSize +
    txOutSize
  )

  var offset = 0
  function writeSlice(slice) {
    if (Array.isArray(slice)) slice = new Buffer(slice) // FIXME: Performance: transitionary only
    slice.copy(buffer, offset)
    offset += slice.length
  }
  function writeUInt32(i) {
    buffer.writeUInt32LE(i, offset)
    offset += 4
  }
  function writeUInt64(i) {
    bufferutils.writeUInt64LE(buffer, i, offset)
    offset += 8
  }
  function writeVarInt(i) {
    var n = bufferutils.writeVarInt(buffer, i, offset)
    offset += n
  }

  writeUInt32(this.version)
  writeVarInt(this.ins.length)

  this.ins.forEach(function(txin, i) {
    var hash = new Buffer(txin.outpoint.hash, 'hex') // FIXME: Performance: convert on tx.addInput instead

    // TxHash hex is big-endian, we need little-endian
    Array.prototype.reverse.call(hash)

    writeSlice(hash)
    writeUInt32(txin.outpoint.index)
    writeVarInt(txin.script.buffer.length)
    writeSlice(txin.script.buffer)
    writeUInt32(txin.sequence)
  })

  writeVarInt(this.outs.length)
  this.outs.forEach(function(txout) {
    writeUInt64(txout.value)
    writeVarInt(txout.script.buffer.length)
    writeSlice(txout.script.buffer)
  })

  writeUInt32(this.locktime)
  assert.equal(offset, buffer.length, 'Invalid transaction object')

  return buffer
}

Transaction.prototype.toHex = function() {
  return this.toBuffer().toString('hex')
}

//var OP_CODESEPARATOR = 171

var SIGHASH_ALL = 1
var SIGHASH_NONE = 2
var SIGHASH_SINGLE = 3
var SIGHASH_ANYONECANPAY = 80

/**
 * Hash transaction for signing a specific input.
 *
 * Bitcoin uses a different hash for each signed transaction input. This
 * method copies the transaction, makes the necessary changes based on the
 * hashType, serializes and finally hashes the result. This hash can then be
 * used to sign the transaction input in question.
 */
Transaction.prototype.hashForSignature =
  function (connectedScript, inIndex, hashType)
{
  var txTmp = this.clone()

  // In case concatenating two scripts ends up with two codeseparators,
  // or an extra one at the end, this prevents all those possible
  // incompatibilities.
  /*scriptCode = scriptCode.filter(function (val) {
    return val !== OP_CODESEPARATOR
    });*/

  // Blank out other inputs' signatures
  txTmp.ins.forEach(function(txin) {
    txin.script = new Script()
  })

  txTmp.ins[inIndex].script = connectedScript

  // Blank out some of the outputs
  if ((hashType & 0x1f) == SIGHASH_NONE) {
    txTmp.outs = []

    // Let the others update at will
    txTmp.ins.forEach(function(txin, i) {
      if (i != inIndex) {
        txTmp.ins[i].sequence = 0
      }
    })

  } else if ((hashType & 0x1f) == SIGHASH_SINGLE) {
    // TODO: Implement
  }

  // Blank out other inputs completely, not recommended for open transactions
  if (hashType & SIGHASH_ANYONECANPAY) {
    txTmp.ins = [txTmp.ins[inIndex]]
  }

  var htB = new Buffer(4)
  htB.writeUInt32LE(hashType, 0)

  var buffer = Buffer.concat([txTmp.toBuffer(), htB])
  return crypto.hash256(buffer)
}

Transaction.prototype.getHash = function () {
  var buffer = crypto.hash256(this.toBuffer())

  // Big-endian is used for TxHash
  Array.prototype.reverse.call(buffer)

  return buffer.toString('hex')
}

Transaction.prototype.clone = function ()
{
  var newTx = new Transaction()
  newTx.version = this.version
  newTx.locktime = this.locktime

  this.ins.forEach(function(txin) {
    newTx.addInput(txin.clone())
  })

  this.outs.forEach(function(txout) {
    newTx.addOutput(txout.clone())
  })

  return newTx
}

Transaction.fromBuffer = function(buffer) {
  // Copy because we mutate (reverse TxOutHashs)
  buffer = new Buffer(buffer)

  var offset = 0
  function readSlice(n) {
    offset += n
    return buffer.slice(offset - n, offset)
  }
  function readUInt32() {
    var i = buffer.readUInt32LE(offset)
    offset += 4
    return i
  }
  function readUInt64() {
    var i = bufferutils.readUInt64LE(buffer, offset)
    offset += 8
    return i
  }
  function readVarInt() {
    var vi = bufferutils.readVarInt(buffer, offset)
    offset += vi.size
    return vi.number
  }

  var ins = []
  var outs = []

  var version = readUInt32()
  var vinLen = readVarInt()

  for (var i = 0; i < vinLen; ++i) {
    var hash = readSlice(32)

    // TxHash is little-endian, we want big-endian hex
    Array.prototype.reverse.call(hash)

    var vout = readUInt32()
    var scriptLen = readVarInt()
    var script = readSlice(scriptLen)
    var sequence = readUInt32()

    ins.push({
      outpoint: {
        hash: hash.toString('hex'),
        index: vout,
      },
      script: Script.fromBuffer(script),
      sequence: sequence
    })
  }

  var voutLen = readVarInt()

  for (i = 0; i < voutLen; ++i) {
    var value = readUInt64()
    var scriptLen = readVarInt()
    var script = readSlice(scriptLen)

    outs.push({
      value: value,
      script: Script.fromBuffer(script)
    })
  }

  var locktime = readUInt32()
  assert.equal(offset, buffer.length, 'Invalid transaction')

  return new Transaction({
    version: version,
    ins: ins,
    outs: outs,
    locktime: locktime
  })
}

Transaction.fromHex = function(hex) {
  return Transaction.fromBuffer(new Buffer(hex, 'hex'))
}

/**
 * Signs a standard output at some index with the given key
 */
Transaction.prototype.sign = function(index, key, type) {
  assert(key instanceof ECKey)

  var script = key.pub.getAddress().toScriptPubKey()
  var signature = this.signScriptSig(index, script, key, type)

  // FIXME: Assumed prior TX was pay-to-pubkey-hash
  var scriptSig = Script.createPubKeyHashScriptSig(signature, key.pub)
  this.setScriptSig(index, scriptSig)
}

Transaction.prototype.signScriptSig = function(index, scriptPubKey, key, type) {
  type = type || SIGHASH_ALL

  assert((index >= 0), 'Invalid vin index')
  assert(scriptPubKey instanceof Script, 'Invalid Script object')
  assert(key instanceof ECKey, 'Invalid private key')
//  assert.equal(type & 0x7F, type, 'Invalid type') // TODO

  var hash = this.hashForSignature(scriptPubKey, index, type)
  var signature = key.sign(hash)
  var DERencoded = ecdsa.serializeSig(signature)

  return Buffer.concat([
    new Buffer(DERencoded),
    new Buffer([type])
  ])
}

Transaction.prototype.setScriptSig = function(index, script) {
  this.ins[index].script = script
}

Transaction.prototype.validateSig = function(index, script, pub, DERsig) {
  var type = DERsig.readUInt8(DERsig.length - 1)
  DERsig = DERsig.slice(0, -1)

  var hash = this.hashForSignature(script, index, type)
  var sig = ecdsa.parseSig(DERsig)

  return pub.verify(hash, sig)
}

Transaction.feePerKb = 20000
Transaction.prototype.estimateFee = function(feePerKb){
  var uncompressedInSize = 180
  var outSize = 34
  var fixedPadding = 34

  if(feePerKb == undefined) feePerKb = Transaction.feePerKb;
  var size = this.ins.length * uncompressedInSize + this.outs.length * outSize + fixedPadding

  return feePerKb * Math.ceil(size / 1000)
}

var TransactionIn = function (data) {
  if (typeof data == "string") {
    this.outpoint = { hash: data.split(':')[0], index: data.split(':')[1] }
  } else if (data.outpoint) {
    this.outpoint = data.outpoint
  } else {
    this.outpoint = { hash: data.hash, index: data.index }
  }

  assert(data.script, 'Invalid TxIn parameters')
  this.script = data.script
  this.sequence = data.sequence == undefined ? DEFAULT_SEQUENCE : data.sequence
}

TransactionIn.prototype.clone = function () {
  return new TransactionIn({
    outpoint: {
      hash: this.outpoint.hash,
      index: this.outpoint.index
    },
    script: this.script.clone(),
    sequence: this.sequence
  })
}

function TransactionOut(data) {
  this.script = data.script
  this.value = data.value
  this.address = data.address

  if (data.address) this.address = data.address
}

TransactionOut.prototype.clone = function() {
  return new TransactionOut({
    script: this.script.clone(),
    value: this.value,
    address: this.address
  })
}

module.exports = {
  Transaction: Transaction,
  TransactionIn: TransactionIn,
  TransactionOut: TransactionOut
}
<commit_msg>Transaction: fix SIGHASH_* constant values<commit_after>// FIXME: To all ye that enter here, be weary of Buffers, Arrays and Hex interchanging between the outpoints

var assert = require('assert')
var Address = require('./address')
var BigInteger = require('bigi')
var bufferutils = require('./bufferutils')
var Script = require('./script')
var convert = require('./convert')
var crypto = require('./crypto')
var ECKey = require('./eckey')
var ecdsa = require('./ecdsa')

var DEFAULT_SEQUENCE = 0xffffffff

function Transaction(doc) {
  if (!(this instanceof Transaction)) { return new Transaction(doc) }
  this.version = 1
  this.locktime = 0
  this.ins = []
  this.outs = []

  if (doc) {
    if (typeof doc == "string" || Array.isArray(doc)) {
      doc = Transaction.fromBuffer(doc)
    }

    if (doc.hash) this.hash = doc.hash;
    if (doc.version) this.version = doc.version;
    if (doc.locktime) this.locktime = doc.locktime;
    if (doc.ins && doc.ins.length) {
      doc.ins.forEach(function(input) {
        this.addInput(new TransactionIn(input))
      }, this)
    }

    if (doc.outs && doc.outs.length) {
      doc.outs.forEach(function(output) {
        this.addOutput(new TransactionOut(output))
      }, this)
    }

    this.hash = this.hash || this.getHash()
  }
}

/**
 * Create a new txin.
 *
 * Can be called with any of:
 *
 * - An existing TransactionIn object
 * - A transaction and an index
 * - A transaction hash and an index
 * - A single string argument of the form txhash:index
 *
 * Note that this method does not sign the created input.
 */
Transaction.prototype.addInput = function (tx, outIndex) {
  if (arguments[0] instanceof TransactionIn) {
    this.ins.push(arguments[0])
    return
  }

  var hash
  if (arguments[0].length > 65) {
    var args = arguments[0].split(':')
    hash = args[0]
    outIndex = parseInt(args[1])

  } else {
    hash = typeof tx === "string" ? tx : tx.hash
  }

  this.ins.push(new TransactionIn({
    outpoint: {
      hash: hash,
      index: outIndex
    },
    script: new Script()
  }))
}

/**
 * Create a new txout.
 *
 * Can be called with:
 *
 * i) An existing TransactionOut object
 * ii) An address object or a string address, and a value
 * iii) An address:value string
 *
 * FIXME: This is a bit convoluted
 */
Transaction.prototype.addOutput = function (address, value) {
  if (arguments[0] instanceof TransactionOut) {
    this.outs.push(arguments[0])
    return
  }

  if (typeof address === 'string') {
    if (arguments[0].indexOf(':') >= 0) {
      var args = arguments[0].split(':')
      address = args[0]
      value = parseInt(args[1])
    }

    address = Address.fromBase58Check(address)
  }

  this.outs.push(new TransactionOut({
    value: value,
    script: address.toScriptPubKey(),
    address: address // TODO: Remove me
  }))
}

Transaction.prototype.toBuffer = function () {
  var txInSize = this.ins.reduce(function(a, x) {
    return a + (40 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
  }, 0)

  var txOutSize = this.outs.reduce(function(a, x) {
    return a + (8 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
  }, 0)

  var buffer = new Buffer(
    8 +
    bufferutils.varIntSize(this.ins.length) +
    bufferutils.varIntSize(this.outs.length) +
    txInSize +
    txOutSize
  )

  var offset = 0
  function writeSlice(slice) {
    if (Array.isArray(slice)) slice = new Buffer(slice) // FIXME: Performance: transitionary only
    slice.copy(buffer, offset)
    offset += slice.length
  }
  function writeUInt32(i) {
    buffer.writeUInt32LE(i, offset)
    offset += 4
  }
  function writeUInt64(i) {
    bufferutils.writeUInt64LE(buffer, i, offset)
    offset += 8
  }
  function writeVarInt(i) {
    var n = bufferutils.writeVarInt(buffer, i, offset)
    offset += n
  }

  writeUInt32(this.version)
  writeVarInt(this.ins.length)

  this.ins.forEach(function(txin, i) {
    var hash = new Buffer(txin.outpoint.hash, 'hex') // FIXME: Performance: convert on tx.addInput instead

    // TxHash hex is big-endian, we need little-endian
    Array.prototype.reverse.call(hash)

    writeSlice(hash)
    writeUInt32(txin.outpoint.index)
    writeVarInt(txin.script.buffer.length)
    writeSlice(txin.script.buffer)
    writeUInt32(txin.sequence)
  })

  writeVarInt(this.outs.length)
  this.outs.forEach(function(txout) {
    writeUInt64(txout.value)
    writeVarInt(txout.script.buffer.length)
    writeSlice(txout.script.buffer)
  })

  writeUInt32(this.locktime)
  assert.equal(offset, buffer.length, 'Invalid transaction object')

  return buffer
}

Transaction.prototype.toHex = function() {
  return this.toBuffer().toString('hex')
}

var SIGHASH_ALL = 0x01
var SIGHASH_NONE = 0x02
var SIGHASH_SINGLE = 0x03
var SIGHASH_ANYONECANPAY = 0x80

/**
 * Hash transaction for signing a specific input.
 *
 * Bitcoin uses a different hash for each signed transaction input. This
 * method copies the transaction, makes the necessary changes based on the
 * hashType, serializes and finally hashes the result. This hash can then be
 * used to sign the transaction input in question.
 */
Transaction.prototype.hashForSignature =
  function (connectedScript, inIndex, hashType)
{
  var txTmp = this.clone()

  // In case concatenating two scripts ends up with two codeseparators,
  // or an extra one at the end, this prevents all those possible
  // incompatibilities.
  /*scriptCode = scriptCode.filter(function (val) {
    return val !== OP_CODESEPARATOR
    });*/

  // Blank out other inputs' signatures
  txTmp.ins.forEach(function(txin) {
    txin.script = new Script()
  })

  txTmp.ins[inIndex].script = connectedScript

  // Blank out some of the outputs
  if ((hashType & 0x1f) == SIGHASH_NONE) {
    txTmp.outs = []

    // Let the others update at will
    txTmp.ins.forEach(function(txin, i) {
      if (i != inIndex) {
        txTmp.ins[i].sequence = 0
      }
    })

  } else if ((hashType & 0x1f) == SIGHASH_SINGLE) {
    // TODO: Implement
  }

  // Blank out other inputs completely, not recommended for open transactions
  if (hashType & SIGHASH_ANYONECANPAY) {
    txTmp.ins = [txTmp.ins[inIndex]]
  }

  var htB = new Buffer(4)
  htB.writeUInt32LE(hashType, 0)

  var buffer = Buffer.concat([txTmp.toBuffer(), htB])
  return crypto.hash256(buffer)
}

Transaction.prototype.getHash = function () {
  var buffer = crypto.hash256(this.toBuffer())

  // Big-endian is used for TxHash
  Array.prototype.reverse.call(buffer)

  return buffer.toString('hex')
}

Transaction.prototype.clone = function ()
{
  var newTx = new Transaction()
  newTx.version = this.version
  newTx.locktime = this.locktime

  this.ins.forEach(function(txin) {
    newTx.addInput(txin.clone())
  })

  this.outs.forEach(function(txout) {
    newTx.addOutput(txout.clone())
  })

  return newTx
}

Transaction.fromBuffer = function(buffer) {
  // Copy because we mutate (reverse TxOutHashs)
  buffer = new Buffer(buffer)

  var offset = 0
  function readSlice(n) {
    offset += n
    return buffer.slice(offset - n, offset)
  }
  function readUInt32() {
    var i = buffer.readUInt32LE(offset)
    offset += 4
    return i
  }
  function readUInt64() {
    var i = bufferutils.readUInt64LE(buffer, offset)
    offset += 8
    return i
  }
  function readVarInt() {
    var vi = bufferutils.readVarInt(buffer, offset)
    offset += vi.size
    return vi.number
  }

  var ins = []
  var outs = []

  var version = readUInt32()
  var vinLen = readVarInt()

  for (var i = 0; i < vinLen; ++i) {
    var hash = readSlice(32)

    // TxHash is little-endian, we want big-endian hex
    Array.prototype.reverse.call(hash)

    var vout = readUInt32()
    var scriptLen = readVarInt()
    var script = readSlice(scriptLen)
    var sequence = readUInt32()

    ins.push({
      outpoint: {
        hash: hash.toString('hex'),
        index: vout,
      },
      script: Script.fromBuffer(script),
      sequence: sequence
    })
  }

  var voutLen = readVarInt()

  for (i = 0; i < voutLen; ++i) {
    var value = readUInt64()
    var scriptLen = readVarInt()
    var script = readSlice(scriptLen)

    outs.push({
      value: value,
      script: Script.fromBuffer(script)
    })
  }

  var locktime = readUInt32()
  assert.equal(offset, buffer.length, 'Invalid transaction')

  return new Transaction({
    version: version,
    ins: ins,
    outs: outs,
    locktime: locktime
  })
}

Transaction.fromHex = function(hex) {
  return Transaction.fromBuffer(new Buffer(hex, 'hex'))
}

/**
 * Signs a standard output at some index with the given key
 */
Transaction.prototype.sign = function(index, key, type) {
  assert(key instanceof ECKey)

  var script = key.pub.getAddress().toScriptPubKey()
  var signature = this.signScriptSig(index, script, key, type)

  // FIXME: Assumed prior TX was pay-to-pubkey-hash
  var scriptSig = Script.createPubKeyHashScriptSig(signature, key.pub)
  this.setScriptSig(index, scriptSig)
}

Transaction.prototype.signScriptSig = function(index, scriptPubKey, key, type) {
  type = type || SIGHASH_ALL

  assert((index >= 0), 'Invalid vin index')
  assert(scriptPubKey instanceof Script, 'Invalid Script object')
  assert(key instanceof ECKey, 'Invalid private key')
//  assert.equal(type & 0x7F, type, 'Invalid type') // TODO

  var hash = this.hashForSignature(scriptPubKey, index, type)
  var signature = key.sign(hash)
  var DERencoded = ecdsa.serializeSig(signature)

  return Buffer.concat([
    new Buffer(DERencoded),
    new Buffer([type])
  ])
}

Transaction.prototype.setScriptSig = function(index, script) {
  this.ins[index].script = script
}

Transaction.prototype.validateSig = function(index, script, pub, DERsig) {
  var type = DERsig.readUInt8(DERsig.length - 1)
  DERsig = DERsig.slice(0, -1)

  var hash = this.hashForSignature(script, index, type)
  var sig = ecdsa.parseSig(DERsig)

  return pub.verify(hash, sig)
}

Transaction.feePerKb = 20000
Transaction.prototype.estimateFee = function(feePerKb){
  var uncompressedInSize = 180
  var outSize = 34
  var fixedPadding = 34

  if(feePerKb == undefined) feePerKb = Transaction.feePerKb;
  var size = this.ins.length * uncompressedInSize + this.outs.length * outSize + fixedPadding

  return feePerKb * Math.ceil(size / 1000)
}

var TransactionIn = function (data) {
  if (typeof data == "string") {
    this.outpoint = { hash: data.split(':')[0], index: data.split(':')[1] }
  } else if (data.outpoint) {
    this.outpoint = data.outpoint
  } else {
    this.outpoint = { hash: data.hash, index: data.index }
  }

  assert(data.script, 'Invalid TxIn parameters')
  this.script = data.script
  this.sequence = data.sequence == undefined ? DEFAULT_SEQUENCE : data.sequence
}

TransactionIn.prototype.clone = function () {
  return new TransactionIn({
    outpoint: {
      hash: this.outpoint.hash,
      index: this.outpoint.index
    },
    script: this.script.clone(),
    sequence: this.sequence
  })
}

function TransactionOut(data) {
  this.script = data.script
  this.value = data.value
  this.address = data.address

  if (data.address) this.address = data.address
}

TransactionOut.prototype.clone = function() {
  return new TransactionOut({
    script: this.script.clone(),
    value: this.value,
    address: this.address
  })
}

module.exports = {
  Transaction: Transaction,
  TransactionIn: TransactionIn,
  TransactionOut: TransactionOut
}
<|endoftext|>


<commit_before>import {
  addClass,
  removeClass,
  isArray,
  isPlainObject
} from '../../util/index'

export default {

  deep: true,

  update (value) {
    if (value && typeof value === 'string') {
      this.handleObject(stringToObject(value))
    } else if (isPlainObject(value)) {
      this.handleObject(value)
    } else if (isArray(value)) {
      this.handleArray(value)
    } else {
      this.cleanup()
    }
  },

  handleObject (value) {
    this.cleanup(value)
    this.prevKeys = Object.keys(value)
    setObjectClasses(this.el, value)
  },

  handleArray (value) {
    this.cleanup(value)
    for (var i = 0, l = value.length; i < l; i++) {
      var val = value[i]
      if (val && isPlainObject(val)) {
        setObjectClasses(this.el, val)
      } else if (val && typeof val === 'string') {
        addClass(this.el, val)
      }
    }
    this.prevKeys = value.slice()
  },

  cleanup (value) {
    if (!this.prevKeys) return

    var i = this.prevKeys.length
    while (i--) {
      var key = this.prevKeys[i]
      if (!key) continue

      var keys = isPlainObject(key) ? Object.keys(key) : [key]
      for (var j = 0, l = keys.length; j < l; j++) {
        toggleClasses(this.el, keys[j], removeClass)
      }
    }
  }
}

function setObjectClasses (el, obj) {
  var keys = Object.keys(obj)
  for (var i = 0, l = keys.length; i < l; i++) {
    var key = keys[i]
    if (!obj[key]) continue
    toggleClasses(el, key, addClass)
  }
}

function stringToObject (value) {
  var res = {}
  var keys = value.trim().split(/\s+/)
  for (var i = 0, l = keys.length; i < l; i++) {
    res[keys[i]] = true
  }
  return res
}

/**
 * Add or remove a class/classes on an element
 *
 * @param {Element} el
 * @param {String} key The class name. This may or may not
 *                     contain a space character, in such a
 *                     case we'll deal with multiple class
 *                     names at once.
 * @param {Function} fn
 */

function toggleClasses (el, key, fn) {
  key = key.trim()

  if (key.indexOf(' ') === -1) {
    fn(el, key)
    return
  }

  // The key contains one or more space characters.
  // Since a class name doesn't accept such characters, we
  // treat it as multiple classes.
  var keys = key.split(' ')
  for (var i = 0, l = keys.length; i < l; i++) {
    fn(el, keys[i])
  }
}
<commit_msg>use regex in multi-class split<commit_after>import {
  addClass,
  removeClass,
  isArray,
  isPlainObject
} from '../../util/index'

export default {

  deep: true,

  update (value) {
    if (value && typeof value === 'string') {
      this.handleObject(stringToObject(value))
    } else if (isPlainObject(value)) {
      this.handleObject(value)
    } else if (isArray(value)) {
      this.handleArray(value)
    } else {
      this.cleanup()
    }
  },

  handleObject (value) {
    this.cleanup(value)
    this.prevKeys = Object.keys(value)
    setObjectClasses(this.el, value)
  },

  handleArray (value) {
    this.cleanup(value)
    for (var i = 0, l = value.length; i < l; i++) {
      var val = value[i]
      if (val && isPlainObject(val)) {
        setObjectClasses(this.el, val)
      } else if (val && typeof val === 'string') {
        addClass(this.el, val)
      }
    }
    this.prevKeys = value.slice()
  },

  cleanup (value) {
    if (!this.prevKeys) return

    var i = this.prevKeys.length
    while (i--) {
      var key = this.prevKeys[i]
      if (!key) continue

      var keys = isPlainObject(key) ? Object.keys(key) : [key]
      for (var j = 0, l = keys.length; j < l; j++) {
        toggleClasses(this.el, keys[j], removeClass)
      }
    }
  }
}

function setObjectClasses (el, obj) {
  var keys = Object.keys(obj)
  for (var i = 0, l = keys.length; i < l; i++) {
    var key = keys[i]
    if (!obj[key]) continue
    toggleClasses(el, key, addClass)
  }
}

function stringToObject (value) {
  var res = {}
  var keys = value.trim().split(/\s+/)
  for (var i = 0, l = keys.length; i < l; i++) {
    res[keys[i]] = true
  }
  return res
}

/**
 * Add or remove a class/classes on an element
 *
 * @param {Element} el
 * @param {String} key The class name. This may or may not
 *                     contain a space character, in such a
 *                     case we'll deal with multiple class
 *                     names at once.
 * @param {Function} fn
 */

function toggleClasses (el, key, fn) {
  key = key.trim()

  if (key.indexOf(' ') === -1) {
    fn(el, key)
    return
  }

  // The key contains one or more space characters.
  // Since a class name doesn't accept such characters, we
  // treat it as multiple classes.
  var keys = key.split(/\s+/)
  for (var i = 0, l = keys.length; i < l; i++) {
    fn(el, keys[i])
  }
}
<|endoftext|>


<commit_before>function Tuner() {

  if (Tuner.prototype._instance) {
    return Tuner.prototype._instance;
  }

  Tuner.prototype._instance = this;

  var context              = new AudioContext()
    , _samplerate          = 44100
    , _downsampleFactor    = 12
    , _fftSize             = 2048
    , _effectiveSamplerate = _samplerate / _downsampleFactor
    , _frequencyResolution = _effectiveSamplerate / _fftSize
    , _bufferSize          = _fftSize * _downsampleFactor
    /* measured in seconds here */
    , _temporalWindow      = _bufferSize / _samplerate
    , _harmonics           = 5
    , _maxHarmFrequency    = _fftSize / _harmonics * _frequencyResolution
    , fft                  = new FFT(_fftSize, _effectiveSamplerate)
    , samples              = new Ring(_bufferSize, 512)
    , _windowFunction      = new WindowObject("Hann", _bufferSize)
    , _frequencyMap        = new FrequencyMap()
    , _viewCallback
    , requestDataType = { peek       : false
                        , spectrum   : false
                        , updateTime : false
                        }
    ;

  var source
    , lowpass
    , highpass
    , processor
    ;

  function fundamental() {

    var downsampled = []
      , spectrum
      , peek
      , i
      , respondData = {}
      ;

    _windowFunction.process(samples);

    for (i = 0; i < samples.length ; i += _downsampleFactor) {
      downsampled.push(samples.get(i));
    }

    fft.forward(downsampled);

    spectrum = fft.spectrum;
    peek     = HPS(spectrum,_harmonics);

    if (requestDataType.peek) {
      respondData.peek = _frequencyMap.closestNote(peek * _frequencyResolution);
    }

    if (requestDataType.spectrum) {
      respondData.spectrum = spectrum;
    }

    _viewCallback(respondData);
  }

  Object.defineProperties(this, {
      "setAudioStream": {
          enumebrable  : false
        , configurable : false
        , set: function (stream) {
            source    = context.createMediaStreamSource(stream);
            lowpass   = context.createBiquadFilter();
            highpass  = context.createBiquadFilter();
            processor = context.createScriptProcessor(512,1,1);

            lowpass.type       = "lowpass";
            highpass.type      = "highpass";
            lowpass.frequency  = (_effectiveSamplerate / 2).toFixed(3);
            highpass.frequency = 35;
        }
      },
      "samplerate" : {
          value        : _samplerate
        , enumerable   : true
        , configurable : false
        , writable     : false
      }
    , "viewCallback" : {
          enumerable   : false
        , configurable : false
        , set : function (clbk) {
          _viewCallback = clbk;

          if (requestDataType.updateTime) {
            _viewCallback({ updateTime : _temporalWindow });
          }
        }
      }
    , "requestDataType" : {
          enumerable   : true
        , configurable : false
        , set : function (rdata){
            requestDataType = rdata;
        }
        , get : function () {
            return requestDataType;
        }
    }
    , "downsampleFactor" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return _downsampleFactor;
          }
        , set : function (value) {

            checkNat("downsampleFactor",value);

            _downsampleFactor = Math.floor(value);

            _effectiveSamplerate = _samplerate / _downsampleFactor;
            _frequencyResolution = _effectiveSamplerate / _fftSize;
            _bufferSize       = _fftSize * _downsampleFactor;
            _temporalWindow   = _bufferSize / _samplerate;
            _maxHarmFrequency = _fftSize / _harmonics * _frequencyResolution;

            fft     = new FFT(_fftSize, _effectiveSamplerate);
            samples = new Ring(_bufferSize, 512);

            lowpass.frequency  = (_effectiveSamplerate / 2).toFixed(3);

            _windowFunction.length = _bufferSize;

            if (requestDataType.updateTime) {
              _viewCallback({ updateTime : _temporalWindow });
            }
          }
      }
    , "fftSize" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return _fftSize;
          }
        , set : function (value) {
            _fftSize = value;

            _frequencyResolution = _effectiveSamplerate / _fftSize;
            _bufferSize       = _fftSize * _downsampleFactor;
            _temporalWindow   = _bufferSize / _samplerate;
            _maxHarmFrequency = _fftSize / _harmonics * _frequencyResolution;

            /* this will throw an exception if the fft size is not valid */
            fft     = new FFT(_fftSize, _effectiveSamplerate);
            samples = new Ring(_bufferSize, 512);

            _windowFunction.length = _bufferSize;

            if (requestDataType.updateTime) {
              _viewCallback({ updateTime : _temporalWindow });
            }
          }
      }
    , "effectiveSamplerate" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return _effectiveSamplerate;
          }
      }
    , "frequencyResolution" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return _frequencyResolution;
          }
      }
    , "temporalWindow" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return _temporalWindow;
          }
      }
    , "frequencyMap" : {
          enumerable   : false
        , configurable : false
        , get : function () {
            return _frequencyMap;
          }
        , set : function (freqMap) {

            if (freqMap.hasOwnProperty("closestNote")) {
              _frequencyMap   = freqMap;
            } else {
              throw new TypeError("Passed object has to " +
                                  "implement method closestNote");
            }
          }
      }
    , "harmonics" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return _harmonics;
          }
        , set : function (value) {

            checkNat("downsampleFactor",value);

            _harmonics        = value;
            _maxHarmFrequency = _fftSize / _harmonics * _frequencyResolution;

          }
      }
    , "maxDetectableFundamental" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return _maxHarmFrequency;
        }
    }
    , "run" : {
          value : function () {

            if (!source) {
              throw new ReferenceError("The audio stream is not set.");
            }

            if (!_viewCallback) {
              throw new PropertyNotInitialized("Tuner", "callback");
            }

            processor.onaudioprocess = function (event) {
              var input = event.inputBuffer.getChannelData(0);

              samples.concat(input);

              event.outputBuffer.getChannelData(0).set(input);
            };

            source.connect(lowpass);
            lowpass.connect(highpass);
            highpass.connect(processor);
            processor.connect(context.destination);

            return window.setInterval(fundamental
                                     , _temporalWindow.toFixed(3) * 1000);
        }
        , enumerable   : false
        , configurable : false
        , writable     : false
    }
  });

}<commit_msg>Lose the underscores in Tuner definition.<commit_after>function Tuner() {

  if (Tuner.prototype._instance) {
    return Tuner.prototype._instance;
  }

  Tuner.prototype._instance = this;

  var context             = new AudioContext()
    , samplerate          = 44100
    , downsampleFactor    = 12
    , fftSize             = 2048
    , effectiveSamplerate = samplerate / downsampleFactor
    , frequencyResolution = effectiveSamplerate / fftSize
    , bufferSize          = fftSize * downsampleFactor
    , temporalWindow      = bufferSize / samplerate /* seconds */
    , harmonics           = 5
    , maxHarmFrequency    = fftSize / harmonics * frequencyResolution
    , fft                 = new FFT(fftSize, effectiveSamplerate)
    , samples             = new Ring(bufferSize, 512)
    , windowFunction      = new WindowObject("Hann", bufferSize)
    , frequencyMap        = new FrequencyMap()
    , viewCallback
    , requestDataType = { peek       : false
                        , spectrum   : false
                        , updateTime : false
                        }
    ;

  var source
    , lowpass
    , highpass
    , processor
    ;

  function fundamental() {

    var downsampled = []
      , spectrum
      , peek
      , i
      , respondData = {}
      ;

    windowFunction.process(samples);

    for (i = 0; i < samples.length ; i += downsampleFactor) {
      downsampled.push(samples.get(i));
    }

    fft.forward(downsampled);

    spectrum = fft.spectrum;
    peek     = HPS(spectrum,harmonics);

    if (requestDataType.peek) {
      respondData.peek = frequencyMap.closestNote(peek * frequencyResolution);
    }

    if (requestDataType.spectrum) {
      respondData.spectrum = spectrum;
    }

    viewCallback(respondData);
  }

  Object.defineProperties(this, {
      "setAudioStream": {
          enumebrable  : false
        , configurable : false
        , set: function (stream) {
            source    = context.createMediaStreamSource(stream);
            lowpass   = context.createBiquadFilter();
            highpass  = context.createBiquadFilter();
            processor = context.createScriptProcessor(512,1,1);

            lowpass.type       = "lowpass";
            highpass.type      = "highpass";
            lowpass.frequency  = (effectiveSamplerate / 2).toFixed(3);
            highpass.frequency = 35;
        }
      },
      "samplerate" : {
          value        : samplerate
        , enumerable   : true
        , configurable : false
        , writable     : false
      }
    , "viewCallback" : {
          enumerable   : false
        , configurable : false
        , set : function (clbk) {
          viewCallback = clbk;

          if (requestDataType.updateTime) {
            viewCallback({ updateTime : temporalWindow });
          }
        }
      }
    , "requestDataType" : {
          enumerable   : true
        , configurable : false
        , set : function (rdata){
            requestDataType = rdata;
        }
        , get : function () {
            return requestDataType;
        }
    }
    , "downsampleFactor" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return downsampleFactor;
          }
        , set : function (value) {

            checkNat("downsampleFactor",value);

            downsampleFactor = Math.floor(value);

            effectiveSamplerate = samplerate / downsampleFactor;
            frequencyResolution = effectiveSamplerate / fftSize;
            bufferSize       = fftSize * downsampleFactor;
            temporalWindow   = bufferSize / samplerate;
            maxHarmFrequency = fftSize / harmonics * frequencyResolution;

            fft     = new FFT(fftSize, effectiveSamplerate);
            samples = new Ring(bufferSize, 512);

            lowpass.frequency  = (effectiveSamplerate / 2).toFixed(3);

            windowFunction.length = bufferSize;

            if (requestDataType.updateTime) {
              viewCallback({ updateTime : temporalWindow });
            }
          }
      }
    , "fftSize" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return fftSize;
          }
        , set : function (value) {
            fftSize = value;

            frequencyResolution = effectiveSamplerate / fftSize;
            bufferSize       = fftSize * downsampleFactor;
            temporalWindow   = bufferSize / samplerate;
            maxHarmFrequency = fftSize / harmonics * frequencyResolution;

            /* this will throw an exception if the fft size is not valid */
            fft     = new FFT(fftSize, effectiveSamplerate);
            samples = new Ring(bufferSize, 512);

            windowFunction.length = bufferSize;

            if (requestDataType.updateTime) {
              viewCallback({ updateTime : temporalWindow });
            }
          }
      }
    , "effectiveSamplerate" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return effectiveSamplerate;
          }
      }
    , "frequencyResolution" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return frequencyResolution;
          }
      }
    , "temporalWindow" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return temporalWindow;
          }
      }
    , "frequencyMap" : {
          enumerable   : false
        , configurable : false
        , get : function () {
            return frequencyMap;
          }
        , set : function (freqMap) {

            if (freqMap.hasOwnProperty("closestNote")) {
              frequencyMap   = freqMap;
            } else {
              throw new TypeError("Passed object has to " +
                                  "implement method closestNote");
            }
          }
      }
    , "harmonics" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return harmonics;
          }
        , set : function (value) {

            checkNat("downsampleFactor",value);

            harmonics        = value;
            maxHarmFrequency = fftSize / harmonics * frequencyResolution;

          }
      }
    , "maxDetectableFundamental" : {
          enumerable   : true
        , configurable : false
        , get : function () {
            return maxHarmFrequency;
        }
    }
    , "run" : {
          value : function () {

            if (!source) {
              throw new ReferenceError("The audio stream is not set.");
            }

            if (!viewCallback) {
              throw new PropertyNotInitialized("Tuner", "callback");
            }

            processor.onaudioprocess = function (event) {
              var input = event.inputBuffer.getChannelData(0);

              samples.concat(input);

              event.outputBuffer.getChannelData(0).set(input);
            };

            source.connect(lowpass);
            lowpass.connect(highpass);
            highpass.connect(processor);
            processor.connect(context.destination);

            return window.setInterval(fundamental
                                     , temporalWindow.toFixed(3) * 1000);
        }
        , enumerable   : false
        , configurable : false
        , writable     : false
    }
  });

}<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function () {
  var usedModels = {
    "AbstractDAO":true,
    "AbstractDAOView":true,
    "Action":true,
    "ActionButtonCView2":true,
    "Arg":true,
    "Calc":true,
    "foam.apps.calc.CalcSpeechView":true,
    "foam.apps.calc.CalcView":true,
    "foam.apps.calc.CalcButton":true,
    "foam.apps.calc.Fonts":true,
    "Constant":true,
    "CountExpr":true,
    "DAOController":true,
    "DAOListView":true,
    "DOMValue":true,
    "DetailView":true,
    "foam.input.touch.DragGesture":true,
    "Expr":true,
    "foam.input.touch.Gesture":true,
    "foam.input.touch.GestureManager":true,
    "foam.input.touch.GestureTarget":true,
    "foam.apps.calc.History":true,
    "foam.apps.calc.HistoryCitationView":true,
    "foam.input.touch.InputPoint": true,
    "Interface":true,
    "foam.apps.calc.MainButtonsView":true,
    "Message":true,
    "Method":true,
    "Model":true,
    "foam.apps.calc.NumberFormatter":true,
    "foam.input.touch.PinchTwistGesture":true,
    "PositionedDOMViewTrait":true,
    "PositionedViewTrait":true,
    "Property":true,
    "PropertyView":true,
    "Relationship":true,
    "foam.input.touch.ScrollGesture":true,
    "foam.apps.calc.SecondaryButtonsView":true,
    "SimpleValue":true,
    "foam.input.touch.TapGesture":true,
    "Template":true,
    "foam.apps.calc.TertiaryButtonsView":true,
    "foam.input.touch.TouchManager":true,
    "View":true,
    "WindowHashValue":true,
    "foam.core.bootstrap.ModelFileDAO":true,
    "foam.graphics.AbstractCViewView":true,
    "foam.graphics.ActionButtonCView":true,
    "foam.graphics.CView":true,
    "foam.graphics.CViewView":true,
    "foam.graphics.Circle":true,
    "foam.graphics.PositionedCViewView":true,
    "foam.html.Element":true,
    "foam.i18n.ChromeMessagesBuilder":true,
    "foam.i18n.ChromeMessagesExtractor":true,
    "foam.i18n.GlobalController":true,
    "foam.i18n.MessagesBuilder":true,
    "foam.i18n.Visitor":true,
    "foam.patterns.ChildTreeTrait":true,
    "foam.ui.SlidePanel":true,
    "foam.ui.Window":true,
    "foam.ui.animated.Label":true,
    "foam.ui.md.Flare":true,
    "foam.ui.md.Halo":true
  };

  var class_ = CLASS;

  GLOBAL.CLASS = function(m) {
    var id = m.package ? m.package + '.' + m.name : m.name;
    if ( usedModels[id] ) class_(m);
  };

  var templates = {
    'CalcView.CSS' : true,
    'foam.ui.animated.Label.CSS' : true,
    'CalcView.toHTML' : true,
    'HistoryCitationView.toHTML' : true,
    'foam.ui.SlidePanel.toHTML' : true,
    'MainButtonsView.toHTML' : true,
    'SecondaryButtonsView.toHTML' : true,
    'TertiaryButtonsView.toHTML' : true
  };

  var aevalTemplate_ = aevalTemplate;

  GLOBAL.aevalTemplate = function(t, model) {
    return templates[model.id + '.' + t.name] ?
      aevalTemplate_(t, model)  :
      aconstant(function() { return ''; }) ;
  };

})();
<commit_msg>Update acalc/Opt.js to disallow all template compiling, as we will use template precompiling from the builder.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function () {
  var usedModels = {
    "AbstractDAO":true,
    "AbstractDAOView":true,
    "Action":true,
    "ActionButtonCView2":true,
    "Arg":true,
    "Calc":true,
    "foam.apps.calc.CalcSpeechView":true,
    "foam.apps.calc.CalcView":true,
    "foam.apps.calc.CalcButton":true,
    "foam.apps.calc.Fonts":true,
    "Constant":true,
    "CountExpr":true,
    "DAOController":true,
    "DAOListView":true,
    "DOMValue":true,
    "DetailView":true,
    "foam.input.touch.DragGesture":true,
    "Expr":true,
    "foam.input.touch.Gesture":true,
    "foam.input.touch.GestureManager":true,
    "foam.input.touch.GestureTarget":true,
    "foam.apps.calc.History":true,
    "foam.apps.calc.HistoryCitationView":true,
    "foam.input.touch.InputPoint": true,
    "Interface":true,
    "foam.apps.calc.MainButtonsView":true,
    "Message":true,
    "Method":true,
    "Model":true,
    "foam.apps.calc.NumberFormatter":true,
    "foam.input.touch.PinchTwistGesture":true,
    "PositionedDOMViewTrait":true,
    "PositionedViewTrait":true,
    "Property":true,
    "PropertyView":true,
    "Relationship":true,
    "foam.input.touch.ScrollGesture":true,
    "foam.apps.calc.SecondaryButtonsView":true,
    "SimpleValue":true,
    "foam.input.touch.TapGesture":true,
    "Template":true,
    "foam.apps.calc.TertiaryButtonsView":true,
    "foam.input.touch.TouchManager":true,
    "View":true,
    "WindowHashValue":true,
    "foam.core.bootstrap.ModelFileDAO":true,
    "foam.graphics.AbstractCViewView":true,
    "foam.graphics.ActionButtonCView":true,
    "foam.graphics.CView":true,
    "foam.graphics.CViewView":true,
    "foam.graphics.Circle":true,
    "foam.graphics.PositionedCViewView":true,
    "foam.html.Element":true,
    "foam.i18n.ChromeMessagesBuilder":true,
    "foam.i18n.ChromeMessagesExtractor":true,
    "foam.i18n.GlobalController":true,
    "foam.i18n.MessagesBuilder":true,
    "foam.i18n.Visitor":true,
    "foam.patterns.ChildTreeTrait":true,
    "foam.ui.SlidePanel":true,
    "foam.ui.Window":true,
    "foam.ui.animated.Label":true,
    "foam.ui.md.Flare":true,
    "foam.ui.md.Halo":true
  };

  var class_ = CLASS;

  GLOBAL.CLASS = function(m) {
    var id = m.package ? m.package + '.' + m.name : m.name;
    if ( usedModels[id] ) class_(m);
  };

  var aevalTemplate_ = aevalTemplate;

  GLOBAL.aevalTemplate = function(t, model) {
    aconstant(function() { return ''; }) ;
  };
})();
<|endoftext|>


<commit_before>
/**
 * Canvas display object.
 * @constructor FORGE.Canvas
 * @param {FORGE.Viewer} viewer - The {@link FORGE.Viewer} reference.
 * @extends {FORGE.DisplayObject}
 */
FORGE.Canvas = function(viewer)
{
    FORGE.DisplayObject.call(this, viewer, document.createElement("canvas"), "Canvas");
};

FORGE.Canvas.prototype = Object.create(FORGE.DisplayObject.prototype);
FORGE.Canvas.prototype.constructor = FORGE.Canvas;

/**
 * Boot sequence.
 * @method FORGE.Canvas#_boot
 * @private
 */
FORGE.Canvas.prototype._boot = function()
{
    FORGE.DisplayObject.prototype._boot.call(this);

    this._viewer.display.register(this);
    this._notifyReady();
    this._applyPending(false);
};

/**
 * Get the context for 2D.
 * @name FORGE.Canvas#context2D
 * @type {CanvasRenderingContext2D}
 * @readonly
 */
Object.defineProperty(FORGE.Canvas.prototype, "context2D",
{
    /** @this {FORGE.Canvas} */
    get: function()
    {
        return this._dom.getContext("2d");
    }
});

/**
 * Get the webGl context for 3D.
 * @name FORGE.Canvas#context3D
 * @type {WebGLRenderingContext}
 * @readonly
 */
Object.defineProperty(FORGE.Canvas.prototype, "context3D",
{
    /** @this {FORGE.Canvas} */
    get: function()
    {
        return this._dom.getContext("webgl");
    }
});

/**
 * Get the canvas DOM element
 * @name FORGE.Canvas#element
 * @type {HTMLCanvasElement}
 * @readonly
 */
Object.defineProperty(FORGE.Canvas.prototype, "element",
{
    /** @this {FORGE.Canvas} */
    get: function()
    {
        return this._dom;
    }
});
<commit_msg>Add a capture method to canvas (#137)<commit_after>
/**
 * Canvas display object.
 * @constructor FORGE.Canvas
 * @param {FORGE.Viewer} viewer - The {@link FORGE.Viewer} reference.
 * @extends {FORGE.DisplayObject}
 */
FORGE.Canvas = function(viewer)
{
    FORGE.DisplayObject.call(this, viewer, document.createElement("canvas"), "Canvas");
};

FORGE.Canvas.prototype = Object.create(FORGE.DisplayObject.prototype);
FORGE.Canvas.prototype.constructor = FORGE.Canvas;

/**
 * Canvas capture modes
 * @name FORGE.Canvas.formats
 * @type {Object}
 * @const
 */
FORGE.Canvas.formats = {};

/**
 * @name FORGE.Canvas.formats.IMAGE
 * @type {Image}
 * @const
 */
FORGE.Canvas.formats.IMAGE = "image";

/**
 * @name FORGE.Canvas.formats.DATA
 * @type {string}
 * @const
 */
FORGE.Canvas.formats.DATA = "data";

/**
 * Boot sequence.
 * @method FORGE.Canvas#_boot
 * @private
 */
FORGE.Canvas.prototype._boot = function()
{
    FORGE.DisplayObject.prototype._boot.call(this);

    this._viewer.display.register(this);
    this._notifyReady();
    this._applyPending(false);
};

/**
 * Capture the canvas and return an image.
 * @method FORGE.Canvas#capture
 */
FORGE.Canvas.prototype.capture = function(format)
{
    format = format || FORGE.Canvas.formats.IMAGE;

    var data = this._dom.toDataURL();

    switch(format)
    {
        case FORGE.Canvas.formats.DATA:
            return data;

        case FORGE.Canvas.formats.IMAGE:
            var image = new Image();
            image.src = data;
            return image;
    }
};

/**
 * Get the context for 2D.
 * @name FORGE.Canvas#context2D
 * @type {CanvasRenderingContext2D}
 * @readonly
 */
Object.defineProperty(FORGE.Canvas.prototype, "context2D",
{
    /** @this {FORGE.Canvas} */
    get: function()
    {
        return this._dom.getContext("2d");
    }
});

/**
 * Get the webGl context for 3D.
 * @name FORGE.Canvas#context3D
 * @type {WebGLRenderingContext}
 * @readonly
 */
Object.defineProperty(FORGE.Canvas.prototype, "context3D",
{
    /** @this {FORGE.Canvas} */
    get: function()
    {
        return this._dom.getContext("webgl");
    }
});

/**
 * Get the canvas DOM element
 * @name FORGE.Canvas#element
 * @type {HTMLCanvasElement}
 * @readonly
 */
Object.defineProperty(FORGE.Canvas.prototype, "element",
{
    /** @this {FORGE.Canvas} */
    get: function()
    {
        return this._dom;
    }
});
<|endoftext|>


<commit_before>
u.preloader = function(node, files, _options) {

//	u.bug("node:" + u.nodeId(node));

	var callback_preloader_loaded = "loaded";
	var callback_preloader_loading = "loading";
	var callback_preloader_waiting = "waiting";

	node._callback_min_delay = 0;

	// additional info passed to function as JSON object
	if(typeof(_options) == "object") {
		var _argument;
		for(_argument in _options) {

			switch(_argument) {
				case "loaded"               : callback_preloader_loaded       = _options[_argument]; break;
				case "loading"              : callback_preloader_loading      = _options[_argument]; break;
				case "waiting"              : callback_preloader_waiting      = _options[_argument]; break;

				case "callback_min_delay"   : node._callback_min_delay              = _options[_argument]; break;
			}

		}
	}

	if(!u._preloader_queue) {
		u._preloader_queue = document.createElement("div");
//		u._preloader_queue = u.ae(document.body, "div");
		u._preloader_processes = 0;

		if(u.e && u.e.event_pref == "touch") {
			u._preloader_max_processes = 1;
		}
		// TODO: option to load more simultaneously - implement as parameter as well?
		else {
			u._preloader_max_processes = 4;
		}

	}

	if(node && files) {

		var entry, file;
		var new_queue = u.ae(u._preloader_queue, "ul");
		new_queue._callback_loaded = callback_preloader_loaded;
		new_queue._callback_loading = callback_preloader_loading;
		new_queue._callback_waiting = callback_preloader_waiting;

		new_queue._node = node;
		new_queue._files = files;
		new_queue.nodes = new Array();
		new_queue._start_time = new Date().getTime();

		for(i = 0; file = files[i]; i++) {
			entry = u.ae(new_queue, "li", {"class":"waiting"});
			entry.i = i;
			entry._queue = new_queue
			entry._file = file;
		}

		// add waiting class on reuest node
		u.ac(node, "waiting");

		// callback to request node (in queue)
		if(typeof(node[new_queue._callback_waiting]) == "function") {
			node[new_queue._callback_waiting](new_queue.nodes);
		}

	}

	u._queueLoader();

	return u._preloader_queue;
}

u._queueLoader = function() {

//	u.bug("_queueLoader:" + u.preload_processes);

	// still items in queue
//	u.bug("li.waiting:" + u.qs("li.waiting", u._preloader_queue))
	if(u.qs("li.waiting", u._preloader_queue)) {

		while(u._preloader_processes < u._preloader_max_processes) {

			var next = u.qs("li.waiting", u._preloader_queue);
			if(next) {

				// it this the fist node of queue? (does node still have waiting position
				if(u.hc(next._queue._node, "waiting")) {
					// adjust classes on request node
					u.rc(next._queue._node, "waiting");
					u.ac(next._queue._node, "loading");

					// callback - loading has begun
					if(typeof(next._queue._node[next._queue._callback_loading]) == "function") {
						next._queue._node[next._queue._callback_loading](next._queue.nodes);
					}
				}
				u._preloader_processes++;

//				u.bug("next:" + u.qs("li.waiting", u._preloader_queue) + ", " + next)
				u.rc(next, "waiting");
				u.ac(next, "loading");

				next.loaded = function(event) {
					this.image = event.target;

					// fallback support
					this._image = this.image;

					// this._image = {};
					// this._image.width = event.target.width;
					// this._image.height = event.target.height;
					// this._image.src = event.target.src;

					this._queue.nodes[this.i] = this;

//					u.as(this, "backgroundImage", "url("+event.target.src+")");
//					u.bug("loaded and used")

					u.rc(this, "loading");
					u.ac(this, "loaded");

					u._preloader_processes--;

					if(!u.qs("li.waiting,li.loading", this._queue)) {

						// remove loading class from request node
						u.rc(this._queue._node, "loading");

						if(typeof(this._queue._node[this._queue._callback_loaded]) == "function") {
							this._queue._node[this._queue._callback_loaded](this._queue.nodes);
						}

						// callback to specific callback function
						// if(typeof(this._queue._callback) == "function") {
						// 	this._queue._node._callback = this._queue._callback;
						// 	this._queue._node._callback(this._queue.nodes);
						// }
						// // or callback to default (loaded)
						// else if(typeof(this._queue._node.loaded) == "function") {
						// 	this._queue._node.loaded(this._queue.nodes);
						// }
					}

					u._queueLoader();
				}
				u.loadImage(next, next._file);
			}
			else {
				break
			}
		}

	}

}

u.loadImage = function(node, src) {
//		u.bug("load image: " + u.nodeId(node) + ", " + src);

	// create new image
	var image = new Image();
	image.node = node;

	u.ac(node, "loading");
    u.e.addEvent(image, 'load', u._imageLoaded);
	u.e.addEvent(image, 'error', u._imageLoadError);

//	TODO: error handling?? missing image or other errors
//		u.e.addEvent(image, 'data', u.i._debug);

//		u.bug("image load:" + image.onload)
//		u.e.addEvent(image, 'error', u.i._debug);
//		u.e.addEvent(image, 'data', u.i._debug);
//		u.e.addEvent(image, 'progress', u.i._debug);
//		u.e.addEvent(image, 'done', u.i._debug);
//		u.e.addEvent(image, 'load', u.i._debug);
//		u.e.addEvent(image, 'complete', u.i._debug);

//		image.onload = function(event) {
		// call event reciever
//			this.e.loaded(event);
//		}

	image.src = src;
}

/**
*
*/
u._imageLoaded = function(event) {
	u.rc(this.node, "loading");
	// notify base
	if(typeof(this.node.loaded) == "function") {
		this.node.loaded(event);
	}

//		delete this;
//		this.src = "/img/mobile_touch/dot.gif";

}
u._imageLoadError = function(event) {

//		u.xInObject(event);
	u.rc(this.node, "loading");
	u.ac(this.node, "error");
	// notify base
	// fallback to loaded if no failed callback function declared
	if(typeof(this.node.loaded) == "function" && typeof(this.node.failed) != "function") {
		this.node.loaded(event);
	}
	else if(typeof(this.node.failed) == "function") {
		this.node.failed(event);
	}
}

// ???
u._imageLoadProgress = function(event) {

	u.bug("progress")
	// notify base
	if(typeof(this.node.progress) == "function") {
		this.node.progress(event);
	}

}

u._imageLoadDebug = function(event) {
	u.bug("event:" + event.type);
	u.xInObject(event);
}

<commit_msg>Comment<commit_after>// TODO: extend to preload more types

u.preloader = function(node, files, _options) {

//	u.bug("node:" + u.nodeId(node));

	var callback_preloader_loaded = "loaded";
	var callback_preloader_loading = "loading";
	var callback_preloader_waiting = "waiting";

	node._callback_min_delay = 0;

	// additional info passed to function as JSON object
	if(typeof(_options) == "object") {
		var _argument;
		for(_argument in _options) {

			switch(_argument) {
				case "loaded"               : callback_preloader_loaded       = _options[_argument]; break;
				case "loading"              : callback_preloader_loading      = _options[_argument]; break;
				case "waiting"              : callback_preloader_waiting      = _options[_argument]; break;

				case "callback_min_delay"   : node._callback_min_delay              = _options[_argument]; break;
			}

		}
	}

	if(!u._preloader_queue) {
		u._preloader_queue = document.createElement("div");
//		u._preloader_queue = u.ae(document.body, "div");
		u._preloader_processes = 0;

		if(u.e && u.e.event_pref == "touch") {
			u._preloader_max_processes = 1;
		}
		// TODO: option to load more simultaneously - implement as parameter as well?
		else {
			u._preloader_max_processes = 4;
		}

	}

	if(node && files) {

		var entry, file;
		var new_queue = u.ae(u._preloader_queue, "ul");
		new_queue._callback_loaded = callback_preloader_loaded;
		new_queue._callback_loading = callback_preloader_loading;
		new_queue._callback_waiting = callback_preloader_waiting;

		new_queue._node = node;
		new_queue._files = files;
		new_queue.nodes = new Array();
		new_queue._start_time = new Date().getTime();

		for(i = 0; file = files[i]; i++) {
			entry = u.ae(new_queue, "li", {"class":"waiting"});
			entry.i = i;
			entry._queue = new_queue
			entry._file = file;
		}

		// add waiting class on reuest node
		u.ac(node, "waiting");

		// callback to request node (in queue)
		if(typeof(node[new_queue._callback_waiting]) == "function") {
			node[new_queue._callback_waiting](new_queue.nodes);
		}

	}

	u._queueLoader();

	return u._preloader_queue;
}

u._queueLoader = function() {

//	u.bug("_queueLoader:" + u.preload_processes);

	// still items in queue
//	u.bug("li.waiting:" + u.qs("li.waiting", u._preloader_queue))
	if(u.qs("li.waiting", u._preloader_queue)) {

		while(u._preloader_processes < u._preloader_max_processes) {

			var next = u.qs("li.waiting", u._preloader_queue);
			if(next) {

				// it this the fist node of queue? (does node still have waiting position
				if(u.hc(next._queue._node, "waiting")) {
					// adjust classes on request node
					u.rc(next._queue._node, "waiting");
					u.ac(next._queue._node, "loading");

					// callback - loading has begun
					if(typeof(next._queue._node[next._queue._callback_loading]) == "function") {
						next._queue._node[next._queue._callback_loading](next._queue.nodes);
					}
				}
				u._preloader_processes++;

//				u.bug("next:" + u.qs("li.waiting", u._preloader_queue) + ", " + next)
				u.rc(next, "waiting");
				u.ac(next, "loading");

				next.loaded = function(event) {
					this.image = event.target;

					// fallback support
					this._image = this.image;

					// this._image = {};
					// this._image.width = event.target.width;
					// this._image.height = event.target.height;
					// this._image.src = event.target.src;

					this._queue.nodes[this.i] = this;

//					u.as(this, "backgroundImage", "url("+event.target.src+")");
//					u.bug("loaded and used")

					u.rc(this, "loading");
					u.ac(this, "loaded");

					u._preloader_processes--;

					if(!u.qs("li.waiting,li.loading", this._queue)) {

						// remove loading class from request node
						u.rc(this._queue._node, "loading");

						if(typeof(this._queue._node[this._queue._callback_loaded]) == "function") {
							this._queue._node[this._queue._callback_loaded](this._queue.nodes);
						}

						// callback to specific callback function
						// if(typeof(this._queue._callback) == "function") {
						// 	this._queue._node._callback = this._queue._callback;
						// 	this._queue._node._callback(this._queue.nodes);
						// }
						// // or callback to default (loaded)
						// else if(typeof(this._queue._node.loaded) == "function") {
						// 	this._queue._node.loaded(this._queue.nodes);
						// }
					}

					u._queueLoader();
				}
				u.loadImage(next, next._file);
			}
			else {
				break
			}
		}

	}

}

u.loadImage = function(node, src) {
//		u.bug("load image: " + u.nodeId(node) + ", " + src);

	// create new image
	var image = new Image();
	image.node = node;

	u.ac(node, "loading");
    u.e.addEvent(image, 'load', u._imageLoaded);
	u.e.addEvent(image, 'error', u._imageLoadError);

//	TODO: error handling?? missing image or other errors
//		u.e.addEvent(image, 'data', u.i._debug);

//		u.bug("image load:" + image.onload)
//		u.e.addEvent(image, 'error', u.i._debug);
//		u.e.addEvent(image, 'data', u.i._debug);
//		u.e.addEvent(image, 'progress', u.i._debug);
//		u.e.addEvent(image, 'done', u.i._debug);
//		u.e.addEvent(image, 'load', u.i._debug);
//		u.e.addEvent(image, 'complete', u.i._debug);

//		image.onload = function(event) {
		// call event reciever
//			this.e.loaded(event);
//		}

	image.src = src;
}

/**
*
*/
u._imageLoaded = function(event) {
	u.rc(this.node, "loading");
	// notify base
	if(typeof(this.node.loaded) == "function") {
		this.node.loaded(event);
	}

//		delete this;
//		this.src = "/img/mobile_touch/dot.gif";

}
u._imageLoadError = function(event) {

//		u.xInObject(event);
	u.rc(this.node, "loading");
	u.ac(this.node, "error");
	// notify base
	// fallback to loaded if no failed callback function declared
	if(typeof(this.node.loaded) == "function" && typeof(this.node.failed) != "function") {
		this.node.loaded(event);
	}
	else if(typeof(this.node.failed) == "function") {
		this.node.failed(event);
	}
}

// ???
u._imageLoadProgress = function(event) {

	u.bug("progress")
	// notify base
	if(typeof(this.node.progress) == "function") {
		this.node.progress(event);
	}

}

u._imageLoadDebug = function(event) {
	u.bug("event:" + event.type);
	u.xInObject(event);
}

<|endoftext|>