text:
// this allow to used the convenient $ notation in  a plugins
(function($) {

    $.extend({ gameQuery: {
        /**
         * This is the Animation Object
         */
        Animation: function (options) {
            // private default values
            var defaults = {
                imageURL:       "",
                numberOfFrame:  1,
                delta:          0,
                rate:           30,
                type:           0,
                distance:       0,
                offsetx:        0,
                offsety:        0
            };

            // options extends defaults
            options = $.extend(defaults, options);

            //"public" attributes:
            this.imageURL       = options.imageURL;     // The url of the image to be used as an animation or sprite
            this.numberOfFrame  = options.numberOfFrame;// The number of frame to be displayed when playing the animation
            this.delta          = options.delta;        // The the distance in pixels between two frame
            this.rate           = options.rate;         // The rate at which the frame must be played in miliseconds
            this.type           = options.type;         // The type of the animation.This is bitwise OR of the properties.
            this.distance       = options.distance;     // The the distance in pixels between two animation
            this.offsetx        = options.offsetx;      // The x coordinate where the first sprite begin
            this.offsety        = options.offsety;      // The y coordinate where the first sprite begin

            //Whenever a new animation is created we add it to the ResourceManager animation list
            $.gameQuery.resourceManager.addAnimation(this);

            return true;
        },

        // "constants" for the different type of an animation
        ANIMATION_VERTICAL:   1,  // genertated by a verical offset of the background
        ANIMATION_HORIZONTAL: 2,  // genertated by a horizontal offset of the background
        ANIMATION_ONCE:       4,  // played only once (else looping indefinitly)
        ANIMATION_CALLBACK:   8,  // A callack is exectued at the end of a cycle
        ANIMATION_MULTI:      16, // The image file contains many animations

        // "constants" for the different type of geometry for a sprite
        GEOMETRY_RECTANGLE:   1,
        GEOMETRY_DISC:        2,

        // basic values
        refreshRate:          30,

        /**
         * An object to manages the resources loading
         **/
        resourceManager: {
            animations: [],    // List of animation / images used in the game
            sounds:     [],    // List of sounds used in the game
            callbacks:  [],    // List of the functions called at each refresh
            running:    false, // State of the game,

            /**
             * This function the covers things to load befor to start the game.
             **/
            preload: function() {
                //Start loading the images
                for (var i = this.animations.length-1 ; i >= 0; i --){
                    this.animations[i].domO = new Image();
                    this.animations[i].domO.src = this.animations[i].imageURL;
                }

                //Start loading the sounds
                for (var i = this.sounds.length-1 ; i >= 0; i --){
                    this.sounds[i].load();
                }

                $.gameQuery.resourceManager.waitForResources();
            },

            /**
             * This function the waits for all the resources called for in preload() to finish loading.
             **/
            waitForResources: function() {
                var loadbarEnabled = ($.gameQuery.loadbar != undefined);
                if(loadbarEnabled){
                    $($.gameQuery.loadbar.id).width(0);
                    var loadBarIncremant = $.gameQuery.loadbar.width / (this.animations.length + this.sounds.length);
                }
                //check the images
                var imageCount = 0;
                for(var i=0; i < this.animations.length; i++){
                    if(this.animations[i].domO.complete){
                        imageCount++;
                    }
                }
                //check the sounds
                var soundCount = 0;
                for(var i=0; i < this.sounds.length; i++){
                    var temp = this.sounds[i].ready();
                    if(temp){
                        soundCount++;
                    }
                }
                //update the loading bar
                if(loadbarEnabled){
                    $("#"+$.gameQuery.loadbar.id).width((imageCount+soundCount)*loadBarIncremant);
                    if($.gameQuery.loadbar.callback){
                        $.gameQuery.loadbar.callback((imageCount+soundCount)/(this.animations.length + this.sounds.length)*100);
                    }
                }
                if($.gameQuery.resourceManager.loadCallback){
                    var percent = (imageCount+soundCount)/(this.animations.length + this.sounds.length)*100;
                    $.gameQuery.resourceManager.loadCallback(percent);
                }
                if(imageCount + soundCount < (this.animations.length + this.sounds.length)){
                    imgWait=setTimeout(function () {
                        $.gameQuery.resourceManager.waitForResources();
                    }, 100);
                } else {
                    // all the resources are loaded!
                    // We can associate the animation's images to their coresponding sprites
                    $.gameQuery.sceengraph.children().each(function(){
                        // recursive call on the children:
                        $(this).children().each(arguments.callee);
                        // add the image as a background
                        if(this.gameQuery && this.gameQuery.animation){
                            $(this).css("background-image", "url("+this.gameQuery.animation.imageURL+")");
                            // we set the correct kind of repeat
                            if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
                                $(this).css("background-repeat", "repeat-x");
                            } else if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
                                $(this).css("background-repeat", "repeat-y");
                            } else {
                                $(this).css("background-repeat", "no-repeat");
                            }
                        }
                    });

                    // And launch the refresh loop
                    $.gameQuery.resourceManager.running = true;
                    setInterval(function () {
                        $.gameQuery.resourceManager.refresh();
                    },($.gameQuery.refreshRate));
                    if($.gameQuery.startCallback){
                        $.gameQuery.startCallback();
                    }
                    //make the sceengraph visible
                    $.gameQuery.sceengraph.css("visibility","visible");
                }
            },

            /**
             * This function refresh a unique sprite here 'this' represent a dom object
             **/
            refreshSprite: function() {
                //Call this function on all the children:
                // is 'this' a sprite ?
                if(this.gameQuery != undefined){
                    var gameQuery = this.gameQuery;
                    // does 'this' has an animation ?
                    if(gameQuery.animation){
                        //Do we have anything to do?
                        if(gameQuery.idleCounter == gameQuery.animation.rate-1){
                            // does 'this' loops?
                            if(gameQuery.animation.type & $.gameQuery.ANIMATION_ONCE){
                                if(gameQuery.currentFrame < gameQuery.animation.numberOfFrame-2){
                                    gameQuery.currentFrame++;
                                } else if(gameQuery.currentFrame == gameQuery.animation.numberOfFrame-2) {
                                    gameQuery.currentFrame++;
                                    // does 'this' has a callback ?
                                    if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){
                                        if($.isFunction(gameQuery.callback)){
                                            gameQuery.callback(this);
                                        }
                                    }
                                }
                            } else {
                                gameQuery.currentFrame = (gameQuery.currentFrame+1)%gameQuery.animation.numberOfFrame;
                                if(gameQuery.currentFrame == 0){
                                    // does 'this' has a callback ?
                                    if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){
                                        if($.isFunction(gameQuery.callback)){
                                            gameQuery.callback(this);
                                        }
                                    }
                                }
                            }
                            // update the background:
                            if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL){
                                if(gameQuery.multi){
                                    $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.multi)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px");
                                } else {
                                    $(this).css("background-position",""+(-gameQuery.animation.offsetx)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px");
                                }
                            } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
                                if(gameQuery.multi){
                                    $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety-gameQuery.multi)+"px");
                                } else {
                                    $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety)+"px");
                                }
                            }
                        }
                        gameQuery.idleCounter = (gameQuery.idleCounter+1)%gameQuery.animation.rate;
                    }
                }
                return true;
            },

            /**
             * This function refresh a unique tile-map here 'this' represent a dom object
             **/
            refreshTilemap: function() {
                //Call this function on all the children:
                // is 'this' a sprite ?
                if(this.gameQuery != undefined){
                    var gameQuery = this.gameQuery;
                    if($.isArray(gameQuery.frameTracker)){
                        for(var i=0; i<gameQuery.frameTracker.length; i++){
                            //Do we have anything to do?
                            if(gameQuery.idleCounter[i] == gameQuery.animations[i].rate-1){
                                // does 'this' loops?
                                if(gameQuery.animations[i].type & $.gameQuery.ANIMATION_ONCE){
                                    if(gameQuery.frameTracker[i] < gameQuery.animations[i].numberOfFrame-1){
                                        gameQuery.frameTracker[i]++;
                                    }
                                } else {
                                    gameQuery.frameTracker[i] = (gameQuery.frameTracker[i]+1)%gameQuery.animations[i].numberOfFrame;
                                }
                            }
                            gameQuery.idleCounter[i] = (gameQuery.idleCounter[i]+1)%gameQuery.animations[i].rate;
                        }
                    } else {
                        //Do we have anything to do?
                        if(gameQuery.idleCounter == gameQuery.animations.rate-1){
                            // does 'this' loops?
                            if(gameQuery.animations.type & $.gameQuery.ANIMATION_ONCE){
                                if(gameQuery.frameTracker < gameQuery.animations.numberOfFrame-1){
                                    gameQuery.frameTracker++;
                                }
                            } else {
                                gameQuery.frameTracker = (gameQuery.frameTracker+1)%gameQuery.animations.numberOfFrame;
                            }
                        }
                        gameQuery.idleCounter = (gameQuery.idleCounter+1)%gameQuery.animations.rate;
                    }

                    // update the background of all active tiles:
                    $(this).find(".active").each(function(){
                        if($.isArray(gameQuery.frameTracker)){
                            var animationNumber = this.gameQuery.animationNumber
                            if(gameQuery.animations[animationNumber].type & $.gameQuery.ANIMATION_VERTICAL){
                                $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx)+"px "+(-gameQuery.animations[animationNumber].offsety-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px");
                            } else if(gameQuery.animations[animationNumber].type & $.gameQuery.ANIMATION_HORIZONTAL) {
                                $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px "+(-gameQuery.animations[animationNumber].offsety)+"px");
                            }
                        } else {
                            if(gameQuery.animations.type & $.gameQuery.ANIMATION_VERTICAL){
                                $(this).css("background-position",""+(-gameQuery.animations.offsetx-this.gameQuery.multi)+"px "+(-gameQuery.animations.offsety-gameQuery.animations.delta*gameQuery.frameTracker)+"px");
                            } else if(gameQuery.animations.type & $.gameQuery.ANIMATION_HORIZONTAL) {
                                $(this).css("background-position",""+(-gameQuery.animations.offsetx-gameQuery.animations.delta*gameQuery.frameTracker)+"px "+(-gameQuery.animations.offsety-this.gameQuery.multi)+"px");
                            }
                        }
                    });
                }
                return true;
            },

            /**
             * This function is called periodically to refresh the state of the game.
             **/
            refresh: function() {
                $.gameQuery.playground.find(".sprite").each(this.refreshSprite);
                $.gameQuery.playground.find(".tileSet").each(this.refreshTilemap);
                var deadCallback= new Array();
                for (var i = this.callbacks.length-1; i >= 0; i--){
                    if(this.callbacks[i].idleCounter == this.callbacks[i].rate-1){
                        var returnedValue = this.callbacks[i].fn();
                        if(typeof returnedValue == 'boolean'){
                            // if we have a boolean: 'true' means 'no more execution', 'false' means 'execute once more'
                            if(returnedValue){
                                deadCallback.push(i);
                            }
                        } else if(typeof returnedValue == 'number') {
                            // if we have a number it re-defines the time to the nex call
                            this.callbacks[i].rate = Math.round(returnedValue/$.gameQuery.refreshRate);
                            this.callbacks[i].idleCounter = 0;
                        }
                    }
                    this.callbacks[i].idleCounter = (this.callbacks[i].idleCounter+1)%this.callbacks[i].rate;
                }
                for(var i = deadCallback.length-1; i >= 0; i--){
                    this.callbacks.splice(deadCallback[i],1);
                }
            },

            addAnimation: function(animation) {
                if($.inArray(animation,this.animations)<0){
                    //normalize the animationRate:
                    animation.rate = Math.round(animation.rate/$.gameQuery.refreshRate);
                    if(animation.rate==0){
                        animation.rate = 1;
                    }
                    this.animations.push(animation);
                }
            },

            addSound: function(sound){
                if($.inArray(sound,this.sounds)<0){
                    this.sounds.push(sound);
                }
            },

            registerCallback: function(fn, rate){
                rate  = Math.round(rate/$.gameQuery.refreshRate);
                if(rate==0){
                    rate = 1;
                }
                this.callbacks.push({fn: fn, rate: rate, idleCounter: 0});
            }
        },

        // This is a single place to update the underlying data of sprites/groups/tiles
        update: function(descriptor, transformation) {
            // Did we really recieve a descriptor or a jQuery object instead?
            if(!$.isPlainObject(descriptor)){
                // Then we must get real descriptor
                if(descriptor.length > 0){
                    var gameQuery = descriptor[0].gameQuery;
                } else {
                    var gameQuery = descriptor.gameQuery;
                }
            } else {
                var gameQuery = descriptor;
            }
            // If we couldn't find one we return
            if(!gameQuery) return;
            if(gameQuery.tileSet === true){
                //then we have a tilemap!
                descriptor = $(descriptor);
                // find the tilemap offset relatif to the playground:
                var playgroundOffset = $.gameQuery.playground.offset();
                var tileSetOffset = descriptor.offset();
                tileSetOffset = {top: tileSetOffset.top - playgroundOffset.top, left: tileSetOffset.left - playgroundOffset.left};
                // test what kind of transformation we have and react accordingly:
                // Update the descriptor
                for(property in transformation){
                    switch(property){
                        case "left":
                            //Do we need to activate/desactive the first/last column
                            var left = parseFloat(transformation.left);
                            //Get the tileSet offset (relatif to the playground)
                            var playgroundOffset = $.gameQuery.playground.offset();
                            var tileSetOffset = descriptor.parent().offset();
                            tileSetOffset = {top: tileSetOffset.top - playgroundOffset.top, left: tileSetOffset.left + left - playgroundOffset.left};

                            //actvates the visible tiles
                            var firstColumn = Math.max(Math.min(Math.floor(-tileSetOffset.left/gameQuery.width), gameQuery.sizex),0);
                            var lastColumn = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].width-tileSetOffset.left)/gameQuery.width), gameQuery.sizex),0);

                            for(var i = gameQuery.firstRow; i < gameQuery.lastRow; i++){
                                // if old first col < new first col
                                // deactivate the newly invisible tiles
                                for(var j = gameQuery.firstColumn; j < firstColumn ; j++) {
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
                                }
                                //and activate the newly visible tiles
                                for(var j = gameQuery.lastColumn; j < lastColumn ; j++) {
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
                                }

                                // if old first col > new first col
                                // deactivate the newly invisible tiles
                                for(var j = lastColumn; j < gameQuery.lastColumn ; j++) {
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
                                }
                                //activate the newly visible tiles
                                for(var j = firstColumn; j < gameQuery.firstColumn ; j++) {
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
                                }
                            }

                            gameQuery.firstColumn = firstColumn;
                            gameQuery.lastColumn = lastColumn;
                            break;
                        case "top":
                            //Do we need to activate/desactive the first/last row
                            var top = parseFloat(transformation.top);
                            //Get the tileSet offset (relatif to the playground)
                            var playgroundOffset = $.gameQuery.playground.offset();
                            var tileSetOffset = descriptor.parent().offset();
                            tileSetOffset = {top: tileSetOffset.top + top - playgroundOffset.top, left: tileSetOffset.left - playgroundOffset.left};

                            //actvates the visible tiles
                            var firstRow = Math.max(Math.min(Math.floor(-tileSetOffset.top/gameQuery.height), gameQuery.sizey), 0);
                            var lastRow = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].height-tileSetOffset.top)/gameQuery.height), gameQuery.sizey), 0);

                            for(var j = gameQuery.firstColumn; j < gameQuery.lastColumn ; j++) {
                                 // if old first row < new first row
                                // deactivate the newly invisible tiles
                                for(var i = gameQuery.firstRow; i < firstRow; i++){
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
                                }
                                //and activate the newly visible tiles
                                for(var i = gameQuery.lastRow; i < lastRow; i++){
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
                                }

                                // if old first row < new first row
                                // deactivate the newly invisible tiles
                                for(var i = lastRow; i < gameQuery.lastRow; i++){
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).removeClass("active");
                                }
                                //and activate the newly visible tiles
                                for(var i = firstRow; i < gameQuery.firstRow; i++){
                                    $("#tile_"+descriptor.attr("id")+"_"+i+"_"+j).addClass("active");
                                }
                            }

                            gameQuery.firstRow = firstRow;
                            gameQuery.lastRow = lastRow;

                            break;
                        case "angle": //(in degree)
                            //TODO
                            break;
                        case "factor":
                            //TODO
                            break;
                    }
                }

            } else {
                var refreshBoundingCircle = $.gameQuery.playground && !$.gameQuery.playground.disableCollision;

                // Update the descriptor
                for(property in transformation){
                    switch(property){
                        case "left":
                            gameQuery.posx = parseFloat(transformation.left);
                            if(refreshBoundingCircle){
                                gameQuery.boundingCircle.x = gameQuery.posx+gameQuery.width/2;
                            }
                            break;
                        case "top":
                            gameQuery.posy = parseFloat(transformation.top);
                            if(refreshBoundingCircle){
                                gameQuery.boundingCircle.y = gameQuery.posy+gameQuery.height/2;
                            }
                            break;
                        case "width":
                            gameQuery.width = parseFloat(transformation.width);
                            break;
                        case "height":
                            gameQuery.height = parseFloat(transformation.height);
                            break;
                        case "angle": //(in degree)
                            gameQuery.angle = parseFloat(transformation.angle);
                            break;
                        case "factor":
                            gameQuery.factor = parseFloat(transformation.factor);
                            if(refreshBoundingCircle){
                                gameQuery.boundingCircle.radius = gameQuery.factor*gameQuery.boundingCircle.originalRadius;
                            }
                            break;
                    }
                }
            }
        },

        // This is a utility function that returns the radius for a geometry
        proj: function (elem, angle) {
            switch (elem.geometry){
                case $.gameQuery.GEOMETRY_RECTANGLE :
                    var b = angle*Math.PI*2/360;
                    var Rx = Math.abs(Math.cos(b)*elem.width/2*elem.factor)+Math.abs(Math.sin(b)*elem.height/2*elem.factor);
                    var Ry = Math.abs(Math.cos(b)*elem.height/2*elem.factor)+Math.abs(Math.sin(b)*elem.width/2*elem.factor);

                    return {x: Rx, y: Ry};
            }
        },

        // This is a utility function for collision of two object
        collide: function(elem1, offset1, elem2, offset2) {
            // test real collision (only for two rectangle...)
            if((elem1.geometry == $.gameQuery.GEOMETRY_RECTANGLE && elem2.geometry == $.gameQuery.GEOMETRY_RECTANGLE)){

                var dx = offset2.x + elem2.boundingCircle.x - elem1.boundingCircle.x - offset1.x;
                var dy = offset2.y + elem2.boundingCircle.y - elem1.boundingCircle.y - offset1.y;
                var a  = Math.atan(dy/dx);

                var Dx = Math.abs(Math.cos(a-elem1.angle*Math.PI*2/360)/Math.cos(a)*dx);
                var Dy = Math.abs(Math.sin(a-elem1.angle*Math.PI*2/360)/Math.sin(a)*dy);

                var R = $.gameQuery.proj(elem2, elem2.angle-elem1.angle);

                if((elem1.width/2*elem1.factor+R.x <= Dx) || (elem1.height/2*elem1.factor+R.y <= Dy)) {
                    return false;
                } else {
                    var Dx = Math.abs(Math.cos(a-elem2.angle*Math.PI*2/360)/Math.cos(a)*-dx);
                    var Dy = Math.abs(Math.sin(a-elem2.angle*Math.PI*2/360)/Math.sin(a)*-dy);

                    var R = $.gameQuery.proj(elem1, elem1.angle-elem2.angle);

                    if((elem2.width/2*elem2.factor+R.x <= Dx) || (elem2.height/2*elem2.factor+R.y <= Dy)) {
                        return false;
                    } else {
                        return true;
                    }
                }
            } else {
                return false;
            }
        }
    // This function mute (or unmute) all the sounds.
    }, muteSound: function(muted){
        for (var i = $.gameQuery.resourceManager.sounds-1 ; i >= 0; i --) {
            $.gameQuery.resourceManager.sounds[i].muted(muted);
        }
    }, playground: function() {
        return $.gameQuery.playground
    // This function define a callback that will be called upon during the
    // loading of the game's resources. The function will recieve as unique
    // parameter a number representing the progess percentage.
    }, loadCallback: function(callback){
        $.gameQuery.resourceManager.loadCallback = callback;
    }});

    $.fn.extend({
        /**
         * Define the div to use for the display the game and initailize it.
         * This could be called on any node it doesn't matter.
         * The returned node is the playground node.
         * This IS a desrtuctive call
         **/
        playground: function(options) {
            if(this.length == 1){
                if(this[0] == document){ // Old usage check
                    throw "Old playground usage, use $.playground() to retreive the playground and $('mydiv').playground(options) to set the div!";
                }
                options = $.extend({
                    height:     320,
                    width:      480,
                    refreshRate: 30,
                    position:   "absolute",
                    keyTracker: false,
                    disableCollision: false
                }, options);
                //We save the playground node and set some variable for this node:
                $.gameQuery.playground = this;
                $.gameQuery.refreshRate = options.refreshRate;
                $.gameQuery.playground[0].height = options.height;
                $.gameQuery.playground[0].width = options.width;

                // We initialize the apearance of the div
                $.gameQuery.playground.css({
                        position: options.position,
                        display:  "block",
                        overflow: "hidden",
                        height:   options.height+"px",
                        width:    options.width+"px"
                    })
                    .append("<div id='sceengraph' style='visibility: hidden'/>");

                $.gameQuery.sceengraph = $("#sceengraph");

                //Add the keyTracker to the gameQuery object:
                $.gameQuery.keyTracker = {};
                // we only enable the real tracking if the users wants it
                if(options.keyTracker){
                    $(document).keydown(function(event){
                        $.gameQuery.keyTracker[event.keyCode] = true;
                    });
                    $(document).keyup(function(event){
                        $.gameQuery.keyTracker[event.keyCode] = false;
                    });
                }
            }
            return this;
        },

        /**
        * Starts the game. The resources from the resource manager are preloaded if necesary
        * Works only for the playgroung node.
        * This is a non-desrtuctive call
        **/
        startGame: function(callback) {
            //if the element is the playground we start the game:
            $.gameQuery.startCallback = callback;
            $.gameQuery.resourceManager.preload();
            return this;
        },

        /**
        * Add a group to the sceen graph
        * works only on the sceengraph root or on another group
        * This IS a desrtuctive call and should be terminated with end() to go back one level up in the chaining
        **/
        addGroup: function(group, options) {
            options = $.extend({
                width:      32,
                height:     32,
                posx:       0,
                posy:       0,
                overflow:   "visible",
                geometry:   $.gameQuery.GEOMETRY_RECTANGLE,
                angle:          0,
                factor:         1
            }, options);

            var newGroupElement = "<div id='"+group+"' class='group' style='position: absolute; display: block; overflow: "+options.overflow+"; top: "+options.posy+"px; left: "+options.posx+"px; height: "+options.height+"px; width: "+options.width+"px;' />";
            if(this == $.gameQuery.playground){
                $.gameQuery.sceengraph.append(newGroupElement);
            } else if ((this == $.gameQuery.sceengraph)||(this.hasClass("group"))){
                this.append(newGroupElement);
            }
            var newGroup = $("#"+group);
            newGroup[0].gameQuery = options;
            newGroup[0].gameQuery.boundingCircle = {x: options.posx + options.width/2,
                                                    y: options.posy + options.height/0,
                                                    originalRadius: Math.sqrt(Math.pow(options.width,2) + Math.pow(options.height,2))/2};
            newGroup[0].gameQuery.boundingCircle.radius = newGroup[0].gameQuery.boundingCircle.originalRadius;
            newGroup[0].gameQuery.group = true;
            return this.pushStack(newGroup);
        },

        /**
        * Add a sprite to the current node.
        * Works only on the playground, the sceengraph root or a sceengraph group
        * This is a non-desrtuctive call
        **/
        addSprite: function(sprite, options) {
            options = $.extend({
                width:          32,
                height:         32,
                posx:           0,
                posy:           0,
                idleCounter:    0,
                currentFrame:   0,
                geometry:       $.gameQuery.GEOMETRY_RECTANGLE,
                angle:          0,
                factor:         1
            }, options);

            var newSpriteElem = "<div id='"+sprite+"' class='sprite' style='position: absolute; display: block; overflow: hidden; height: "+options.height+"px; width: "+options.width+"px; left: "+options.posx+"px; top: "+options.posy+"px; background-position: "+((options.animation)? -options.animation.offsetx : 0)+"px "+((options.animation)? -options.animation.offsety : 0)+"px;' />";
            if(this == $.gameQuery.playground){
                $.gameQuery.sceengraph.append(newSpriteElem);
            } else {
                this.append(newSpriteElem);
            }

            //if the game has already started we want to add the animation's image as a background now:
            if(options.animation){
                if($.gameQuery.resourceManager.running){
                    $("#"+sprite).css("background-image", "url("+options.animation.imageURL+")");
                }
                if(options.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
                    $("#"+sprite).css("background-repeat", "repeat-x");
                } else if(options.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
                    $("#"+sprite).css("background-repeat", "repeat-y");
                } else {
                    $("#"+sprite).css("background-repeat", "no-repeat");
                }
            }

            var spriteDOMObject = $("#"+sprite)[0];
            if(spriteDOMObject != undefined){
                spriteDOMObject.gameQuery = options;
                //Compute bounding Cirlce:
                spriteDOMObject.gameQuery.boundingCircle = {x: options.posx + options.width/2,
                                                            y: options.posy + options.height/2,
                                                            originalRadius: Math.sqrt(Math.pow(options.width,2) + Math.pow(options.height,2))/2};
                spriteDOMObject.gameQuery.boundingCircle.radius = spriteDOMObject.gameQuery.boundingCircle.originalRadius;
            }
            return this;
        },

        /**
        * Remove the sprite  on which it is called. This is here for backward compatibility  but it doesn't
        * do anything more than simply calling .remove()
        * This is a non-desrtuctive call.
        **/
        removeSprite: function() {
            this.remove();
            return this;
        },

        /**
        * Add a Tile Map to the selected element.
        * This is a non-destructive call.
        **/
        addTilemap: function(name, tileDescription, animationList, options){
            options = $.extend({
                width:          32,
                height:         32,
                sizex:          32,
                sizey:          32,
                posx:           0,
                posy:           0
            }, options);

            //var newSpriteElem = "<div id='"+sprite+"' style='position: absolute; display: block; overflow: hidden; height: "+options.height+"px; width: "+options.width+"px; left: "+options.posx+"px; top: "+options.posy+"px; background-position: 0px 0px;' />";

            var tileSet = $("<div class='tileSet' style='position: absolute; display: block; overflow: hidden;' />");
            tileSet.css({top: options.posy, left: options.posx, height: options.height*options.sizey, width: options.width*options.sizex}).attr("id",name);
            if(this == $.gameQuery.playground){
                $.gameQuery.sceengraph.append(tileSet);
            } else {
                this.append(tileSet);
            }

            if($.isArray(animationList)){
                var frameTracker = [];
                var idleCounter = [];
                for(var i=0; i<animationList.length; i++){
                    frameTracker[i] = 0;
                    idleCounter[i] = 0;
                }
                tileSet[0].gameQuery = options
                tileSet[0].gameQuery.frameTracker = frameTracker;
                tileSet[0].gameQuery.animations = animationList;
                tileSet[0].gameQuery.idleCounter =  idleCounter;
                tileSet[0].gameQuery.tileSet = true;
            } else {
                tileSet[0].gameQuery = options
                tileSet[0].gameQuery.frameTracker = 0;
                tileSet[0].gameQuery.animations = animationList;
                tileSet[0].gameQuery.idleCounter =  0;
                tileSet[0].gameQuery.tileSet = true;
            }

            if(typeof tileDescription == "function"){
                for(var i=0; i<options.sizey; i++){
                    for(var j=0; j<options.sizex; j++){
                        if(tileDescription(i,j) != 0){
                            if($.isArray(animationList)){
                                // for many simple animation:
                                tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
                                                      {width: options.width,
                                                       height: options.height,
                                                       posx: j*options.width,
                                                       posy: i*options.height,
                                                       animation: animationList[tileDescription(i,j)-1]});
                                var newTile = $("#tile_"+name+"_"+i+"_"+j);
                                newTile.removeClass("sprite");
                                newTile.addClass("tileType_"+(tileDescription(i,j)-1));
                                newTile[0].gameQuery.animationNumber = tileDescription(i,j)-1;
                            } else {
                                // for multi-animation:
                                tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
                                                      {width: options.width,
                                                       height: options.height,
                                                       posx: j*options.width,
                                                       posy: i*options.height,
                                                       animation: animationList});
                                var newTile = $("#tile_"+name+"_"+i+"_"+j);
                                newTile.setAnimation(tileDescription(i,j)-1);
                                newTile.removeClass("sprite");
                                newTile.addClass("tileType_"+(tileDescription(i,j)-1));
                            }
                        }
                    }
                }
            } else if(typeof tileDescription == "object") {
                for(var i=0; i<tileDescription.length; i++){
                    for(var j=0; j<tileDescription[0].length; j++){
                        if(tileDescription[i][j] != 0){
                            if($.isArray(animationList)){
                                // for many simple animation:
                                tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
                                                      {width: options.width,
                                                       height: options.height,
                                                       posx: j*options.width,
                                                       posy: i*options.height,
                                                       animation: animationList[tileDescription[i][j]-1]});
                                var newTile = $("#tile_"+name+"_"+i+"_"+j);
                                newTile.removeClass("sprite");
                                newTile.addClass("tileType_"+(tileDescription[i][j]-1));
                                newTile[0].gameQuery.animationNumber = tileDescription[i][j]-1;
                            } else {
                                // for multi-animation:
                                tileSet.addSprite("tile_"+name+"_"+i+"_"+j,
                                                      {width: options.width,
                                                       height: options.height,
                                                       posx: j*options.width,
                                                       posy: i*options.height,
                                                       animation: animationList});
                                var newTile = $("#tile_"+name+"_"+i+"_"+j);
                                newTile.setAnimation(tileDescription[i][j]-1);
                                newTile.removeClass("active");
                                newTile.addClass("tileType_"+(tileDescription[i][j]-1));
                            }
                        }
                    }
                }
            }
            //Get the tileSet offset (relatif to the playground)
            var playgroundOffset = $.gameQuery.playground.offset();
            var tileSetOffset = tileSet.offset();
            tileSetOffset = {top: tileSetOffset.top - playgroundOffset.top, left: tileSetOffset.left - playgroundOffset.left};

            //actvates the visible tiles
            var firstRow = Math.max(Math.min(Math.floor(-tileSetOffset.top/options.height), options.sizey), 0);
            var lastRow = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].height-tileSetOffset.top)/options.height), options.sizey), 0);
            var firstColumn = Math.max(Math.min(Math.floor(-tileSetOffset.left/options.width), options.sizex), 0);
            var lastColumn = Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].width-tileSetOffset.left)/options.width), options.sizex), 0);

            tileSet[0].gameQuery.firstRow = firstRow;
            tileSet[0].gameQuery.lastRow = lastRow;
            tileSet[0].gameQuery.firstColumn = firstColumn;
            tileSet[0].gameQuery.lastColumn = lastColumn;

            for(var i = firstRow; i < lastRow; i++){
                for(var j = firstColumn; j < lastColumn ; j++) {
                    $("#tile_"+name+"_"+i+"_"+j).toggleClass("active");
                }
            }
            return this.pushStack(tileSet);
        },

        /**
        * Changes the animation associated with a sprite.
        * WARNING: no check are made to ensure that the object is really a sprite
        * This is a non-desrtuctive call
        **/
        setAnimation: function(animation, callback) {
            var gameQuery = this[0].gameQuery;
            if(typeof animation == "number"){
                if(gameQuery.animation.type & $.gameQuery.ANIMATION_MULTI){
                    var distance = gameQuery.animation.distance * animation;
                    gameQuery.multi = distance;
                    if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
                       gameQuery.currentFrame = 0;
                        this.css("background-position",""+(-distance-gameQuery.animation.offsetx)+"px "+(-gameQuery.animation.offsety)+"px");
                    } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
                        gameQuery.currentFrame = 0;
                        this.css("background-position",""+(-gameQuery.animation.offsetx)+"px "+(-distance-gameQuery.animation.offsety)+"px");
                    }
                }
            } else {
                if(animation){
                    gameQuery.animation = animation;
                    gameQuery.currentFrame = 0;
                    this.css({"background-image": "url("+animation.imageURL+")", "background-position": ""+(-animation.offsetx)+"px "+(-animation.offsety)+"px"});

                    if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
                        this.css("background-repeat", "repeat-x");
                    } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
                        this.css("background-repeat", "repeat-y");
                    } else {
                        this.css("background-repeat", "no-repeat");
                    }
                } else {
                    this.css("background-image", "");
                }
            }

            if(callback != undefined){
                this[0].gameQuery.callback = callback;
            }

            return this;
        },

        /**
        * This function add the sound to the resourceManger for later use and associate it to the selected dom element(s).
        * This is a non-desrtuctive call
        **/
        addSound: function(sound, add) {
            // Does a SoundWrapper exists
            if($.gameQuery.SoundWrapper) {
                var gameQuery = this[0].gameQuery;
                // should we add to existing sounds ?
                if(add) {
                    // we do, have we some sound associated with 'this'?
                    var sounds = gameQuery.sounds;
                    if(sounds) {
                        // yes, we add it
                        sounds.push(sound);
                    } else {
                        // no, we create a new sound array
                        gameQuery.sounds = [sound];
                    }
                } else {
                    // no, we replace all sounds with this one
                    gameQuery.sounds = [sound];
                }
            }
            return this;
        },

        /**
        * This function plays the sound(s) associated with the selected dom element(s)
        * This is a non-desrtuctive call
        **/
        playSound: function() {
            $(this).each(function(){
                var gameQuery = this.gameQuery;
                if(gameQuery.sounds) {
                    for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
                        gameQuery.sounds[i].play();
                    }
                }
            });

            return this;
        },

        /**
        * This function stops the sound(s) associated with the selected dom element(s) and rewind them
        * This is a non-desrtuctive call
        **/
        stopSound: function() {
            $(this).each(function(){
                var gameQuery = this.gameQuery;
                if(gameQuery.sounds) {
                    for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
                        gameQuery.sounds[i].stop();
                    }
                }
            });
            return this;
        },

        /**
        * This function pauses the sound(s) associated with the selected dom element(s)
        * This is a non-desrtuctive call
        **/
        pauseSound: function() {
            $(this).each(function(){
                var gameQuery = this.gameQuery;
                if(gameQuery.sounds) {
                    for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
                        gameQuery.sounds[i].pause();
                    }
                }
            });
            return this;
        },

        /**
        * this function mute or unmute the selected sound or all the sounds if none is specified
        **/
        muteSound: function(muted) {
            $(this).each(function(){
                var gameQuery = this.gameQuery;
                if(gameQuery.sounds) {
                    for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
                        gameQuery.sounds[i].muted(muted);
                    }
                }
            });
        },

        /**
        * Register a callback to be trigered every "rate"
        * This is a non-desrtuctive call
        **/
        registerCallback: function(fn, rate) {
            $.gameQuery.resourceManager.registerCallback(fn, rate);
            return this;
        },

        /**
        * @DEPRECATED: use loadCallback() instead
        * Set the id of the div to use as a loading bar while the games media are loaded during the preload.
        * If a callback function is given it will be called each time the loading progression changes with
        * the precentage passed as unique argument.
        * This is a non-desrtuctive call
        **/
        setLoadBar: function(elementId, finalwidth, callback) {
            $.gameQuery.loadbar = {id: elementId, width: finalwidth, callback: callback};
            return this;
        },

        /**
         * This function retreive a list of object in collision with the subject:
         * - if 'this' is a sprite or a group, the function will retrieve the list of sprites (not groups) that touch it
         * - if 'this' is the playground, the function will return a list of all pair of collisioning elements. They are represented
         *    by a jQuery object containing a series of paire. Each paire represents two object colliding.(not yet implemented)
         * For now all abject are considered to be boxes.
         * This IS a desrtuctive call and should be terminated with end() to go back one level up in the chaining
         **/
        collision: function(filter){
            var resultList = [];

            //retrieve 'this' offset by looking at the parents
            var itsParent = this[0].parentNode, offsetX = 0, offsetY = 0;
            while (itsParent != $.gameQuery.playground[0]){
                    if(itsParent.gameQuery){
                    offsetX += itsParent.gameQuery.posx;
                    offsetY += itsParent.gameQuery.posy;
                }
                itsParent = itsParent.parentNode;
            }

            // retrieve the gameQuery object
            var gameQuery = this[0].gameQuery;

            // retrieve the playground's absolute position and size information
            var pgdGeom = {top: 0, left: 0, bottom: $.playground().height(), right: $.playground().width()};

            // Does 'this' is inside the playground ?
            if( (gameQuery.boundingCircle.y + gameQuery.boundingCircle.radius + offsetY < pgdGeom.top)    ||
                (gameQuery.boundingCircle.x + gameQuery.boundingCircle.radius + offsetX < pgdGeom.left)   ||
                (gameQuery.boundingCircle.y - gameQuery.boundingCircle.radius + offsetY > pgdGeom.bottom) ||
                (gameQuery.boundingCircle.x - gameQuery.boundingCircle.radius + offsetX > pgdGeom.right)){
                return this.pushStack(new $([]));
            }

            if(this == $.gameQuery.playground){
                //TODO Code the "all against all" collision detection and find a nice way to return a list of pairs of elements
            } else {
                // we must find all the element that touches 'this'
                var elementsToCheck = new Array();
                elementsToCheck.push($.gameQuery.sceengraph.children(filter).get());
                elementsToCheck[0].offsetX = 0;
                elementsToCheck[0].offsetY = 0;

                for(var i = 0, len = elementsToCheck.length; i < len; i++) {
                    var subLen = elementsToCheck[i].length;
                    while(subLen--){
                        var elementToCheck = elementsToCheck[i][subLen];
                        // is it a gameQuery generated element?
                        if(elementToCheck.gameQuery){
                            // we don't want to check groups
                            if(!elementToCheck.gameQuery.group && !elementToCheck.gameQuery.tileSet){
                                // does it touches the selection?
                                if(this[0]!=elementToCheck){
                                    // check bounding circle collision
                                    // 1) distance between center:
                                    var distance = Math.sqrt(Math.pow(offsetY + gameQuery.boundingCircle.y - elementsToCheck[i].offsetY - elementToCheck.gameQuery.boundingCircle.y, 2) + Math.pow(offsetX + gameQuery.boundingCircle.x - elementsToCheck[i].offsetX - elementToCheck.gameQuery.boundingCircle.x, 2));
                                    if(distance - gameQuery.boundingCircle.radius - elementToCheck.gameQuery.boundingCircle.radius <= 0){
                                        // check real collision
                                        if($.gameQuery.collide(gameQuery, {x: offsetX, y: offsetY}, elementToCheck.gameQuery, {x: elementsToCheck[i].offsetX, y: elementsToCheck[i].offsetY})) {
                                            // add to the result list if collision detected
                                            resultList.push(elementsToCheck[i][subLen]);
                                        }
                                    }
                                }
                            }
                            // Add the children nodes to the list
                            var eleChildren = $(elementToCheck).children(filter);
                            if(eleChildren.length){
                                elementsToCheck.push(eleChildren.get());
                                elementsToCheck[len].offsetX = elementToCheck.gameQuery.posx + elementsToCheck[i].offsetX;
                                elementsToCheck[len].offsetY = elementToCheck.gameQuery.posy + elementsToCheck[i].offsetY;
                                len++;
                            }
                        }
                    }
                }
                return this.pushStack($(resultList));
            }
        },

        /**
         * This is an internal function doing the combine action of rotate and scale
         * Both argument are mandatory. To get the values back use .rotate() or
         * .scale()
         **/
        transform: function(angle, factor) {
            var gameQuery = this[0].gameQuery;
            // Mark transformed and compute bounding box
            $.gameQuery.update(gameQuery,{angle: angle, factor: factor});

            if(this.css("MozTransform")) {
                // For firefox from 3.5
                var transform = "rotate("+angle+"deg) scale("+factor+")";
                this.css("MozTransform",transform);
            } else if(this.css("WebkitTransform")!==null && this.css("WebkitTransform")!==undefined) {
                // For safari from 3.1 (and chrome)
                var transform = "rotate("+angle+"deg) scale("+factor+")";
                this.css("WebkitTransform",transform);
            } else if(this.css("filter")!==undefined){
                var angle_rad = Math.PI * 2 / 360 * angle;
                // For ie from 5.5
                var cos = Math.cos(angle_rad) * factor;
                var sin = Math.sin(angle_rad) * factor;
                var previousWidth = this.width();
                var previousHeight = this.height();
                this.css("filter","progid:DXImageTransform.Microsoft.Matrix(M11="+cos+",M12="+(-sin)+",M21="+sin+",M22="+cos+",SizingMethod='auto expand',FilterType='nearest neighbor')");
                var newWidth = this.width();
                var newHeight = this.height();
                this.css("left", ""+(gameQuery.posx-(newWidth-previousWidth)/2)+"px");
                this.css("top", ""+(gameQuery.posy-(newHeight-previousHeight)/2)+"px");
            }
            return this;
        },

        /**
         * This function rotates the selected element(s) clock-wise. The argument is a degree.
         **/
        rotate: function(angle){
            var gameQuery = this[0].gameQuery;

            if(angle !== undefined) {
                return this.transform(angle % 360, this.scale());
            } else {
                var ang = gameQuery.angle;
                return ang ? ang : 0;
            }
        },

        /**
         * This function change the scale of the selected element(s). The passed argument is a ratio:
         * 1.0 = original size
         * 0.5 = half the original size
         * 2.0 = twice the original size
         **/
        scale: function(factor){
            var gameQuery = this[0].gameQuery;

            if(factor !== undefined) {
                return this.transform(this.rotate(), factor);
            } else {
                var fac = gameQuery.factor;
                return fac ? fac : 1;
            }
        }
    });

    // This is an hijack to keep track of the change in the sprites, and group positions and size
    var oldCssFunction = $.fn.css;
    $.fn.css = function(key, value) {
        // This is the list of parameters that we watch for
        var sensibleKey = {left: true, top: true, height: true, width: true};

        // This is the function that takes care of warning $.gameQuery.update when a watched parameter
        // changes. If a function was passed instead of a fix value we call it first to compute the value.
        var testfunction = function (index, oldValue){
            var obj = {};
            var result;

            if(typeof value == "function"){
                result = value.apply(this,[index, oldValue]);
            } else {
                result = value;
            }

            obj[key]= result;
            $.gameQuery.update(this, obj);

            return result;
        };

        // This check for the kind of css() call
        if(typeof key == "object") {
            // Have we an object literal? Then we deserialize the call to the watched parameters
            for(sensible in sensibleKey){
                if(key[sensible]){
                    arguments.callee.apply(this,[sensible, key[sensible]]);
                    delete key[sensible];
                }
            }
            return oldCssFunction.apply(this,[key, value]);
        } else {
            // Otherwise we just interscept the call to watched parameters
            if(value && sensibleKey[key]){
                return oldCssFunction.apply(this,[key, testfunction]);
            }
            // or just call the standard css() function
            return oldCssFunction.apply(this,[key, value]);
        }
    };

})(jQuery);


