<commit_before>// ----------------------------------------------------------------------------
// Vegas - jQuery plugin
// Add awesome fullscreen backgrounds to your webpages.
// v 1.1 beta
// Dual licensed under the MIT and GPL licenses.
// http://vegas.jaysalvat.com/
// ----------------------------------------------------------------------------
// Copyright (C) 2011 Jay Salvat
// http://jaysalvat.com/
// ----------------------------------------------------------------------------
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files ( the "Software" ), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ----------------------------------------------------------------------------
( function( $ ){
    var $background = $( '<img />' ).addClass( 'vegas-background' ),
        $overlay    = $( '<div />' ).addClass( 'vegas-overlay' ),
        $loading    = $( '<div />' ).addClass( 'vegas-loading' ),
        $current    = $(),
        paused = null,
        backgrounds = [],
        step = 0,
        timer,
        methods = {

        // Init plugin
        init : function( settings ) {

            var options = {
                src: getBackground(),
                align: 'center',
                valign: 'center',
                fade: 0,
                loading: true,
                load: function() {},
                complete: function() {}
            }
            $.extend( options, $.vegas.defaults.background, settings );

            if ( options.loading ) {
                loading();
            }

            var $new = $background.clone();
            $new.css( {
                'position': 'fixed',
                'left': '0px',
                'top': '0px'
            })
            .load( function() {
                if ( $new == $current ) {
                    return;
                }

                $( window ).bind( 'resize.vegas', function( e ) {
                    resize( $new, options );
                });

                if ( $current.is( 'img' ) ) {

                    $current.stop();

                    $new.hide()
                        .insertAfter( $current )
                        .fadeIn( options.fade, function() {
                            $('.vegas-background')
                                .not(this)
                                    .remove();
                            $( 'body' ).trigger( 'vegascomplete', [ this, step - 1 ] );
                            options.complete.apply( $new, [ step - 1 ] );
                        });
                } else {
                    $new.hide()
                        .prependTo( 'body' )
                        .fadeIn( options.fade, function() {
                            $( 'body' ).trigger( 'vegascomplete', [ this, step - 1 ] );
                            options.complete.apply( this, [ step - 1 ] );
                        });
                }

                $current = $new;

                resize( $current, options );

                if ( options.loading ) {
                    loaded();
                }

                $( 'body' ).trigger( 'vegasload', [ $current.get(0), step - 1 ] );
                options.load.apply( $current.get(0), [ step - 1 ] );

                if ( step ) {
                    $( 'body' ).trigger( 'vegaswalk', [ $current.get(0), step - 1 ] );
                    options.walk.apply( $current.get(0), [ step - 1 ] );
                }
            })
            .attr( 'src', options.src );

            return $.vegas;
        },

        // Destroy background and/or overlay
        destroy: function( what ) {
            if ( !what || what == 'background') {
                $( '.vegas-background, .vegas-loading' ).remove();
                $( window ).unbind( 'resize.vegas' );
                $current = null;
            }

            if ( what == 'overlay') {
                $( '.vegas-overlay' ).remove();
            }

            return $.vegas;
        },

        // Display the pattern overlay
        overlay: function( settings ) {
            var options = {
                src: null,
                opacity: null
            };
            $.extend( options, $.vegas.defaults.overlay, settings );

            $overlay.remove();

            $overlay
                .css( {
                    'margin': '0',
                    'padding': '0',
                    'position': 'fixed',
                    'left': '0px',
                    'top': '0px',
                    'width': '100%',
                    'height': '100%'
            });

            if ( options.src ) {
                $overlay.css( 'backgroundImage', 'url(' + options.src + ')' );
            }

            if ( options.opacity ) {
                $overlay.css( 'opacity', options.opacity );
            }

            $overlay.prependTo( 'body' );

            return $.vegas;
        },

        // Start/restart slideshow
        slideshow: function( settings, keepPause ) {
            var options = {
                step: step,
                delay: 5000,
                preload: false,
                backgrounds: backgrounds,
                walk: function() {}
            };

            $.extend( options, $.vegas.defaults.slideshow, settings );

            if ( options.backgrounds != backgrounds ) {
                if ( !settings.step ) {
                    options.step = 0;
                }

                if ( options.preload ) {
                    $.vegas( 'preload', options.backgrounds )
                }
            }

            backgrounds = options.backgrounds;
            step = options.step;

            clearInterval( timer );

            if ( !backgrounds.length ) {
                return $.vegas;
            }

            var doSlideshow = function() {
                if ( step < 0 ) {
                    step = backgrounds.length - 1;
                }

                if ( step >= backgrounds.length || !backgrounds[ step - 1 ] ) {
                    step = 0;
                }

                var settings = backgrounds[ step++ ];
                settings.walk = options.walk;

                $.vegas( settings );
            }
            doSlideshow();

            if ( !keepPause ) {
                paused = false;

                $( 'body' ).trigger( 'vegasstart', [ $current.get(0), step - 1 ] );
            }

            if ( !paused ) {
                timer = setInterval( doSlideshow, options.delay );
            }

            return $.vegas;
        },

        // Jump to the next background in the current slideshow
        next: function() {
            var from = step;

            if ( step ) {
                $.vegas( 'slideshow', { step: step }, true );

                $( 'body' ).trigger( 'vegasnext', [ $current.get(0), step - 1, from - 1 ] );
            }

            return $.vegas;
        },

        // Jump to the previous background in the current slideshow
        previous: function() {
            var from = step;

            if ( step ) {
                $.vegas( 'slideshow', { step: step - 2 }, true );

                $( 'body' ).trigger( 'vegasprevious', [ $current.get(0), step - 1, from - 1 ] );
            }

            return $.vegas;
        },

        // Jump to a specific background in the current slideshow
        jump: function( s ) {
            var from = step;

            if ( step ) {
                $.vegas( 'slideshow', { step: s }, true );

                $( 'body' ).trigger( 'vegasjump', [ $current.get(0), step - 1, from - 1 ] );
            }

            return $.vegas;
        },

        // Stop slideshow
        stop: function() {
            var from = step;
            step = 0;
            paused = null;
            clearInterval( timer );

            $( 'body' ).trigger( 'vegasstop', [ $current.get(0), from - 1 ] );

            return $.vegas;
        },

        // Pause slideShow
        pause: function() {
            paused = true;
            clearInterval( timer );

            $( 'body' ).trigger( 'vegaspause', [ $current.get(0), step - 1 ] );

            return $.vegas;
        },

        // Get some useful values or objects
        get: function( what ) {
            if ( what == null || what == 'background' ) {
                return $current.get(0);
            }

            if ( what == 'overlay' ) {
                return $overlay.get(0);
            }

            if ( what == 'step' ) {
                return step - 1;
            }

            if ( what == 'paused' ) {
                return paused;
            }
        },

        // Preload an array of backgrounds
        preload: function( backgrounds ) {
            for( var i in backgrounds ) {
                if ( backgrounds[ i ].src ) {
                    $('<img src="' + backgrounds[ i ].src + '">');
                }
            }

            return $.vegas;
        }
    }

    // Resize the background
    function resize( $img, settings ) {
        var options =  {
            align: 'center',
            valign: 'center'
        }
        $.extend( options, settings );

        var ww = $( window ).width(),
            wh = $( window ).height(),
            iw = $img.width(),
            ih = $img.height(),
            rw = wh / ww,
            ri = ih / iw,
            newWidth, newHeight,
            newLeft, newTop,
            properties;

        if ( rw > ri ) {
            newWidth = wh / ri;
            newHeight = wh;
        } else {
            newWidth = ww;
            newHeight = ww * ri;
        }

        properties = {
            'width': newWidth + 'px',
            'height': newHeight + 'px',
			'top': 'auto',
			'bottom': 'auto',
			'left': 'auto',
			'right': 'auto'
        }

        if ( !isNaN( parseInt( options.valign ) ) ) {
            properties[ 'top' ] = ( 0 - ( newHeight - wh ) / 100 * parseInt( options.valign ) ) + 'px';
        } else if ( options.valign == 'top' ) {
            properties[ 'top' ] = 0;
        } else if ( options.valign == 'bottom' ) {
            properties[ 'bottom' ] = 0;
        } else {
            properties[ 'top' ] = ( wh - newHeight ) / 2;
        }

        if ( !isNaN( parseInt( options.align ) ) ) {
            properties[ 'left' ] = ( 0 - ( newWidth - ww ) / 100 * parseInt( options.align ) ) + 'px';
        } else if ( options.align == 'left' ) {
            properties[ 'left' ] = 0;
        } else if ( options.align == 'right' ) {
            properties[ 'right' ] = 0;
        } else {
            properties[ 'left' ] = ( ww - newWidth ) / 2 ;
        }

        $img.css( properties );
    }

    // Display the loading indicator
    function loading() {
        $loading.prependTo( 'body' ).fadeIn();
    }

    // Hide the loading indicator
    function loaded() {
        $loading.fadeOut( 'fast', function() {
            $( this ).remove();
        });
    }

    // Get the background image from the body
    function getBackground() {
        if ( $( 'body' ).css( 'backgroundImage' ) ) {
            return $( 'body' ).css( 'backgroundImage' ).replace( /url\("?(.*?)"?\)/i, '$1' );
        }
    }

    // The plugin
    $.vegas = function( method ) {
        if ( methods[ method ] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
        } else if ( typeof method === 'object' || !method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist' );
        }
    };

    // Global parameters
    $.vegas.defaults = {
        background: {
            // src:         string
            // align:       string/int
            // valign:      string/int
            // fade:        int
            // loading      bool
            // load:        function
            // complete:    function
        },
        slideshow: {
            // step:        int
            // delay:       int
            // backgrounds: array
            // preload:     bool
            // walk:        function
        },
        overlay: {
            // src:         string
            // opacity:     float
        }
    }
})( jQuery );<commit_msg>Issue #5 Fix delay lost when next or previous were used<commit_after>// ----------------------------------------------------------------------------
// Vegas - jQuery plugin
// Add awesome fullscreen backgrounds to your webpages.
// v 1.1 beta
// Dual licensed under the MIT and GPL licenses.
// http://vegas.jaysalvat.com/
// ----------------------------------------------------------------------------
// Copyright (C) 2011 Jay Salvat
// http://jaysalvat.com/
// ----------------------------------------------------------------------------
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files ( the "Software" ), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ----------------------------------------------------------------------------
( function( $ ){
    var $background = $( '<img />' ).addClass( 'vegas-background' ),
        $overlay    = $( '<div />' ).addClass( 'vegas-overlay' ),
        $loading    = $( '<div />' ).addClass( 'vegas-loading' ),
        $current    = $(),
        paused = null,
        backgrounds = [],
        step = 0,
		delay = 5000,
        timer,
        methods = {

        // Init plugin
        init : function( settings ) {

            var options = {
                src: getBackground(),
                align: 'center',
                valign: 'center',
                fade: 0,
                loading: true,
                load: function() {},
                complete: function() {}
            }
            $.extend( options, $.vegas.defaults.background, settings );

            if ( options.loading ) {
                loading();
            }

            var $new = $background.clone();
            $new.css( {
                'position': 'fixed',
                'left': '0px',
                'top': '0px'
            })
            .load( function() {
                if ( $new == $current ) {
                    return;
                }

                $( window ).bind( 'resize.vegas', function( e ) {
                    resize( $new, options );
                });

                if ( $current.is( 'img' ) ) {

                    $current.stop();

                    $new.hide()
                        .insertAfter( $current )
                        .fadeIn( options.fade, function() {
                            $('.vegas-background')
                                .not(this)
                                    .remove();
                            $( 'body' ).trigger( 'vegascomplete', [ this, step - 1 ] );
                            options.complete.apply( $new, [ step - 1 ] );
                        });
                } else {
                    $new.hide()
                        .prependTo( 'body' )
                        .fadeIn( options.fade, function() {
                            $( 'body' ).trigger( 'vegascomplete', [ this, step - 1 ] );
                            options.complete.apply( this, [ step - 1 ] );
                        });
                }

                $current = $new;

                resize( $current, options );

                if ( options.loading ) {
                    loaded();
                }

                $( 'body' ).trigger( 'vegasload', [ $current.get(0), step - 1 ] );
                options.load.apply( $current.get(0), [ step - 1 ] );

                if ( step ) {
                    $( 'body' ).trigger( 'vegaswalk', [ $current.get(0), step - 1 ] );
                    options.walk.apply( $current.get(0), [ step - 1 ] );
                }
            })
            .attr( 'src', options.src );

            return $.vegas;
        },

        // Destroy background and/or overlay
        destroy: function( what ) {
            if ( !what || what == 'background') {
                $( '.vegas-background, .vegas-loading' ).remove();
                $( window ).unbind( 'resize.vegas' );
                $current = null;
            }

            if ( what == 'overlay') {
                $( '.vegas-overlay' ).remove();
            }

            return $.vegas;
        },

        // Display the pattern overlay
        overlay: function( settings ) {
            var options = {
                src: null,
                opacity: null
            };
            $.extend( options, $.vegas.defaults.overlay, settings );

            $overlay.remove();

            $overlay
                .css( {
                    'margin': '0',
                    'padding': '0',
                    'position': 'fixed',
                    'left': '0px',
                    'top': '0px',
                    'width': '100%',
                    'height': '100%'
            });

            if ( options.src ) {
                $overlay.css( 'backgroundImage', 'url(' + options.src + ')' );
            }

            if ( options.opacity ) {
                $overlay.css( 'opacity', options.opacity );
            }

            $overlay.prependTo( 'body' );

            return $.vegas;
        },

        // Start/restart slideshow
        slideshow: function( settings, keepPause ) {
            var options = {
                step: step,
                delay: delay,
                preload: false,
                backgrounds: backgrounds,
                walk: function() {}
            };

            $.extend( options, $.vegas.defaults.slideshow, settings );

            if ( options.backgrounds != backgrounds ) {
                if ( !settings.step ) {
                    options.step = 0;
                }

                if ( options.preload ) {
                    $.vegas( 'preload', options.backgrounds )
                }
            }

            backgrounds = options.backgrounds;
			delay = options.delay;
            step = options.step;

            clearInterval( timer );

            if ( !backgrounds.length ) {
                return $.vegas;
            }

            var doSlideshow = function() {
                if ( step < 0 ) {
                    step = backgrounds.length - 1;
                }

                if ( step >= backgrounds.length || !backgrounds[ step - 1 ] ) {
                    step = 0;
                }

                var settings = backgrounds[ step++ ];
                settings.walk = options.walk;

                $.vegas( settings );
            }
            doSlideshow();

            if ( !keepPause ) {
                paused = false;

                $( 'body' ).trigger( 'vegasstart', [ $current.get(0), step - 1 ] );
            }

            if ( !paused ) {
                timer = setInterval( doSlideshow, options.delay );
            }

            return $.vegas;
        },

        // Jump to the next background in the current slideshow
        next: function() {
            var from = step;

            if ( step ) {
                $.vegas( 'slideshow', { step: step }, true );

                $( 'body' ).trigger( 'vegasnext', [ $current.get(0), step - 1, from - 1 ] );
            }

            return $.vegas;
        },

        // Jump to the previous background in the current slideshow
        previous: function() {
            var from = step;

            if ( step ) {
                $.vegas( 'slideshow', { step: step - 2 }, true );

                $( 'body' ).trigger( 'vegasprevious', [ $current.get(0), step - 1, from - 1 ] );
            }

            return $.vegas;
        },

        // Jump to a specific background in the current slideshow
        jump: function( s ) {
            var from = step;

            if ( step ) {
                $.vegas( 'slideshow', { step: s }, true );

                $( 'body' ).trigger( 'vegasjump', [ $current.get(0), step - 1, from - 1 ] );
            }

            return $.vegas;
        },

        // Stop slideshow
        stop: function() {
            var from = step;
            step = 0;
            paused = null;
            clearInterval( timer );

            $( 'body' ).trigger( 'vegasstop', [ $current.get(0), from - 1 ] );

            return $.vegas;
        },

        // Pause slideShow
        pause: function() {
            paused = true;
            clearInterval( timer );

            $( 'body' ).trigger( 'vegaspause', [ $current.get(0), step - 1 ] );

            return $.vegas;
        },

        // Get some useful values or objects
        get: function( what ) {
            if ( what == null || what == 'background' ) {
                return $current.get(0);
            }

            if ( what == 'overlay' ) {
                return $overlay.get(0);
            }

            if ( what == 'step' ) {
                return step - 1;
            }

            if ( what == 'paused' ) {
                return paused;
            }
        },

        // Preload an array of backgrounds
        preload: function( backgrounds ) {
            for( var i in backgrounds ) {
                if ( backgrounds[ i ].src ) {
                    $('<img src="' + backgrounds[ i ].src + '">');
                }
            }

            return $.vegas;
        }
    }

    // Resize the background
    function resize( $img, settings ) {
        var options =  {
            align: 'center',
            valign: 'center'
        }
        $.extend( options, settings );

        var ww = $( window ).width(),
            wh = $( window ).height(),
            iw = $img.width(),
            ih = $img.height(),
            rw = wh / ww,
            ri = ih / iw,
            newWidth, newHeight,
            newLeft, newTop,
            properties;

        if ( rw > ri ) {
            newWidth = wh / ri;
            newHeight = wh;
        } else {
            newWidth = ww;
            newHeight = ww * ri;
        }

        properties = {
            'width': newWidth + 'px',
            'height': newHeight + 'px',
			'top': 'auto',
			'bottom': 'auto',
			'left': 'auto',
			'right': 'auto'
        }

        if ( !isNaN( parseInt( options.valign ) ) ) {
            properties[ 'top' ] = ( 0 - ( newHeight - wh ) / 100 * parseInt( options.valign ) ) + 'px';
        } else if ( options.valign == 'top' ) {
            properties[ 'top' ] = 0;
        } else if ( options.valign == 'bottom' ) {
            properties[ 'bottom' ] = 0;
        } else {
            properties[ 'top' ] = ( wh - newHeight ) / 2;
        }

        if ( !isNaN( parseInt( options.align ) ) ) {
            properties[ 'left' ] = ( 0 - ( newWidth - ww ) / 100 * parseInt( options.align ) ) + 'px';
        } else if ( options.align == 'left' ) {
            properties[ 'left' ] = 0;
        } else if ( options.align == 'right' ) {
            properties[ 'right' ] = 0;
        } else {
            properties[ 'left' ] = ( ww - newWidth ) / 2 ;
        }

        $img.css( properties );
    }

    // Display the loading indicator
    function loading() {
        $loading.prependTo( 'body' ).fadeIn();
    }

    // Hide the loading indicator
    function loaded() {
        $loading.fadeOut( 'fast', function() {
            $( this ).remove();
        });
    }

    // Get the background image from the body
    function getBackground() {
        if ( $( 'body' ).css( 'backgroundImage' ) ) {
            return $( 'body' ).css( 'backgroundImage' ).replace( /url\("?(.*?)"?\)/i, '$1' );
        }
    }

    // The plugin
    $.vegas = function( method ) {
        if ( methods[ method ] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
        } else if ( typeof method === 'object' || !method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist' );
        }
    };

    // Global parameters
    $.vegas.defaults = {
        background: {
            // src:         string
            // align:       string/int
            // valign:      string/int
            // fade:        int
            // loading      bool
            // load:        function
            // complete:    function
        },
        slideshow: {
            // step:        int
            // delay:       int
            // backgrounds: array
            // preload:     bool
            // walk:        function
        },
        overlay: {
            // src:         string
            // opacity:     float
        }
    }
})( jQuery );<|endoftext|>