text:
require "kaminari/data_mapper/version"
require 'kaminari'
require 'data_mapper'

module Kaminari
  module DataMapper
  end
end

require 'dm-aggregates'
require 'kaminari/data_mapper/data_mapper_extension'
::DataMapper::Collection.send :include, Kaminari::DataMapper::DataMapperExtension::Collection
::DataMapper::Model.append_extensions Kaminari::DataMapper::DataMapperExtension::Model
# ::DataMapper::Model.send :extend, Kaminari::DataMapper::DataMapperExtension::Model

redpajama_set_name: RedPajamaGithub


text:
import { APP_MENU_TITLE_CHANGE,
    APP_MENU_DRAWER_TOGGLE,
    APP_DIALOG_OPEN,
    APP_DIALOG_CLOSE,
    APP_SNACKBAR_OPEN,
    APP_SNACKBAR_CLOSE
} from "../constants/actions";
import asapReducers from "../asapapp/reducers";
import packageReducers from "../packageapp/reducers";
import filterReducers from "../filter-app/filter-reducers";

const initialAppState = {
    appMenuTitle: "RxApps",
    appMenuDrawerOpen: false,
    appDialog: {
        open: false,
        title: "RxApps",
        message: "RxApps"
    },
    appSnackbar: {
        open: false,
        message: "RxApps"
    },
    appUser: "demo",
    appURL: "demo"
};