<commit_before>'use strict';

var Q = require('q'),
    uuidGen = require('node-uuid'),
    npm_debug = require('debug'),
    log = npm_debug('3dsim:info'),
    error = npm_debug('3dsim:error'),
    debug = npm_debug('3dsim:debug'),
    db = require('spacebox-common-native').db,
    C = require('spacebox-common')

var worldState = require('../world_state.js'),
    solarsystems = require('../solar_systems.js')

function spawnThing(msg, h, fn) {
    return Q.spread([C.getBlueprints(), solarsystems.getSpawnSystemId()], function(blueprints, solar_system) {
        var account, blueprint = blueprints[msg.blueprint]

        if (blueprint === undefined) {
            throw new Error("no such blueprint: "+msg.blueprint)
        }

        if (h.auth.privileged) {
            account = msg.account || h.auth.account
        } else {
            account = h.auth.account
        }

        var obj = C.deepMerge({
            position: msg.position,
            solar_system: msg.solar_system
        } ,{
            blueprint: blueprint.uuid,
            account: account,
            effects: {},
            position: { x: 0, y: 0, z: 0 },
            solar_system: solar_system
        })

        C.deepMerge(blueprint, obj);

        // This is a byproduct of the blueprint's own uuid
        delete obj.uuid

        obj.health = obj.maxHealth

        if (fn !== undefined) {
            // TODO error handling
            fn(obj)
        }

        debug(obj)

        // TODO what if the inventory transaction fails?
        return worldState.addObject(obj).then(function(uuid) {
            console.log("build a %s as %s", msg.blueprint, uuid)

            return [ uuid, blueprint ]
        })
    }).spread(function(uuid, blueprint) {
        var obj = worldState.get(uuid)
        var transaction = msg.inventory_transaction || []

        transaction.push({
            container_action: "create",
            uuid: uuid,
            blueprint: blueprint.uuid
        })

        // TODO what happens if we fail to inform build and inventory,
        // how we converge them?
        return C.updateInventory(h.auth.account, transaction).then(function() {
            if (blueprint.production !== undefined) {
                return C.request('build', 'POST', 201, '/facilities/'+uuid, {
                    blueprint: blueprint.uuid
                }, {
                    sudo_account: h.auth.account
                })
            }
        }).then(function() {
            return uuid
        })
    })

}