const appReducers = function(state = initialAppState, action) {
    switch(action.type) {
        case APP_MENU_TITLE_CHANGE:
            return Object.assign({}, state, {appMenuTitle: action.title});

        case APP_MENU_DRAWER_TOGGLE:
            return Object.assign({}, state, {appMenuDrawerOpen: !state.appMenuDrawerOpen});

        case APP_DIALOG_OPEN:
            return Object.assign({}, state, {appDialog: {open: true, message: action.message}});

        case APP_DIALOG_CLOSE:
            return Object.assign({}, state, {appDialog: {open: false, title: "RxApps", message: "RxApps"}});

        case APP_SNACKBAR_OPEN:
            return Object.assign({}, state, {appSnackbar: {open: true, message: action.message}});

        case APP_SNACKBAR_CLOSE:
            return Object.assign({}, state, {appSnackbar: {open: false, message: "RxApps"}});
    }
    return state;
};

const reducers = Object.assign({}, {app: appReducers}, {package: packageReducers, filter: filterReducers});

export default reducers;


text:
using bv.common.Core;

namespace eidss.model.Reports.Common
{
    public class ItemWrapper
    {
        private readonly string m_NativeName;
        private readonly int m_Number;

        public ItemWrapper(string nativeName, int number)
        {
            Utils.CheckNotNullOrEmpty(nativeName, "nativeName");
            m_NativeName = nativeName;
            m_Number = number;
        }

        public string NativeName
        {
            get { return m_NativeName; }
        }

        public int Number
        {
            get { return m_Number; }
        }

        public override string ToString()
        {
            return NativeName;
        }
    }
}


text:
title:  La oración de Nehemías
date:   30/09/2019
---

### inTerpreta

Aunque Nehemías se hallaba lejos y el avance del proyecto era desalentador, él no iba a aceptar la mediocridad. Su determinación y su deseo de que Dios fuera finalmente glorificado, lo llevaron a arrodillarse. El secreto del liderazgo y del valor de Nehemías radicaba en su dependencia de la oración.

La oración del capítulo 1 de Nehemías tiene cuatro componentes.

**Adoración**

En el versículo 5 vemos cómo Nehemías se dirige a Dios mencionando algunos de sus atributos: «Señor Dios del cielo», «Dios grande y terrible», «que mantienes firme tu alianza y tu fidelidad». Estos títulos contextualizan la grandeza de Dios con relación a nosotros así como la pequeñez de nuestros propios problemas.

A lo largo de la oración, los pronombres de segunda persona «tú, tu, ti», eclipsan los que se refieren a la primera persona «yo», «nosotros» y «mi». La plegaria es teocéntrica (centrada en Dios), no antropocéntrica (centrada en el ser humano). De hecho, la única ocasión en que Nehemías emplea la primera persona es para confesar pecados.