function spawnShip(msg, h) {
    return spawnThing(msg, h, function(ship) {
        if (ship.type != 'spaceship') {
            throw new Error("not a spaceship: " + ship.blueprint)
        }

        C.deepMerge({
            velocity: {
                x: 0,
                y: 0,
                z: 0
            },
            facing: {
                x: 0,
                y: 0,
                z: 0,
                w: 1
            }
        }, ship)

        ship.subsystems.forEach(function(s) {
            ship[s].state = "none"
        })
    })
}

function updateFacility(uuid, blueprint, account) {
    return C.request('build', 'POST', 201, '/facilities/'+uuid, {
        blueprint: blueprint
    })
}

var loadout = {
    blueprint: "7abb04d3-7d58-42d8-be93-89eb486a1c67",
    contents: {
        "f9e7e6b4-d5dc-4136-a445-d3adffc23bc6": 35
    }
}

module.exports = {
    'spawn': function(msg, h) {
        return spawnShip(msg, h)
    },
    'spawnStarter': function(msg, h) {
        return db.query("select count(*)::int from space_objects where account_id = $1 and doc::json->>'blueprint' = $2", [ h.auth.account, loadout.blueprint ]).
            then(function(data) {
                if (data[0].count > 0)
                    throw "this account already has a starter ship"

                return spawnShip({
                    blueprint: loadout.blueprint,
                    // TODO copy the position of the spawnpoint
                    position: {
                        x: 1,
                        y: 1,
                        z: 1
                    }
                }, h)
            }).then(function(uuid) {
                var list = []

                for (var type in loadout.contents) {
                    list.push({
                        inventory: uuid,
                        slice: "default",
                        blueprint: type,
                        quantity: loadout.contents[type]
                    })
                }

                return C.updateInventory(h.auth.account, list)
            })
    },
    'undock': function(msg, h) {
        console.log("got the message")
        return C.request('inventory', 'POST', 200, '/ships/'+msg.ship_uuid, {
            in_space: true
        }, {
            sudo_account: h.auth.account
        }).then(function(ship) {
            console.log('spawning ship')
            return spawnShip({
                blueprint: ship.blueprint,
                // TODO spawn it at the location it undocked from
                position: {
                    x: 1,
                    y: 1,
                    z: 1
                }
            }, h)
        })
    },
    'deploy': function(msg, h) {
        return spawnThing({
            blueprint: msg.blueprint,
            inventory_transaction: [{
                inventory: msg.shipID,
                slice: msg.slice,
                blueprint: msg.blueprint,
                quantity: -1
            }]
            // TODO copy the position of the ship
        })
    },
    'spawnStructure': function(msg, h) {
        return spawnThing(msg, h)
    }
}
<commit_msg>fixes<commit_after>'use strict';

var Q = require('q'),
    uuidGen = require('node-uuid'),
    npm_debug = require('debug'),
    log = npm_debug('3dsim:info'),
    error = npm_debug('3dsim:error'),
    debug = npm_debug('3dsim:debug'),
    db = require('spacebox-common-native').db,
    C = require('spacebox-common')

var worldState = require('../world_state.js'),
    solarsystems = require('../solar_systems.js')

function spawnThing(msg, h, fn) {
    return Q.spread([C.getBlueprints(), solarsystems.getSpawnSystemId()], function(blueprints, solar_system) {
        var account, blueprint = blueprints[msg.blueprint]

        if (blueprint === undefined) {
            throw new Error("no such blueprint: "+msg.blueprint)
        }

        if (h.auth.privileged) {
            account = msg.account || h.auth.account
        } else {
            account = h.auth.account
        }

        var obj = C.deepMerge({
            position: msg.position,
            solar_system: msg.solar_system
        } ,{
            blueprint: blueprint.uuid,
            account: account,
            effects: {},
            position: { x: 0, y: 0, z: 0 },
            solar_system: solar_system
        })

        C.deepMerge(blueprint, obj);

        // This is a byproduct of the blueprint's own uuid
        delete obj.uuid

        obj.health = obj.maxHealth

        if (fn !== undefined) {
            // TODO error handling
            fn(obj)
        }

        debug(obj)

        // TODO what if the inventory transaction fails?
        return worldState.addObject(obj).then(function(uuid) {
            console.log("build a %s as %s", msg.blueprint, uuid)

            return [ uuid, blueprint ]
        })
    }).spread(function(uuid, blueprint) {
        var obj = worldState.get(uuid)
        var transaction = msg.inventory_transaction || []

        transaction.push({
            container_action: "create",
            uuid: uuid,
            blueprint: blueprint.uuid
        })

        // TODO what happens if we fail to inform build and inventory,
        // how we converge them?
        return C.updateInventory(h.auth.account, transaction).then(function() {
            if (blueprint.production !== undefined) {
                return C.request('tech', 'POST', 201, '/facilities/'+uuid, {
                    blueprint: blueprint.uuid
                }, {
                    sudo_account: h.auth.account
                })
            }
        }).then(function() {
            return uuid
        })
    })

}

function spawnShip(msg, h) {
    return spawnThing(msg, h, function(ship) {
        if (ship.type != 'spaceship') {
            throw new Error("not a spaceship: " + ship.blueprint)
        }

        C.deepMerge({
            velocity: {
                x: 0,
                y: 0,
                z: 0
            },
            facing: {
                x: 0,
                y: 0,
                z: 0,
                w: 1
            }
        }, ship)

        ship.subsystems.forEach(function(s) {
            ship[s].state = "none"
        })
    })
}

function updateFacility(uuid, blueprint, account) {
    return C.request('tech', 'POST', 201, '/facilities/'+uuid, {
        blueprint: blueprint
    })
}

var loadout = {
    blueprint: "7abb04d3-7d58-42d8-be93-89eb486a1c67",
    contents: {
        "f9e7e6b4-d5dc-4136-a445-d3adffc23bc6": 35
    }
}

module.exports = {
    'spawn': function(msg, h) {
        return spawnShip(msg, h)
    },
    'spawnStarter': function(msg, h) {
        return db.query("select count(*)::int from space_objects where account_id = $1 and doc::json->>'blueprint' = $2", [ h.auth.account, loadout.blueprint ]).
            then(function(data) {
                if (data[0].count > 0)
                    throw "this account already has a starter ship"

                return spawnShip({
                    blueprint: loadout.blueprint,
                    // TODO copy the position of the spawnpoint
                    position: {
                        x: 1,
                        y: 1,
                        z: 1
                    }
                }, h)
            }).then(function(uuid) {
                var list = []

                for (var type in loadout.contents) {
                    list.push({
                        inventory: uuid,
                        slice: "default",
                        blueprint: type,
                        quantity: loadout.contents[type]
                    })
                }

                return C.updateInventory(h.auth.account, list)
            })
    },
    'undock': function(msg, h) {
        console.log("got the message")
        return C.request('tech', 'POST', 200, '/ships/'+msg.ship_uuid, {
            in_space: true
        }, {
            sudo_account: h.auth.account
        }).then(function(ship) {
            console.log('spawning ship')
            return spawnShip({
                blueprint: ship.blueprint,
                // TODO spawn it at the location it undocked from
                position: {
                    x: 1,
                    y: 1,
                    z: 1
                }
            }, h)
        })
    },
    'deploy': function(msg, h) {
        return spawnThing({
            blueprint: msg.blueprint,
            inventory_transaction: [{
                inventory: msg.shipID,
                slice: msg.slice,
                blueprint: msg.blueprint,
                quantity: -1
            }]
            // TODO copy the position of the ship
        })
    },
    'spawnStructure': function(msg, h) {
        return spawnThing(msg, h)
    }
}
<|endoftext|>