**Confesión**

El pecado representa una barrera para Dios (ver Isa. 59: 1-2). Por eso, en los versículos 6 a 9 vemos cómo Nehemías se asegura de que sus pecados y los de Israel sean perdonados. Aunque Jesús aún no iba a llegar sino hasta siglos después, la fe de Nehemías se apoya en esa previsión de futuro.

Tal como vemos en la oración de Nehemías, una confesión puede ser tanto general como específica. Curiosamente, él se coloca en la categoría de pecador contra Dios. Tal vez estaba confesando sus pecados de indiferencia, violación personal de los mandamientos de Dios, o quizá de ignorar el llamado a regresar a Jerusalén mientras permanecía en la corte de Susa. En cualquier caso, Nehemías invoca motivos puros y se identifica personalmente con el pecado corporativo de Israel. Esa actitud de un líder consagrado que asume la deuda espiritual de los suyos se observa también en la vida de otros grandes personajes de la Biblia.

**Promesas**

Nehemías repite a Dios lo que el Señor dijo en el pasado (vers. 8), creyendo que Dios sería fiel a su Palabra. Jesús hizo lo mismo, citando el Antiguo Testamento durante las tentaciones que sufrió. Confiando en la fidelidad divina, todo creyente puede ser directo con Dios respecto a lo que él mismo ha prometido.