<commit_before>(function( $ ){
  'use strict';

var element,
    callbacks = {},
    resultsTitle,
    resultsDivID;

var methods = {
  setup   : function(options){
    element = this; // set element for build_containers()
    if (options.callbacks) callbacks = options.callbacks;

    if(options.resultsDivID){

    	resultsDivID = options.resultsDivID;

    }
    else
    {
    	resultsDivID = 'results';
    }

    if (options.url !== undefined)
      methods.process_from_url(options);
    else
      methods.process(options);
  },
  process : function(options){
    if (callbacks.beforePopulate) {
      callbacks.beforePopulate();
    };

    var self = methods;

    pivot.init(options);

    resultsTitle = options.resultsTitle;

    if (options.skipBuildContainers === undefined || options.skipBuildContainers === false) self.build_containers();

    self.populate_containers();

    $(document).on('change', '.row-labelable', function(event) {
      self.update_label_fields('row');
    });

    $(document).on('change', '.column-labelable', function(event) {
      self.update_label_fields('column');
    });

    $(document).on('change', '.summary', function(event) {
      self.update_summary_fields();
    });

    methods.update_results();

    if (callbacks.afterPopulate) {
      callbacks.afterPopulate();
    };
  },
  process_from_url : function(options){
    var re = /\.json$/i,
        dataType;

    if (re.test(options.url))
      dataType = 'text/json'
    else
      dataType = 'text/csv'

    $.ajax({
      url: options.url,
      dataType: "text",
      accepts: "text/csv",
      success: function(data, status){
        if (dataType === 'text/json')
          options['json'] = data
        else
          options['csv']  = data

        methods.process(options)
      }
    });
  },
  populate_containers: function(){
    methods.build_toggle_fields('#row-label-fields',     pivot.fields().rowLabelable,    'row-labelable');
    methods.build_toggle_fields('#column-label-fields',  pivot.fields().columnLabelable, 'column-labelable');
    methods.build_toggle_fields('#summary-fields',       pivot.fields().summarizable,    'summary');
    methods.build_filter_list();
  },
  reprocess_display : function(options){
    if (options.rowLabels     === undefined) options.rowLabels    = [];
    if (options.columnLabels  === undefined) options.columnLabels = [];
    if (options.summaries     === undefined) options.summaries    = [];
    if (options.filters       === undefined) options.filters      = {};
    if (options.callbacks     === undefined) options.callbacks    = {};

    if (options.callbacks.beforeReprocessDisplay) {
      options.callbacks.afterReprocessDisplay();
    }

    pivot.filters().set(options.filters);
    pivot.display().summaries().set(options.summaries);
    pivot.display().rowLabels().set(options.rowLabels);
    pivot.display().columnLabels().set(options.columnLabels);

    methods.populate_containers();
    methods.update_results();

    if (options.callbacks.afterReprocessDisplay) {
      options.callbacks.afterReprocessDisplay();
    }
  },
  build_containers : function(){

    var containers = '
' +
                     '
' +
                     '  Filter Fields' +
                     '

' +
                     '
' +
                     '
' +
                     '  Row Label Fields' +
                     '

' +
                     '
' +
                     '
' +
                     '  Column Label Fields' +
                     '

' +
                     '
' +
                     '
' +
                     '  Summary Fields' +
                     '

' +
                     '
' +
                     '
';
    element.append(containers);
  },
  // Filters
  build_filter_list : function(){
    var select = '<select id="select-constructor">'
    select += '<option></option>'
    $.each(pivot.fields().filterable, function(index, field){
      select += '<option>' + field.name + '</option>';
    })
    select += '</select>'
    $('#filter-list').empty().append(select);

    // show pre-defined filters (from init)
    $.each(pivot.filters().all(), function(fieldName, restriction){
      methods.build_filter_field(fieldName, restriction);
    });

    // Bind build action to select-constructor explicitly
    $('#select-constructor').change(function(){
      methods.build_filter_field($(this).val());
    })
  },
  build_filter_field : function(fieldName, selectedValue) {
    var snip,
        remove_filter,
        field = pivot.fields().get(fieldName);

    if (fieldName === '') return;

    // Check to see if this field has already been built
    var filterExists = $('#filter-list select[data-field=' + field.name + ']');
    if (filterExists.length) return;

    if (field.filterType === 'regexp')
      snip = methods.build_regexp_filter_field(field, selectedValue);
    else
      snip = methods.build_select_filter_field(field, selectedValue);

    remove_filter = '(X)';
    $('#filter-list').append('

' + field.name + remove_filter + snip + '
');

    // Update field listeners
    $('select.filter').on('change', function(event) {
      methods.update_filtered_rows();
    });

    //Optional Chosen/Select2 integration
    if($.fn.chosen!==undefined) $('select.filter').chosen();
    else if($.fn.select2!==undefined) $('select.filter').select2();

    $('input[type=text].filter').on('keyup', function(event) {
      var filterInput = this,
          eventValue  = $(filterInput).val();

      setTimeout(function(){ if ($(filterInput).val() === eventValue) methods.update_filtered_rows()}, 500);
    });

    // remove_filter listener
    $('.remove-filter-field').click(function(){
      $(this).parents('div').first().remove();
      methods.update_filtered_rows();
    })
  },
  build_select_filter_field : function(field, selectedValue){
    var snip  = '<select class="filter span3" '+(field.filterType==='multiselect'?'multiple':'')+' data-field="' + field.name + '">' +
                '<option></option>',
        orderedValues = [];

    for (var value in field.values){
      orderedValues.push(value);
    };

    orderedValues = orderedValues.sort();
    jQuery.each(orderedValues, function(index, value){
      var selected = "";
      if (value === selectedValue) selected = 'selected="selected"';
      snip += '<option value="' + value + '" ' + selected + '>' + field.values[value].displayValue + '</option>';
    });
    snip += '</select>'

    return snip;
  },
  build_regexp_filter_field : function(field, value){
    if (value === undefined) value = "";
    return '<input type="text" class="filter span3" data-field="' + field.name + '" value="' + value + '">';
  },
  update_filtered_rows :  function(){
    var restrictions = {}, field;

    $('.filter').each(function(index){
      field = pivot.fields().get($(this).attr('data-field'));

      if ($(this).val() !== null && $(this).val()[0] !== ''){
        if (field.filterType === 'regexp')
          restrictions[$(this).attr('data-field')] = new RegExp($(this).val(),'i');
        else
          restrictions[$(this).attr('data-field')] = $(this).val();
      }
    });
    pivot.filters().set(restrictions);
    methods.update_results();
  },

  //toggles

  build_toggle_fields : function(div, fields, klass){
    $(div).empty();
    $.each(fields, function(index, field){
      $(div).append('' +
                    '<input type="checkbox" class="' + klass + '" ' +
                      'data-field="' + field.name + '" ' +
                    '> ' + field.name +
                    '');
    });

    var displayFields;
    if (klass === 'row-labelable')
      displayFields = pivot.display().rowLabels().get
    else if (klass === 'column-labelable')
      displayFields = pivot.display().columnLabels().get
    else
      displayFields = pivot.display().summaries().get

    for (var fieldName in displayFields) {
      var elem = $(div + ' input[data-field="' + fieldName +'"]');
      elem.prop("checked", true);
      methods.orderChecked(div, elem);
    };

    // order listener
    $(div + ' input').on("click", function(){
      if (this.checked) {
        methods.orderChecked(div, this);
      } else {
        var field = $(this).parent().detach()[0];
        $(div).append( field );
      };
    });
  },
  orderChecked : function(parent, elem){
    var last_checked = $(parent + ' input:checked');     // last changed field (lcf)
    var field        = $(elem).parent().detach()[0]; // pluck item from div
    var children     = $(parent).children();

    //subtract 1 because clicked field is already checked insert plucked item into div at index
    if ((last_checked.length-1) === 0)
      $(parent).prepend( field );
    else if (children.length < last_checked.length)
      $(parent).append( field );
    else
      $(children[last_checked.length-1]).before( field );
  },
  update_result_details : function(){
    var snip = '';
    var filters = '';
    $.each(pivot.filters().all(), function(k,v) {
      filters += '' + k + '' + " => " + v + " "
    });

    if ($('#pivot-detail').length !== 0)
      snip += 'Filters: '    + filters + "
"
      $('#pivot-detail').html(snip);
  },
  update_results : function(){
    if (callbacks && callbacks.beforeUpdateResults) {
      callbacks.beforeUpdateResults();
    };

    var results = pivot.results().all(),
        config  = pivot.config(),
        columns = pivot.results().columns(),
        snip    = '',
        fieldName;

    var result_table = $('#' + resultsDivID),
        result_rows;
    result_table.empty();

    snip += '

';

    // build columnLabel header row
    if (config.columnLabels.length > 0 && config.summaries.length > 1) {
      var summarySnip = '', summaryRow = '';
      $.each(config.summaries, function(index, fieldName){
        summarySnip += '' + fieldName + '	';
      })

      snip += '
'
      $.each(columns, function(index, column){
        switch (column.type){
          case 'row':
            snip += ''+ column.fieldName + '	';
            break;
          case 'column':
            snip += '' + column.fieldName + '	';
            summaryRow += summarySnip
            break;
        }
      });
      snip += '

' + summaryRow + '
';
    } else {
      snip += '
'
      $.each(columns, function(index, column){
        if (column.type !== 'column' || config.summaries.length <= 1) {
          snip += '' + column.fieldName + '	';
        } else {
          $.each(config.summaries, function(index, fieldName){
            snip += '' + fieldName + '	';
          });
        }
      });
      snip += '
'
    }
    snip += '

';
    result_table.append(snip);

    result_rows = $('#result-rows');

    $.each(results,function(index, row){
      snip = '
';
      $.each(columns, function(index, column){
        if (column.type !== 'column')
          snip += '' + row[column.fieldName] + '	';
        else {
          $.each(config.summaries, function(index, fieldName){
            if (row[column.fieldName] !== undefined)
              snip += '' + row[column.fieldName][fieldName] + '	';
            else
              snip += ' 	';
          });
        }
      });
      snip += '
';

      result_rows.append(snip);
    });
    methods.update_result_details();

    if (callbacks && callbacks.afterUpdateResults) {
      callbacks.afterUpdateResults();
    };
  },
  update_label_fields :  function(type){
    var display_fields = [];

    $('.' + type + '-labelable:checked').each(function(index){
        display_fields.push($(this).attr('data-field'));
    });

    pivot.display()[type + 'Labels']().set(display_fields);

    methods.update_results();
  },
  update_summary_fields : function(){
    var summary_fields = [];

    $('.summary:checked').each(function(index){
        summary_fields.push($(this).attr('data-field'));
    });

    pivot.display().summaries().set(summary_fields);

    methods.update_results();
  }
};

  $.fn.pivot_display = function( method ) {
    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + '  doesn\'t exists');
    }
  };

})( jQuery );
<commit_msg>Fix Select2 integration. Select2 adds to filter class to multiple elements including divs and inputs used internally by Select2. Exclude the elements which do not have data-field attribute during restrictions build.<commit_after>(function( $ ){
  'use strict';

var element,
    callbacks = {},
    resultsTitle,
    resultsDivID;

var methods = {
  setup   : function(options){
    element = this; // set element for build_containers()
    if (options.callbacks) callbacks = options.callbacks;

    if(options.resultsDivID){

    	resultsDivID = options.resultsDivID;

    }
    else
    {
    	resultsDivID = 'results';
    }

    if (options.url !== undefined)
      methods.process_from_url(options);
    else
      methods.process(options);
  },
  process : function(options){
    if (callbacks.beforePopulate) {
      callbacks.beforePopulate();
    };

    var self = methods;

    pivot.init(options);

    resultsTitle = options.resultsTitle;

    if (options.skipBuildContainers === undefined || options.skipBuildContainers === false) self.build_containers();

    self.populate_containers();

    $(document).on('change', '.row-labelable', function(event) {
      self.update_label_fields('row');
    });

    $(document).on('change', '.column-labelable', function(event) {
      self.update_label_fields('column');
    });

    $(document).on('change', '.summary', function(event) {
      self.update_summary_fields();
    });

    methods.update_results();

    if (callbacks.afterPopulate) {
      callbacks.afterPopulate();
    };
  },
  process_from_url : function(options){
    var re = /\.json$/i,
        dataType;

    if (re.test(options.url))
      dataType = 'text/json'
    else
      dataType = 'text/csv'

    $.ajax({
      url: options.url,
      dataType: "text",
      accepts: "text/csv",
      success: function(data, status){
        if (dataType === 'text/json')
          options['json'] = data
        else
          options['csv']  = data

        methods.process(options)
      }
    });
  },
  populate_containers: function(){
    methods.build_toggle_fields('#row-label-fields',     pivot.fields().rowLabelable,    'row-labelable');
    methods.build_toggle_fields('#column-label-fields',  pivot.fields().columnLabelable, 'column-labelable');
    methods.build_toggle_fields('#summary-fields',       pivot.fields().summarizable,    'summary');
    methods.build_filter_list();
  },
  reprocess_display : function(options){
    if (options.rowLabels     === undefined) options.rowLabels    = [];
    if (options.columnLabels  === undefined) options.columnLabels = [];
    if (options.summaries     === undefined) options.summaries    = [];
    if (options.filters       === undefined) options.filters      = {};
    if (options.callbacks     === undefined) options.callbacks    = {};

    if (options.callbacks.beforeReprocessDisplay) {
      options.callbacks.afterReprocessDisplay();
    }

    pivot.filters().set(options.filters);
    pivot.display().summaries().set(options.summaries);
    pivot.display().rowLabels().set(options.rowLabels);
    pivot.display().columnLabels().set(options.columnLabels);

    methods.populate_containers();
    methods.update_results();

    if (options.callbacks.afterReprocessDisplay) {
      options.callbacks.afterReprocessDisplay();
    }
  },
  build_containers : function(){

    var containers = '
' +
                     '
' +
                     '  Filter Fields' +
                     '

' +
                     '
' +
                     '
' +
                     '  Row Label Fields' +
                     '

' +
                     '
' +
                     '
' +
                     '  Column Label Fields' +
                     '

' +
                     '
' +
                     '
' +
                     '  Summary Fields' +
                     '

' +
                     '
' +
                     '
';
    element.append(containers);
  },
  // Filters
  build_filter_list : function(){
    var select = '<select id="select-constructor">'
    select += '<option></option>'
    $.each(pivot.fields().filterable, function(index, field){
      select += '<option>' + field.name + '</option>';
    })
    select += '</select>'
    $('#filter-list').empty().append(select);

    // show pre-defined filters (from init)
    $.each(pivot.filters().all(), function(fieldName, restriction){
      methods.build_filter_field(fieldName, restriction);
    });

    // Bind build action to select-constructor explicitly
    $('#select-constructor').change(function(){
      methods.build_filter_field($(this).val());
    })
  },
  build_filter_field : function(fieldName, selectedValue) {
    var snip,
        remove_filter,
        field = pivot.fields().get(fieldName);

    if (fieldName === '') return;

    // Check to see if this field has already been built
    var filterExists = $('#filter-list select[data-field=' + field.name + ']');
    if (filterExists.length) return;

    if (field.filterType === 'regexp')
      snip = methods.build_regexp_filter_field(field, selectedValue);
    else
      snip = methods.build_select_filter_field(field, selectedValue);

    remove_filter = '(X)';
    $('#filter-list').append('

' + field.name + remove_filter + snip + '
');

    //Optional Chosen/Select2 integration
    if($.fn.chosen!==undefined) $('select.filter').chosen();
    else if($.fn.select2!==undefined) $('select.filter').select2();

    // Update field listeners
    $('select.filter').on('change', function(event) {
      methods.update_filtered_rows();
    });

    $('input[type=text].filter').on('keyup', function(event) {
      var filterInput = this,
          eventValue  = $(filterInput).val();

      setTimeout(function(){ if ($(filterInput).val() === eventValue) methods.update_filtered_rows()}, 500);
    });

    // remove_filter listener
    $('.remove-filter-field').click(function(){
      $(this).parents('div').first().remove();
      methods.update_filtered_rows();
    })
  },
  build_select_filter_field : function(field, selectedValue){
    var snip  = '<select class="filter span3" '+(field.filterType==='multiselect'?'multiple':'')+' data-field="' + field.name + '">' +
                '<option></option>',
        orderedValues = [];

    for (var value in field.values){
      orderedValues.push(value);
    };

    orderedValues = orderedValues.sort();
    jQuery.each(orderedValues, function(index, value){
      var selected = "";
      if (value === selectedValue) selected = 'selected="selected"';
      snip += '<option value="' + value + '" ' + selected + '>' + field.values[value].displayValue + '</option>';
    });
    snip += '</select>'

    return snip;
  },
  build_regexp_filter_field : function(field, value){
    if (value === undefined) value = "";
    return '<input type="text" class="filter span3" data-field="' + field.name + '" value="' + value + '">';
  },
  update_filtered_rows :  function(){
    var restrictions = {}, field;

    $('.filter').each(function(index){
      field = pivot.fields().get($(this).attr('data-field'));

      if (field) {
        if ($(this).val() !== null && $(this).val()[0] !== ''){
          if (field.filterType === 'regexp')
            restrictions[$(this).attr('data-field')] = new RegExp($(this).val(),'i');
          else
            restrictions[$(this).attr('data-field')] = $(this).val();
        }
      }
    });
    pivot.filters().set(restrictions);
    methods.update_results();
  },

  //toggles

  build_toggle_fields : function(div, fields, klass){
    $(div).empty();
    $.each(fields, function(index, field){
      $(div).append('' +
                    '<input type="checkbox" class="' + klass + '" ' +
                      'data-field="' + field.name + '" ' +
                    '> ' + field.name +
                    '');
    });

    var displayFields;
    if (klass === 'row-labelable')
      displayFields = pivot.display().rowLabels().get
    else if (klass === 'column-labelable')
      displayFields = pivot.display().columnLabels().get
    else
      displayFields = pivot.display().summaries().get

    for (var fieldName in displayFields) {
      var elem = $(div + ' input[data-field="' + fieldName +'"]');
      elem.prop("checked", true);
      methods.orderChecked(div, elem);
    };

    // order listener
    $(div + ' input').on("click", function(){
      if (this.checked) {
        methods.orderChecked(div, this);
      } else {
        var field = $(this).parent().detach()[0];
        $(div).append( field );
      };
    });
  },
  orderChecked : function(parent, elem){
    var last_checked = $(parent + ' input:checked');     // last changed field (lcf)
    var field        = $(elem).parent().detach()[0]; // pluck item from div
    var children     = $(parent).children();

    //subtract 1 because clicked field is already checked insert plucked item into div at index
    if ((last_checked.length-1) === 0)
      $(parent).prepend( field );
    else if (children.length < last_checked.length)
      $(parent).append( field );
    else
      $(children[last_checked.length-1]).before( field );
  },
  update_result_details : function(){
    var snip = '';
    var filters = '';
    $.each(pivot.filters().all(), function(k,v) {
      filters += '' + k + '' + " => " + v + " "
    });

    if ($('#pivot-detail').length !== 0)
      snip += 'Filters: '    + filters + "
"
      $('#pivot-detail').html(snip);
  },
  update_results : function(){
    if (callbacks && callbacks.beforeUpdateResults) {
      callbacks.beforeUpdateResults();
    };

    var results = pivot.results().all(),
        config  = pivot.config(),
        columns = pivot.results().columns(),
        snip    = '',
        fieldName;

    var result_table = $('#' + resultsDivID),
        result_rows;
    result_table.empty();

    snip += '

';

    // build columnLabel header row
    if (config.columnLabels.length > 0 && config.summaries.length > 1) {
      var summarySnip = '', summaryRow = '';
      $.each(config.summaries, function(index, fieldName){
        summarySnip += '' + fieldName + '	';
      })

      snip += '
'
      $.each(columns, function(index, column){
        switch (column.type){
          case 'row':
            snip += ''+ column.fieldName + '	';
            break;
          case 'column':
            snip += '' + column.fieldName + '	';
            summaryRow += summarySnip
            break;
        }
      });
      snip += '

' + summaryRow + '
';
    } else {
      snip += '
'
      $.each(columns, function(index, column){
        if (column.type !== 'column' || config.summaries.length <= 1) {
          snip += '' + column.fieldName + '	';
        } else {
          $.each(config.summaries, function(index, fieldName){
            snip += '' + fieldName + '	';
          });
        }
      });
      snip += '
'
    }
    snip += '

';
    result_table.append(snip);

    result_rows = $('#result-rows');

    $.each(results,function(index, row){
      snip = '
';
      $.each(columns, function(index, column){
        if (column.type !== 'column')
          snip += '' + row[column.fieldName] + '	';
        else {
          $.each(config.summaries, function(index, fieldName){
            if (row[column.fieldName] !== undefined)
              snip += '' + row[column.fieldName][fieldName] + '	';
            else
              snip += ' 	';
          });
        }
      });
      snip += '
';

      result_rows.append(snip);
    });
    methods.update_result_details();

    if (callbacks && callbacks.afterUpdateResults) {
      callbacks.afterUpdateResults();
    };
  },
  update_label_fields :  function(type){
    var display_fields = [];

    $('.' + type + '-labelable:checked').each(function(index){
        display_fields.push($(this).attr('data-field'));
    });

    pivot.display()[type + 'Labels']().set(display_fields);

    methods.update_results();
  },
  update_summary_fields : function(){
    var summary_fields = [];

    $('.summary:checked').each(function(index){
        summary_fields.push($(this).attr('data-field'));
    });

    pivot.display().summaries().set(summary_fields);

    methods.update_results();
  }
};

  $.fn.pivot_display = function( method ) {
    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + '  doesn\'t exists');
    }
  };

})( jQuery );
<|endoftext|>