En los versículos 8 y 9, Nehemías resume las bendiciones y maldiciones de las promesas que se encuentran en Deuteronomio 30 y Levítico 26. Aunque puedan parecernos incompatibles con una sensibilidad moderna, está claro que la obediencia es el fundamento de las bendiciones de Dios. Más tarde, Pablo enfatiza que es la obediencia de Cristo la que se convirtió en la base de las promesas de bendición de Dios y que «en él» podemos participar de esas mismas bendiciones mientras nos beneficiamos de la eliminación de dichas maldiciones. Ya sea contemplando el futuro como lo hizo Nehemías o mirando al pasado, la cuestión es mirar a Cristo como el cumplimiento de la promesa divina.

**Visión**

A través de la oración, se restablecen las prioridades y se fija un objetivo en el corazón de Nehemías. Él se da cuenta de que Dios lo ha enviado al palacio para cumplir un propósito. A través de la oración, Nehemías entendió su papel como copero del rey y adquirió una visión para satisfacer esa necesidad que comenzó a formularse en su mente.

Los medos y los persas tenían un concepto muy elevado de sus leyes: una vez que se aprobaba una ley, era imposible cambiarla (ver Dan. 6: 15). Con relación a las leyes que impidieron la restauración de Jerusalén (Esd. 4: 17-24), la reconstrucción parecía imposible. Sin embargo, en lugar de centrarse en las imposibilidades, Nehemías buscó la respuesta de Dios. Nehemías oró durante muchos días (ver Neh. 1: 4) hasta que algo sucedió. Pasaron cuatro meses antes de que recibiera una respuesta (desde diciembre/enero hasta abril/mayo, como veremos en el capítulo 2: 1).