<commit_before>// Copyright 2014 Volker Sorge
//
// 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.

/**
 * @fileoverview Setup for browser integration of speech rule engine.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */
goog.provide('sre.Browser');

goog.require('sre.BrowserUtil');
goog.require('sre.Engine.Mode');
goog.require('sre.System');

/**
 * Default setup of the Engine.
 */
(sre.System.getInstance()).setupEngine(
    {mode: sre.Engine.Mode.HTTP,
      domain: 'mathspeak',
      style: 'default',
      semantics: true}
);

var SRE = sre.System.getInstance();
<commit_msg>Removes obsolete require before publish.<commit_after>// Copyright 2014 Volker Sorge
//
// 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.

/**
 * @fileoverview Setup for browser integration of speech rule engine.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */
goog.provide('sre.Browser');

goog.require('sre.Engine.Mode');
goog.require('sre.System');

/**
 * Default setup of the Engine.
 */
(sre.System.getInstance()).setupEngine(
    {mode: sre.Engine.Mode.HTTP,
      domain: 'mathspeak',
      style: 'default',
      semantics: true}
);

var SRE = sre.System.getInstance();
<|endoftext|>


<commit_before>//
//  CSVParser.js
//  Mr-Data-Converter
//
//  Input CSV or Tab-delimited data and this will parse it into a Data Grid Javascript object
//
//  CSV Parsing Function from Ben Nadel, http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm

var CSVParser = {

  //---------------------------------------
  // UTILS
  //---------------------------------------

  isNumber: function(string) {
    if( (string == null) || isNaN( new Number(string) ) ) {
      return false;
    }
    return true;
  },

  //---------------------------------------
  // PARSE
  //---------------------------------------

  parse: function (input, headersIncluded) {

    var dataArray = [];

    var errors = [];

    //test for delimiter
    //count the number of commas
    var RE = new RegExp("[^,]", "gi");
    var numCommas = input.replace(RE, "").length;

    //count the number of tabs
    RE = new RegExp("[^\t]", "gi");
    var numTabs = input.replace(RE, "").length;

    var rowDelimiter = "\n";
    //set delimiter
    var columnDelimiter = ",";
    if (numTabs > numCommas) {
      columnDelimiter = "\t"
    };

    // kill extra empty lines
    RE = new RegExp("^" + rowDelimiter + "+", "gi");
    input = input.replace(RE, "");
    RE = new RegExp(rowDelimiter + "+$", "gi");
    input = input.replace(RE, "");

    // var arr = input.split(rowDelimiter);
    //
    // for (var i=0; i < arr.length; i++) {
    //   dataArray.push(arr[i].split(columnDelimiter));
    // };

    // dataArray = jQuery.csv(columnDelimiter)(input);
    dataArray = this.CSVToArray(input, columnDelimiter);

    //escape out any tabs or returns or new lines
    for (var i = dataArray.length - 1; i >= 0; i--){
      for (var j = dataArray[i].length - 1; j >= 0; j--){
        dataArray[i][j] = dataArray[i][j].replace("\t", "\\t");
        dataArray[i][j] = dataArray[i][j].replace("\n", "\\n");
        dataArray[i][j] = dataArray[i][j].replace("\r", "\\r");
      };
    };

    var headerNames = [];
    var headerTypes = [];
    var numColumns = dataArray[0].length;
    var numRows = dataArray.length;
    if (headersIncluded) {

      //remove header row
      headerNames = dataArray.splice(0,1)[0];
      numRows = dataArray.length;

    } else { //if no headerNames provided

      //create generic property names
      for (var i=0; i < numColumns; i++) {
        headerNames.push("val"+String(i));
        headerTypes.push("");
      };

    }

    //test all the rows for proper number of columns.
    for (var i=0; i < dataArray.length; i++) {
      var numValues = dataArray[i].length;
      if (numValues != numColumns) {this.log("Error parsing row "+String(i)+". Wrong number of columns.")};
    };

    //test columns for number data type
    var numRowsToTest = numColumns;
    var threshold = 0.5;
    for (var i=0; i < headerNames.length; i++) {
      var numFloats = 0;
      var numInts = 0;
      for (var r=0; r < numRowsToTest; r++) {
        if (CSVParser.isNumber(dataArray[r][i])) {
          numInts++
          if (String(dataArray[r][i]).indexOf(".") > 0) {
            numFloats++
          }
        };
      };

      if ((numInts / numRowsToTest) > threshold){
        if (numFloats > 0) {
          headerTypes[i] = "float"
        } else {
          headerTypes[i] = "int"
        }
      } else {
        headerTypes[i] = "string"
      }
    }

    return {'dataGrid':dataArray, 'headerNames':headerNames, 'headerTypes':headerTypes, 'errors':this.getLog()}

  },

  //---------------------------------------
  // ERROR LOGGING
  //---------------------------------------
  errorLog:[],

  resetLog: function() {
    this.errorLog = [];
  },

  log: function(l) {
    this.errorLog.push(l);
  },

  getLog: function() {
    var out = "";
    if (this.errorLog.length > 0) {
      for (var i=0; i < this.errorLog.length; i++) {
        out += ("!!"+this.errorLog[i] + "!!\n");
      };
      out += "\n"
    };

    return out;
  },

  //---------------------------------------
  // UTIL
  //---------------------------------------

    // This Function from Ben Nadel, http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
  	// This will parse a delimited string into an array of
  	// arrays. The default delimiter is the comma, but this
  	// can be overriden in the second argument.
  	CSVToArray: function( strData, strDelimiter ){
  		// Check to see if the delimiter is defined. If not,
  		// then default to comma.
  		strDelimiter = (strDelimiter || ",");

  		// Create a regular expression to parse the CSV values.
  		var objPattern = new RegExp(
  			(
  				// Delimiters.
  				"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +

  				// Quoted fields.
  				"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +

  				// Standard fields.
  				"([^\"\\" + strDelimiter + "\\r\\n]*))"
  			),
  			"gi"
  			);

  		// Create an array to hold our data. Give the array
  		// a default empty first row.
  		var arrData = [[]];

  		// Create an array to hold our individual pattern
  		// matching groups.
  		var arrMatches = null;

  		// Keep looping over the regular expression matches
  		// until we can no longer find a match.
  		while (arrMatches = objPattern.exec( strData )){

  			// Get the delimiter that was found.
  			var strMatchedDelimiter = arrMatches[ 1 ];

  			// Check to see if the given delimiter has a length
  			// (is not the start of string) and if it matches
  			// field delimiter. If id does not, then we know
  			// that this delimiter is a row delimiter.
  			if (
  				strMatchedDelimiter.length &&
  				(strMatchedDelimiter != strDelimiter)
  				){

  				// Since we have reached a new row of data,
  				// add an empty row to our data array.
  				arrData.push( [] );

  			}

  			// Now that we have our delimiter out of the way,
  			// let's check to see which kind of value we
  			// captured (quoted or unquoted).
  			if (arrMatches[ 2 ]){

  				// We found a quoted value. When we capture
  				// this value, unescape any double quotes.
  				var strMatchedValue = arrMatches[ 2 ].replace(
  					new RegExp( "\"\"", "g" ),
  					"\""
  					);

  			} else {

  				// We found a non-quoted value.
  				var strMatchedValue = arrMatches[ 3 ];

  			}

  			// Now that we have our value string, let's add
  			// it to the data array.
  			arrData[ arrData.length - 1 ].push( strMatchedValue );
  		}

  		// Return the parsed data.
  		return( arrData );
  	}

}<commit_msg>Fixed an error with an undefined object when checking for data types<commit_after>//
//  CSVParser.js
//  Mr-Data-Converter
//
//  Input CSV or Tab-delimited data and this will parse it into a Data Grid Javascript object
//
//  CSV Parsing Function from Ben Nadel, http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm

var CSVParser = {

  //---------------------------------------
  // UTILS
  //---------------------------------------

  isNumber: function(string) {
    if( (string == null) || isNaN( new Number(string) ) ) {
      return false;
    }
    return true;
  },

  //---------------------------------------
  // PARSE
  //---------------------------------------

  parse: function (input, headersIncluded) {

    var dataArray = [];

    var errors = [];

    //test for delimiter
    //count the number of commas
    var RE = new RegExp("[^,]", "gi");
    var numCommas = input.replace(RE, "").length;

    //count the number of tabs
    RE = new RegExp("[^\t]", "gi");
    var numTabs = input.replace(RE, "").length;

    var rowDelimiter = "\n";
    //set delimiter
    var columnDelimiter = ",";
    if (numTabs > numCommas) {
      columnDelimiter = "\t"
    };

    // kill extra empty lines
    RE = new RegExp("^" + rowDelimiter + "+", "gi");
    input = input.replace(RE, "");
    RE = new RegExp(rowDelimiter + "+$", "gi");
    input = input.replace(RE, "");

    // var arr = input.split(rowDelimiter);
    //
    // for (var i=0; i < arr.length; i++) {
    //   dataArray.push(arr[i].split(columnDelimiter));
    // };

    // dataArray = jQuery.csv(columnDelimiter)(input);
    dataArray = this.CSVToArray(input, columnDelimiter);

    //escape out any tabs or returns or new lines
    for (var i = dataArray.length - 1; i >= 0; i--){
      for (var j = dataArray[i].length - 1; j >= 0; j--){
        dataArray[i][j] = dataArray[i][j].replace("\t", "\\t");
        dataArray[i][j] = dataArray[i][j].replace("\n", "\\n");
        dataArray[i][j] = dataArray[i][j].replace("\r", "\\r");
      };
    };

    var headerNames = [];
    var headerTypes = [];
    var numColumns = dataArray[0].length;
    var numRows = dataArray.length;
    if (headersIncluded) {

      //remove header row
      headerNames = dataArray.splice(0,1)[0];
      numRows = dataArray.length;

    } else { //if no headerNames provided

      //create generic property names
      for (var i=0; i < numColumns; i++) {
        headerNames.push("val"+String(i));
        headerTypes.push("");
      };

    }

    //test all the rows for proper number of columns.
    for (var i=0; i < dataArray.length; i++) {
      var numValues = dataArray[i].length;
      if (numValues != numColumns) {this.log("Error parsing row "+String(i)+". Wrong number of columns.")};
    };

    //test columns for number data type
    var numRowsToTest = numColumns;
    var threshold = 0.5;
    for (var i=0; i < headerNames.length; i++) {
      var numFloats = 0;
      var numInts = 0;
      for (var r=0; r < numRowsToTest; r++) {
        if (dataArray[r]) {
          if (CSVParser.isNumber(dataArray[r][i])) {
            numInts++
            if (String(dataArray[r][i]).indexOf(".") > 0) {
              numFloats++
            }
          };
        };

      };

      if ((numInts / numRowsToTest) > threshold){
        if (numFloats > 0) {
          headerTypes[i] = "float"
        } else {
          headerTypes[i] = "int"
        }
      } else {
        headerTypes[i] = "string"
      }
    }

    return {'dataGrid':dataArray, 'headerNames':headerNames, 'headerTypes':headerTypes, 'errors':this.getLog()}

  },

  //---------------------------------------
  // ERROR LOGGING
  //---------------------------------------
  errorLog:[],

  resetLog: function() {
    this.errorLog = [];
  },

  log: function(l) {
    this.errorLog.push(l);
  },

  getLog: function() {
    var out = "";
    if (this.errorLog.length > 0) {
      for (var i=0; i < this.errorLog.length; i++) {
        out += ("!!"+this.errorLog[i] + "!!\n");
      };
      out += "\n"
    };

    return out;
  },

  //---------------------------------------
  // UTIL
  //---------------------------------------

    // This Function from Ben Nadel, http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
  	// This will parse a delimited string into an array of
  	// arrays. The default delimiter is the comma, but this
  	// can be overriden in the second argument.
  	CSVToArray: function( strData, strDelimiter ){
  		// Check to see if the delimiter is defined. If not,
  		// then default to comma.
  		strDelimiter = (strDelimiter || ",");

  		// Create a regular expression to parse the CSV values.
  		var objPattern = new RegExp(
  			(
  				// Delimiters.
  				"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +

  				// Quoted fields.
  				"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +

  				// Standard fields.
  				"([^\"\\" + strDelimiter + "\\r\\n]*))"
  			),
  			"gi"
  			);

  		// Create an array to hold our data. Give the array
  		// a default empty first row.
  		var arrData = [[]];

  		// Create an array to hold our individual pattern
  		// matching groups.
  		var arrMatches = null;

  		// Keep looping over the regular expression matches
  		// until we can no longer find a match.
  		while (arrMatches = objPattern.exec( strData )){

  			// Get the delimiter that was found.
  			var strMatchedDelimiter = arrMatches[ 1 ];

  			// Check to see if the given delimiter has a length
  			// (is not the start of string) and if it matches
  			// field delimiter. If id does not, then we know
  			// that this delimiter is a row delimiter.
  			if (
  				strMatchedDelimiter.length &&
  				(strMatchedDelimiter != strDelimiter)
  				){

  				// Since we have reached a new row of data,
  				// add an empty row to our data array.
  				arrData.push( [] );

  			}

  			// Now that we have our delimiter out of the way,
  			// let's check to see which kind of value we
  			// captured (quoted or unquoted).
  			if (arrMatches[ 2 ]){

  				// We found a quoted value. When we capture
  				// this value, unescape any double quotes.
  				var strMatchedValue = arrMatches[ 2 ].replace(
  					new RegExp( "\"\"", "g" ),
  					"\""
  					);

  			} else {

  				// We found a non-quoted value.
  				var strMatchedValue = arrMatches[ 3 ];

  			}

  			// Now that we have our value string, let's add
  			// it to the data array.
  			arrData[ arrData.length - 1 ].push( strMatchedValue );
  		}

  		// Return the parsed data.
  		return( arrData );
  	}

}<|endoftext|>


<commit_before>// Copyright 2016, University of Colorado Boulder

/**
 * IO type for Emitter
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrew Adare (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var ValidatorDef = require( 'AXON/ValidatorDef' );
  var axon = require( 'AXON/axon' );
  var FunctionIO = require( 'TANDEM/types/FunctionIO' );
  var ObjectIO = require( 'TANDEM/types/ObjectIO' );
  var phetioInherit = require( 'TANDEM/phetioInherit' );
  var VoidIO = require( 'TANDEM/types/VoidIO' );

  // allowed keys
  var ELEMENT_KEYS = [
    'name', // {string}
    'type', // {ObjectIO}
    'documentation', // {string}
    'validator' // {ValidatorDef} - This should be a complete validator, it will not be combined with type.validator.
  ];

  /**
   * IO type for Emitter
   * Emitter for 0, 1 or 2 args, or maybe 3.
   *
   * @param {Object[]} argumentObjects, each with {name:string, type: IO type, documentation: string}
   * @returns {EmitterIOImpl} - the parameterized type
   * @constructor
   */
  function EmitterIO( argumentObjects ) {

    assert && assert( Array.isArray( argumentObjects ) );

    var elementTypes = argumentObjects.map( function( argumentObject ) {

      // validate the look of the content
      assert && assert( argumentObject !== null && typeof argumentObject === 'object' );
      assert && argumentObject.validator && ValidatorDef.validateValidator( argumentObject.validator );

      var keys = Object.keys( argumentObject );
      for ( let i = 0; i < keys.length; i++ ) {
        const key = keys[ i ];
        assert && assert( ELEMENT_KEYS.indexOf( key ) >= 0, 'unrecognized argumentObject key: ' + key );
      }
      assert && assert( argumentObject.type, 'required argumentObject key: type.' );

      return argumentObject.type;
    } );

    var validators = argumentObjects.map( argumentObject => argumentObject.validator || argumentObject.type.validator );

    /**
     * @param {Emitter} emitter
     * @param {string} phetioID
     * @constructor
     */
    var EmitterIOImpl = function EmitterIOImpl( emitter, phetioID ) {
      assert && assert( argumentObjects, 'phetioArgumentTypes should be defined' );

      ObjectIO.call( this, emitter, phetioID );
    };

    return phetioInherit( ObjectIO, 'EmitterIO', EmitterIOImpl, {
      addListener: {
        returnType: VoidIO,
        parameterTypes: [ FunctionIO( VoidIO, elementTypes ) ],
        implementation: function( listener ) {
          this.instance.addListener( listener );
        },
        documentation: 'Adds a listener which will be called when the emitter emits.'
      },
      emit: {
        returnType: VoidIO,
        parameterTypes: elementTypes,

        // Match Emitter.emit's dynamic number of arguments
        implementation: function() {
          this.instance.emit.apply( this.instance, arguments );
        },
        documentation: 'Emits a single event to all listeners.',
        invocableForReadOnlyInstances: false
      }
    }, {
      documentation: 'Emits when an event occurs. ' + ( argumentObjects.length === 0 ? 'No arguments.' : 'The arguments are:
' +
                     '
' + argumentObjects.map( function( element ) {
          var docText = element.documentation ? '. ' + element.documentation : '';
          return '
' + element.name + ': ' + element.type.typeName + docText + '
';
        } ).join( '\n' ) + '
' ),

      events: [ 'emitted' ],

      /**
       * {Array.<ObjectIO>} - typeIOs
       */
      parameterTypes: elementTypes,

      /**
       * {Array.<Object>} - see constructor for details on object literal keys
       */
      elements: argumentObjects,

      /**
       * A list of validators, one for each argument that will be emitted.
       * {ValidatorDef[]}
       */
      validators: validators,

      validator: { isValidValue: v => v instanceof phet.axon.Emitter }
    } );
  }

  axon.register( 'EmitterIO', EmitterIO );

  return EmitterIO;
} );