Después que hayas repasado el texto que has copiado y resaltado,

`¿Qué te parece lo que has marcado o subrayado y relacionado?`

`¿Qué preguntas te surgen después de haber estudiado dicho pasaje?`

`¿Cuáles son las partes del pasaje que te parecen más difíciles?`

`¿Qué otros principios y conclusiones puedes identificar en este texto bíblico?`

`¿Cuál de los cuatro componentes de la oración mencionados necesitas más en tu relación con Dios?`


text:
/* Usage: This is TCP client provider that can connect to a tcp server and pass data from there to the provider pipeline.
 * It takes the options "host" and "port".
 * Example:

 {
   "type": "providers/tcp",
   "options": {
     "host": 'localhost',
     "port": 10110,
   }
 },

 */

const net = require('net')
const Transform = require('stream').Transform
const isArray = require('lodash').isArray

const debug = require('debug')('signalk-server:streams:tcp')
const debugData = require('debug')('signalk-server:streams:tcp-data')

function TcpStream (options) {
  Transform.call(this, options)
  this.options = options
  this.noDataReceivedTimeout = Number.parseInt((this.options.noDataReceivedTimeout + '').trim()) * 1000
}

require('util').inherits(TcpStream, Transform)

TcpStream.prototype.pipe = function (pipeTo) {
  if ( this.options.outEvent ) {
    const that = this
    that.options.app.on(that.options.outEvent, function (d) {
      if ( that.tcpStream ) {
        debug('sending %s', d)
        that.tcpStream.write(d)
      }
    })
  }

  const stdOutEvent = this.options.toStdout
  if (stdOutEvent) {
    const that = this; //semicolon required here
    (isArray(stdOutEvent) ? stdOutEvent : [stdOutEvent]).forEach(stdEvent => {
      that.options.app.on(stdEvent, function (d) {
        if (that.tcpStream) {
          that.tcpStream.write(d + '\r\n')
          debug('event %s sending %s', stdEvent, d)
        }
      })
    })
  }

  const re = require('reconnect-core')(function () {
    return net.connect.apply(null, arguments)
  })({ maxDelay: 5 * 1000 }, tcpStream => {
    if (!isNaN(this.noDataReceivedTimeout)) {
      tcpStream.setTimeout(this.noDataReceivedTimeout)
      debug(
        `Setting socket idle timeout ${this.options.host}:${this.options.port} ${this.noDataReceivedTimeout}`
      )
      tcpStream.on('timeout', () => {
        debug(
          `Idle timeout, closing socket ${this.options.host}:${this.options.port}`
        )
        tcpStream.end()
      })
    }
    tcpStream.on('data', data => {
      if (debugData.enabled) {
        debugData(data.toString())
      }
      this.write(data)
    })
  })
    .on('connect', con => {
      this.tcpStream = con
      const msg = `Connected to ${this.options.host} ${this.options.port}`
      this.options.app.setProviderStatus(this.options.providerId, msg)
      debug(msg)
    })
    .on('reconnect', (n, delay) => {
      const msg = `Reconnect ${this.options.host} ${
        this.options.port
      } retry ${n} delay ${delay}`
      this.options.app.setProviderError(this.options.providerId, msg)
      debug(msg)
    })
    .on('disconnect', err => {
      delete this.tcpStream
      debug(`Disconnected ${this.options.host} ${this.options.port}`)
    })
    .on('error', err => {
      this.options.app.setProviderError(this.options.providerId, err.message)
      console.error('TcpProvider:' + err.message)
    })
    .connect(this.options)

  Transform.prototype.pipe.call(this, pipeTo)
}