<commit_msg>add validator doc, https://github.com/phetsims/axon/issues/229<commit_after>// Copyright 2016, University of Colorado Boulder

/**
 * IO type for Emitter.
 *
 * Providing validators to instrumented Emitters:
 * Instrumented Emitters should have their `validators` for each argument passed via EmitterIO (the phetioType).
 * To provide validators, there are two methods. First, by default each TypeIO has its own
 * validator that will be used. So specifying an argument object like `{ type: NumberIO }` will automatically use
 * `NumberIO.validator` as the validator. This can be overridden with the `validator` key (second option), like
 * { type: NumberIO, validator: { isValidValue: v=> typeof v === 'number' &&  v < 5 } }`
 * NOTE: currently the implementation is either/or, if a validator is provided via the `validator` key, the validator
 * from the `type` will be ignored.
 * see https://github.com/phetsims/axon/issues/204 for more details.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 * @author Andrew Adare (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var ValidatorDef = require( 'AXON/ValidatorDef' );
  var axon = require( 'AXON/axon' );
  var FunctionIO = require( 'TANDEM/types/FunctionIO' );
  var ObjectIO = require( 'TANDEM/types/ObjectIO' );
  var phetioInherit = require( 'TANDEM/phetioInherit' );
  var VoidIO = require( 'TANDEM/types/VoidIO' );

  // allowed keys
  var ELEMENT_KEYS = [
    'name', // {string}
    'type', // {ObjectIO}
    'documentation', // {string}
    'validator' // {ValidatorDef} - This should be a complete validator, it will not be combined with type.validator.
  ];

  /**
   * IO type for Emitter
   * Emitter for 0, 1 or 2 args, or maybe 3.
   *
   * @param {Object[]} argumentObjects, each with {name:string, type: IO type, documentation: string}
   * @returns {EmitterIOImpl} - the parameterized type
   * @constructor
   */
  function EmitterIO( argumentObjects ) {

    assert && assert( Array.isArray( argumentObjects ) );

    var elementTypes = argumentObjects.map( function( argumentObject ) {

      // validate the look of the content
      assert && assert( argumentObject !== null && typeof argumentObject === 'object' );
      assert && argumentObject.validator && ValidatorDef.validateValidator( argumentObject.validator );

      var keys = Object.keys( argumentObject );
      for ( let i = 0; i < keys.length; i++ ) {
        const key = keys[ i ];
        assert && assert( ELEMENT_KEYS.indexOf( key ) >= 0, 'unrecognized argumentObject key: ' + key );
      }
      assert && assert( argumentObject.type, 'required argumentObject key: type.' );

      return argumentObject.type;
    } );

    var validators = argumentObjects.map( argumentObject => argumentObject.validator || argumentObject.type.validator );

    /**
     * @param {Emitter} emitter
     * @param {string} phetioID
     * @constructor
     */
    var EmitterIOImpl = function EmitterIOImpl( emitter, phetioID ) {
      assert && assert( argumentObjects, 'phetioArgumentTypes should be defined' );

      ObjectIO.call( this, emitter, phetioID );
    };

    return phetioInherit( ObjectIO, 'EmitterIO', EmitterIOImpl, {
      addListener: {
        returnType: VoidIO,
        parameterTypes: [ FunctionIO( VoidIO, elementTypes ) ],
        implementation: function( listener ) {
          this.instance.addListener( listener );
        },
        documentation: 'Adds a listener which will be called when the emitter emits.'
      },
      emit: {
        returnType: VoidIO,
        parameterTypes: elementTypes,

        // Match Emitter.emit's dynamic number of arguments
        implementation: function() {
          this.instance.emit.apply( this.instance, arguments );
        },
        documentation: 'Emits a single event to all listeners.',
        invocableForReadOnlyInstances: false
      }
    }, {
      documentation: 'Emits when an event occurs. ' + ( argumentObjects.length === 0 ? 'No arguments.' : 'The arguments are:
' +
                     '
' + argumentObjects.map( function( element ) {
          var docText = element.documentation ? '. ' + element.documentation : '';
          return '
' + element.name + ': ' + element.type.typeName + docText + '
';
        } ).join( '\n' ) + '
' ),

      events: [ 'emitted' ],

      /**
       * {Array.<ObjectIO>} - typeIOs
       */
      parameterTypes: elementTypes,

      /**
       * {Array.<Object>} - see constructor for details on object literal keys
       */
      elements: argumentObjects,

      /**
       * A list of validators, one for each argument that will be emitted.
       * {ValidatorDef[]}
       */
      validators: validators,

      validator: { isValidValue: v => v instanceof phet.axon.Emitter }
    } );
  }

  axon.register( 'EmitterIO', EmitterIO );

  return EmitterIO;
} );

<|endoftext|>


<commit_before>// Copyright 2015, University of Colorado Boulder

/**
 * @author Jonathan Olson
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  /**
   * @param {string} name
   * @constructor
   */
  function Namespace( name ) {

    this.name = name; // @public (read-only)

    if ( window.phet ) {
      assert && assert( !window.phet[ name ] );
      window.phet[ name ] = this;
    }
  }

  Namespace.prototype = {
    constructor: Namespace,

    /**
     * Registers a key-value pair with the namespace.
     *
     * If there are no dots ('.') in the key, it will be assigned to the namespace. For example:
     * - x.register( 'A', A );
     * will set x.A = A.
     *
     * If the key contains one or more dots ('.'), it's treated somewhat like a path expression. For instance, if the
     * following is called:
     * - x.register( 'A.B.C', C );
     * then the register function will navigate to the object x.A.B and add x.A.B.C = C.
     *
     * @param {string} key
     * @param {*} value
     * @public
     */
    register: function( key, value ) {
      // If the key isn't compound (doesn't contain '.'), we can just look it up on this namespace
      if ( key.indexOf( '.' ) < 0 ) {
        assert && assert( !this[ key ], key + ' is already registered for namespace ' + this.name );
        this[ key ] = value;
      }
      // Compound (contains '.' at least once). x.register( 'A.B.C', C ) should set x.A.B.C.
      else {
        var keys = key.split( '.' ); // e.g. [ 'A', 'B', 'C' ]

        // Walk into the namespace, verifying that each level exists. e.g. parent => x.A.B
        var parent = this;
        for ( var i = 0; i < keys.length - 1; i++ ) { // for all but the last key
          assert && assert( !!parent[ keys[ i ] ],
            [ this.name ].concat( keys.slice( 0, i + 1 ) ).join( '.' ) + ' needs to be defined to register ' + key );

          parent = parent[ keys[ i ] ];
        }

        // Write into the inner namespace, e.g. x.A.B[ 'C' ] = C
        var lastKey = keys[ keys.length - 1 ];
        assert && assert( !parent[ lastKey ], key + ' is already registered for namespace ' + this.name );
        parent[ lastKey ] = value;
      }

      return value;
    }
  };

  return Namespace;
} );
<commit_msg>add blank lines<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * @author Jonathan Olson
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  /**
   * @param {string} name
   * @constructor
   */
  function Namespace( name ) {

    this.name = name; // @public (read-only)

    if ( window.phet ) {
      assert && assert( !window.phet[ name ] );
      window.phet[ name ] = this;
    }
  }

  Namespace.prototype = {

    constructor: Namespace,

    /**
     * Registers a key-value pair with the namespace.
     *
     * If there are no dots ('.') in the key, it will be assigned to the namespace. For example:
     * - x.register( 'A', A );
     * will set x.A = A.
     *
     * If the key contains one or more dots ('.'), it's treated somewhat like a path expression. For instance, if the
     * following is called:
     * - x.register( 'A.B.C', C );
     * then the register function will navigate to the object x.A.B and add x.A.B.C = C.
     *
     * @param {string} key
     * @param {*} value
     * @public
     */
    register: function( key, value ) {

      // If the key isn't compound (doesn't contain '.'), we can just look it up on this namespace
      if ( key.indexOf( '.' ) < 0 ) {
        assert && assert( !this[ key ], key + ' is already registered for namespace ' + this.name );
        this[ key ] = value;
      }
      // Compound (contains '.' at least once). x.register( 'A.B.C', C ) should set x.A.B.C.
      else {
        var keys = key.split( '.' ); // e.g. [ 'A', 'B', 'C' ]

        // Walk into the namespace, verifying that each level exists. e.g. parent => x.A.B
        var parent = this;
        for ( var i = 0; i < keys.length - 1; i++ ) { // for all but the last key
          assert && assert( !!parent[ keys[ i ] ],
            [ this.name ].concat( keys.slice( 0, i + 1 ) ).join( '.' ) + ' needs to be defined to register ' + key );

          parent = parent[ keys[ i ] ];
        }

        // Write into the inner namespace, e.g. x.A.B[ 'C' ] = C
        var lastKey = keys[ keys.length - 1 ];
        assert && assert( !parent[ lastKey ], key + ' is already registered for namespace ' + this.name );
        parent[ lastKey ] = value;
      }

      return value;
    }
  };

  return Namespace;
} );
<|endoftext|>