TcpStream.prototype._transform = function (data, encoding, callback) {
  callback(null, data)
}

module.exports = TcpStream


text:
import { expect } from 'chai';
import sinon from 'sinon';

import { expenseStatus } from '../../../server/constants';
import * as transferwiseController from '../../../server/controllers/transferwise';
import { idEncode, IDENTIFIER_TYPES } from '../../../server/graphql/v2/identifiers';
import { PayoutMethodTypes } from '../../../server/models/PayoutMethod';
import transferwise from '../../../server/paymentProviders/transferwise';
import {
  fakeCollective,
  fakeConnectedAccount,
  fakeExpense,
  fakePayoutMethod,
  fakeUser,
} from '../../test-helpers/fake-data';

describe('server/controllers/transferwise', () => {
  const sandbox = sinon.createSandbox();

  after(sandbox.restore);

  let remoteUser, expense, host, req, res;
  let fundExpensesBatchGroup;
  beforeEach(async () => {
    sandbox.restore();
    remoteUser = await fakeUser();
    host = await fakeCollective({ isHostAccount: true, admin: remoteUser.collective });
    await remoteUser.populateRoles();
    const collective = await fakeCollective({ isHostAccount: false, HostCollectiveId: host.id });
    const payoutMethod = await fakePayoutMethod({
      type: PayoutMethodTypes.BANK_ACCOUNT,
      data: {
        accountHolderName: 'Leo Kewitz',
        currency: 'EUR',
        type: 'iban',
        legalType: 'PRIVATE',
        details: {
          IBAN: 'DE89370400440532013000',
        },
      },
    });
    await fakeConnectedAccount({
      CollectiveId: host.id,
      service: 'transferwise',
      token: 'fake-token',
      data: {
        type: 'business',
        id: 0,
        details: {
          companyType: 'NON_PROFIT_CORPORATION',
        },
        blockedCurrencies: ['BTC'],
      },
    });
    expense = await fakeExpense({
      payoutMethod: 'transferwise',
      status: expenseStatus.SCHEDULED_FOR_PAYMENT,
      amount: 10000,
      CollectiveId: collective.id,
      currency: 'USD',
      PayoutMethodId: payoutMethod.id,
      category: 'Engineering',
      type: 'INVOICE',
      description: 'January Invoice',
    });
    req = {
      body: {
        hostId: idEncode(host.id, IDENTIFIER_TYPES.ACCOUNT),
        expenseIds: [idEncode(expense.id, IDENTIFIER_TYPES.EXPENSE)],
      },
      remoteUser,
      headers: {},
    };
    res = {
      sendStatus: sandbox.stub(),
    };
    res.send = sandbox.stub().returns(res);
    res.status = sandbox.stub().returns(res);
    res.end = sandbox.stub().returns(res);
    res.setHeader = sandbox.stub().returns(res);

    sandbox.stub(transferwise, 'getTemporaryQuote').resolves({
      id: 1234,
      sourceCurrency: 'USD',
      targetCurrency: 'EUR',
      sourceAmount: 101.14,
      targetAmount: 90.44,
      rate: 0.9044,
      payOut: 'BANK_TRANSFER',
      paymentOptions: [
        {
          formattedEstimatedDelivery: 'by March 18th',
          estimatedDeliveryDelays: [],
          allowedProfileTypes: ['PERSONAL', 'BUSINESS'],
          payInProduct: 'BALANCE',
          feePercentage: 0.0038,
          estimatedDelivery: '2021-03-18T12:45:00Z',
          fee: { transferwise: 3.79, payIn: 0, discount: 0, total: 3.79, priceSetId: 134, partner: 0 },
          payIn: 'BALANCE',
          sourceAmount: 101.14,
          targetAmount: 90.44,
          sourceCurrency: 'USD',
          targetCurrency: 'EUR',
          payOut: 'BANK_TRANSFER',
          disabled: false,
        },
      ],
    });
    fundExpensesBatchGroup = sandbox.stub(transferwise, 'fundExpensesBatchGroup').resolves();
    sandbox.stub(transferwise, 'createExpensesBatchGroup').resolves();
  });

  it('should throw if remote user is not a host admin', async () => {
    const otherUser = await fakeUser();
    await transferwiseController.payBatch({ ...req, remoteUser: otherUser }, res as any);

    expect(res.status.called).to.be.true;
    expect(res.status.firstCall.firstArg).to.equal(401);
    expect(res.send.firstCall.firstArg).to.equal('Error: User must be admin of host collective');
  });

  it('should throw if an expense can not be found', async () => {
    await transferwiseController.payBatch(
      { ...req, body: { hostId: req.body.hostId, expenseIds: [idEncode(11223, IDENTIFIER_TYPES.EXPENSE)] } },
      res as any,
    );

    expect(res.status.called).to.be.true;
    expect(res.status.firstCall.firstArg).to.equal(404);
    expect(res.send.firstCall.firstArg).to.equal('Error: Could not find every expense requested');
  });

  it('should throw if an expense is not scheduled for payment', async () => {
    await expense.update({ status: expenseStatus.PENDING });
    await transferwiseController.payBatch(req, res);

    expect(res.status.called).to.be.true;
    expect(res.status.firstCall.firstArg).to.equal(500);
    expect(res.send.firstCall.firstArg).to.equal('Error: Expense must be scheduled for payment');
  });

  it("should throw if an expense does not match its host's currency", async () => {
    await expense.update({ currency: 'CNY' });
    await transferwiseController.payBatch(req, res);

    expect(res.status.called).to.be.true;
    expect(res.status.firstCall.firstArg).to.equal(500);
    expect(res.send.firstCall.firstArg).to.equal(
      'Error: Can not batch an expense with a currency different from its host currency',
    );
  });

  it('should throw if an expense belongs to a collective from a different host', async () => {
    const collective = await fakeCollective({ isHostAccount: false });
    const otherExpense = await fakeExpense({
      payoutMethod: 'transferwise',
      status: expenseStatus.SCHEDULED_FOR_PAYMENT,
      amount: 10000,
      CollectiveId: collective.id,
      currency: 'USD',
      type: 'INVOICE',
    });
    req.body.expenseIds = [
      idEncode(expense.id, IDENTIFIER_TYPES.EXPENSE),
      idEncode(otherExpense.id, IDENTIFIER_TYPES.EXPENSE),
    ];

    await transferwiseController.payBatch(req, res);

    expect(res.status.called).to.be.true;
    expect(res.status.firstCall.firstArg).to.equal(400);
    expect(res.send.firstCall.firstArg).to.equal('Error: Expenses must belong to the requested host');
  });

  it('should proxy OTT headers from TransferWise', async () => {
    fundExpensesBatchGroup.resolves({ status: 403, headers: { 'x-2fa-approval': 'hash' } });

    await transferwiseController.payBatch(req, res);

    expect(res.setHeader.called).to.be.true;
    expect(res.sendStatus.called).to.be.true;
    expect(res.setHeader.firstCall).to.have.nested.property('args[0]', 'x-2fa-approval');
    expect(res.setHeader.firstCall).to.have.nested.property('args[1]', 'hash');
    expect(res.sendStatus.firstCall.firstArg).to.equal(403);
  });

  it('should create transactions for paid expenses when retrying with OTT header', async () => {
    req.headers['x-2fa-approval'] = 'hash';
    // Simulate paid expenses because we stub fundExpensesBatchGroup
    await expense.update({ data: { ...expense.data, transfer: { id: 1234 } } });
    await transferwiseController.payBatch(req, res);

    await expense.reload();
    const transactions = await expense.getTransactions();
    expect(transactions).to.be.an('array').with.length(2);
    expect(expense).to.have.property('status', expenseStatus.PROCESSING);
  });
});