<commit_before>GAME.YACOPU = (function() {
    'use strict';

    /*
     * Global variables and constants
     */
    var image;

    // animation loops
    var animations = {
        "still": [
            {
                "frame": 0,
                "duration": -1
            }
        ],
        "ascending": [
            {
                "frame": 1,
                "duration": 6
            },
            {
                "frame": 2,
                "duration": 6
            },
            {
                "frame": 3,
                "duration": 6
            },
            {
                "frame": 4,
                "duration": 6
            }
        ],
        "descending": [
            {
                "frame": 3,
                "duration": -1
            }
        ],
        "sliding": [
            {
                "frame": 6,
                "duration": -1
            }
        ]
    };

    /*
     * public constructor(x, y)
     *
     *  sets initial variables for yacopu
     *
     */
    var yacopu = function(x, y) {
        this.x = x || 64;
        this.y = y || 288;
        this.alive = true;
        this.flying = false;
        this.crash = false;
        this.goal = false;

        this.onGround = 0;
        this.lastOnGround = 0;
        this.thisFrameOnGround = true;

        this.level = null;

        this.speedX = 0;
        this.speedY = 0;

        this.maxSpeed = 0;
        this.bonks = 0;

        this.animation = {
            name: "",
            step: 0,
            totalSteps: 0,
            left: 0,
            frame: 0
        };

        this.setAnimation("still");

        // Preload image if needed
        if (image === undefined) {
            image = new Image();
            image.src = "assets/yacopu.png";
        }

    };

    /*
     * public void .render(context, scrollX)
     *
     *  draws Yacopu on the provided canvas context, shifted according to the scroll x value
     *
     */
    yacopu.prototype.render = function (context, scrollX) {

        /* display:
         *
         *  to properly "simulate" 2x effect, sprites coords should be rounded to the nearest even number
         *
         *  speaking numbers, 2 canvas pixels = 16 ingame subpixels (sub-units)
         *  ...so 1 canvas pixel = 8 ingame subpixels - this will be reflected in the update method
         *
         */

        // Quit inmediately if image has not been loaded
        if (!image.complete) return null;

        // Calculate coords to draw image
        var thisx = 2 * Math.round((this.x - scrollX) / 2);
        var thisy = 2 * Math.round((this.y) / 2) + 2;

        // Draw yacopu
        var animPos = this.animation.frame * 32;
        context.drawImage(image, animPos, 0, 32, 32, thisx, thisy, 32, 32);

        // debug
        context.font = "12px Arial";
        context.fillStyle = "#543210";
        context.fillText("speed: " + this.speedX.toString() + ", " + this.speedY.toString(), 0, 16);
        context.fillText("position: " + this.x.toString() + ", " + this.y.toString(), 0, 32);
        context.fillText("onGround: " + this.lastOnGround.toString(), 0, 192);

        // speed
        if (this.speedX > 0) {
            context.fillStyle = "#A03010";
            context.fillRect(0, 352, Math.floor(this.speedX * 8), 359);
        }

    };

    /*
     * public void .update(ticks)
     *
     *  updates yacopu's speed and position on every frame, and handles level interaction
     *
     */
    yacopu.prototype.update = function (game) {

        // get ticks
        var ticks = game.getTicks();

        // Determine relevant surroundings (tiles below and ahead)
        var tileUnder = this.level.tileAt(this, 16, 32);
        var tileAbove = this.level.tileAt(this, 16, 0);
        var tileAhead = this.level.tileAt(this, 32, 16);

        // Horizontal deacceleration every 16 frames
        if ((ticks % 16) === 0) {
            if (this.speedX > 0) this.speedX--;
            if (this.speedX < 0) this.speedX++;
        }

        // Gravity
        if (this.speedY < 24) this.speedY++;

        // if standing on ground, cancel Y acceleration if positive
        if (tileUnder.solid) {
            // if going down
            if (this.speedY > 0) {

                // determine whether to bounce or fullstop
                if (tileUnder.bounce) {
                    this.speedY = -this.speedY * tileUnder.bounce;
                } else {
                    this.speedY = 0;
                }
            }

            // deaccelerate after 2 frames on ground unless floor is slippery
            if (this.speedX > 0 && !tileUnder.slippery && (this.onGround >= 2)) this.speedX--;

            // "snap to grid"
            this.y = 32 * parseInt(this.y / 32);
            this.onGround++;
        } else {
            // reset onground counter
            this.onGround = 0;
        }

        // detect "special" ground (slopes)
        if (tileUnder.slope) {
            // calculate position within the tile
            var xWithinTile = Math.floor(this.x + 16) % 32;
            var yWithinTile = Math.floor(this.y + 32) % 32;
            // positive acceleration (slope descending forward)
            if (tileUnder.slope === 1) {
                // only consider slope if we're close enough to the actual diagonal
                // (lets avoid snapping the player to the slope just for being within its tile)
                if ((yWithinTile - xWithinTile) >= -16) {

                    // keep "snapped to slope" unless we're flapping away (y speed negative)
                    if (this.speedY >= 0)
                        this.y = 32 * parseInt(this.y / 32) + xWithinTile;

                    // accelerate fast to 24
                    if (this.speedX < 24) {
                        this.speedX++;
                    } else {
                        // then slow down acceleration (every other frame)
                        if (ticks % 2) this.speedX++;
                    }
                }
            // negative acceleration (slope descending backwards)
            }
        };

        // If hitting an obstacle with head, cancel upwards velocity and "snap to grid"
        if (tileAbove.solid) {
            // determine whether to bounce or fullstop
            if (tileAbove.bounce) {
                this.speedY = -this.speedY * tileAbove.bounce;
            } else {
                this.speedY = 0;
            }
            this.y = 32 * Math.round((this.y / 32));
        };

        // If hitting an obstacle face first, stop fully and "snap to grid"
        if (tileAhead.solid) {
            // if we were going too fast, count this as a "bonk"
            if (this.speedX >= 16) {
                this.bonks++;
                console.log("bonk!");
            }

            // determine whether to bounce or fullstop
            if (tileAhead.bounce) {
                this.speedX = -this.speedX * tileAhead.bounce;
            } else {
                this.speedX = 0;
            }

            this.x = 32 * parseInt(this.x / 32);
        };

        // Vertical movement if flying and not on ground (simulates holding right)
        if (this.flying && this.speedX < 24 && !(tileUnder.solid || tileUnder.slope)) this.speedX++;

        // Actually move based on speed
        this.x += (this.speedX / 8);
        this.y += (this.speedY / 8);

        // record max speed
        if (this.speedX > this.maxSpeed) this.maxSpeed = this.speedX;

        // Check if goal has been reached
        if (!this.goal) {
            if (this.x >= (this.level.goal * 32)) {
                console.log("GOAL! " + (this.x - (this.level.goal * 32)).toString());
                console.log("max speed: " + this.maxSpeed.toString());
                console.log("bonks: " + this.bonks.toString());
                this.goal = true;
            };
        };

        // Determine proper animation
        if (tileUnder.solid || tileUnder.slope) {
            // If standing on something...
            // Set animation depending on xspeed
            if (this.speedX > 0) {
                this.setAnimation("sliding");
            } else {
                this.setAnimation("still");
            }
        } else {
            // If on midair
            // Set animation depending on yspeed
            if (this.speedY > 0) {
                this.setAnimation("descending");
            } else {
                this.setAnimation("ascending");
            }
        }

        // Update animation
        updateAnimation(this.animation);

        // store onground status to be used by "flop"
        this.thisFrameOnGround = (tileUnder.solid || tileUnder.slope);

    };

    /*
     * public void .flap()
     *
     *  activates a "flap", which is yacopu gaining upwards velocity
     *
     */
    yacopu.prototype.flap = function (game) {

        // If the goal has been reached already, ignore
        if (this.goal) return null;

        // If standing on ground, give uncapped X acceleration
        if (this.thisFrameOnGround) {
            this.speedX += 6;
            this.speedY = 0;
            this.lastOnGround = this.onGround;
        };

        // Iniciate flight
        if (!this.flying) this.flying = true;

        // Upwards velocity
        if (this.speedY >= -24) this.speedY -= 16;

    };

    /*
     * public void .setAnimation(animId)
     *
     *  initializes a new animation
     *
     */
    yacopu.prototype.setAnimation = function (animId) {

        // If trying to set to already active animation, ignore
        if (this.animation.name === animId) return null;

        // Set animation variables, to step 0
        this.animation.name = animId;
        this.animation.step = 0;
        this.animation.totalSteps = animations[animId].length;
        this.animation.left = animations[animId][0].duration;
        this.animation.frame = animations[animId][0].frame;
    };

    /*
     * private void updateAnimation(anim)
     *
     *  advances animation by one frame
     *
     */
    function updateAnimation (anim) {

        // Time left being negative means no change
        if (anim.left < 0) return null;

        // else decrease by 1
        anim.left--;

        // If it reaches 0, advance one step of the animation cycle
        if (anim.left === 0) {
            // Increase step by 1
            anim.step++;

            // If step exceedes number, cycle back to 0
            if (anim.step === anim.totalSteps) anim.step = 0;

            // Set new timeleft and frame values
            anim.left = animations[anim.name][anim.step].duration;
            anim.frame = animations[anim.name][anim.step].frame;
        };

    };

    // Return object to global namespace
    return yacopu;

}());<commit_msg>Prevented player from going backwards offscreen when on slippery surfaces<commit_after>GAME.YACOPU = (function() {
    'use strict';

    /*
     * Global variables and constants
     */
    var image;

    // animation loops
    var animations = {
        "still": [
            {
                "frame": 0,
                "duration": -1
            }
        ],
        "ascending": [
            {
                "frame": 1,
                "duration": 6
            },
            {
                "frame": 2,
                "duration": 6
            },
            {
                "frame": 3,
                "duration": 6
            },
            {
                "frame": 4,
                "duration": 6
            }
        ],
        "descending": [
            {
                "frame": 3,
                "duration": -1
            }
        ],
        "sliding": [
            {
                "frame": 6,
                "duration": -1
            }
        ]
    };

    /*
     * public constructor(x, y)
     *
     *  sets initial variables for yacopu
     *
     */
    var yacopu = function(x, y) {
        this.x = x || 64;
        this.y = y || 288;
        this.alive = true;
        this.flying = false;
        this.crash = false;
        this.goal = false;

        this.onGround = 0;
        this.lastOnGround = 0;
        this.thisFrameOnGround = true;

        this.level = null;

        this.speedX = 0;
        this.speedY = 0;

        this.maxSpeed = 0;
        this.bonks = 0;

        this.animation = {
            name: "",
            step: 0,
            totalSteps: 0,
            left: 0,
            frame: 0
        };

        this.setAnimation("still");

        // Preload image if needed
        if (image === undefined) {
            image = new Image();
            image.src = "assets/yacopu.png";
        }

        return this;

    };

    /*
     * public void .render(context, scrollX)
     *
     *  draws Yacopu on the provided canvas context, shifted according to the scroll x value
     *
     */
    yacopu.prototype.render = function (context, scrollX) {

        /* display:
         *
         *  to properly "simulate" 2x effect, sprites coords should be rounded to the nearest even number
         *
         *  speaking numbers, 2 canvas pixels = 16 ingame subpixels (sub-units)
         *  ...so 1 canvas pixel = 8 ingame subpixels - this will be reflected in the update method
         *
         */

        // Quit inmediately if image has not been loaded
        if (!image.complete) return null;

        // Calculate coords to draw image
        var thisx = 2 * Math.round((this.x - scrollX) / 2);
        var thisy = 2 * Math.round((this.y) / 2) + 2;

        // Draw yacopu
        var animPos = this.animation.frame * 32;
        context.drawImage(image, animPos, 0, 32, 32, thisx, thisy, 32, 32);

        // debug
        context.font = "12px Arial";
        context.fillStyle = "#543210";
        context.fillText("speed: " + this.speedX.toString() + ", " + this.speedY.toString(), 0, 16);
        context.fillText("position: " + this.x.toString() + ", " + this.y.toString(), 0, 32);
        context.fillText("onGround: " + this.lastOnGround.toString(), 0, 192);

        // speed
        if (this.speedX > 0) {
            context.fillStyle = "#A03010";
            context.fillRect(0, 352, Math.floor(this.speedX * 8), 359);
        }

    };

    /*
     * public void .update(ticks)
     *
     *  updates yacopu's speed and position on every frame, and handles level interaction
     *
     */
    yacopu.prototype.update = function (game) {

        // get ticks
        var ticks = game.getTicks();

        // Determine relevant surroundings (tiles below and ahead)
        var tileUnder = this.level.tileAt(this, 16, 32);
        var tileAbove = this.level.tileAt(this, 16, 0);
        var tileAhead = this.level.tileAt(this, 32, 16);

        // Horizontal deacceleration every 16 frames
        if ((ticks % 16) === 0) {
            if (this.speedX > 0) this.speedX--;
            if (this.speedX < 0) this.speedX++;
        }

        // Gravity
        if (this.speedY < 24) this.speedY++;

        // if standing on ground, cancel Y acceleration if positive
        if (tileUnder.solid) {
            // if going down
            if (this.speedY > 0) {

                // determine whether to bounce or fullstop
                if (tileUnder.bounce) {
                    this.speedY = -this.speedY * tileUnder.bounce;
                } else {
                    this.speedY = 0;
                }
            }

            // deaccelerate after 2 frames on ground unless floor is slippery
            if (this.speedX > 0 && !tileUnder.slippery && (this.onGround >= 2)) this.speedX--;
            // if going backwards, deaccelerate no matter what
            if (this.speedX < 0) this.speedX++;

            // "snap to grid"
            this.y = 32 * parseInt(this.y / 32);
            // increase onground counter
            this.onGround++;

        } else {
            // reset onground counter
            this.onGround = 0;
        }

        // detect "special" ground (slopes)
        if (tileUnder.slope) {
            // calculate position within the tile
            var xWithinTile = Math.floor(this.x + 16) % 32;
            var yWithinTile = Math.floor(this.y + 32) % 32;
            // positive acceleration (slope descending forward)
            if (tileUnder.slope === 1) {
                // only consider slope if we're close enough to the actual diagonal
                // (lets avoid snapping the player to the slope just for being within its tile)
                if ((yWithinTile - xWithinTile) >= -16) {

                    // keep "snapped to slope" unless we're flapping away (y speed negative)
                    if (this.speedY >= 0)
                        this.y = 32 * parseInt(this.y / 32) + xWithinTile;

                    // accelerate fast to 24
                    //if (this.speedX < 24) {
                        this.speedX++;
                    //} else {
                        // then slow down acceleration (every other frame)
                    //    if (ticks % 2) this.speedX++;
                    //}
                }
            // negative acceleration (slope descending backwards)
            }
        };

        // If hitting an obstacle with head, cancel upwards velocity and "snap to grid"
        if (tileAbove.solid) {
            // determine whether to bounce or fullstop
            if (tileAbove.bounce) {
                this.speedY = -this.speedY * tileAbove.bounce;
            } else {
                this.speedY = 0;
            }
            this.y = 32 * Math.round((this.y / 32));
        };

        // If hitting an obstacle face first, stop fully and "snap to grid"
        if (tileAhead.solid) {
            // if we were going too fast, count this as a "bonk"
            if (this.speedX >= 16) {
                this.bonks++;
                console.log("bonk!");
            }

            // determine whether to bounce or fullstop
            if (tileAhead.bounce) {
                this.speedX = -this.speedX * tileAhead.bounce;
            } else {
                this.speedX = 0;
            }

            this.x = 32 * parseInt(this.x / 32);
        };

        // Vertical movement if flying and not on ground (simulates holding right)
        if (this.flying && this.speedX < 24 && !(tileUnder.solid || tileUnder.slope)) this.speedX++;

        // Actually move based on speed
        this.x += (this.speedX / 8);
        this.y += (this.speedY / 8);

        // record max speed
        if (this.speedX > this.maxSpeed) this.maxSpeed = this.speedX;

        // Check if goal has been reached
        if (!this.goal) {
            if (this.x >= (this.level.goal * 32)) {
                console.log("GOAL! " + (this.x - (this.level.goal * 32)).toString());
                console.log("max speed: " + this.maxSpeed.toString());
                console.log("bonks: " + this.bonks.toString());
                this.goal = true;
            };
        };

        // Determine proper animation
        if (tileUnder.solid || tileUnder.slope) {
            // If standing on something...
            // Set animation depending on xspeed
            if (this.speedX > 0) {
                this.setAnimation("sliding");
            } else {
                this.setAnimation("still");
            }
        } else {
            // If on midair
            // Set animation depending on yspeed
            if (this.speedY > 0) {
                this.setAnimation("descending");
            } else {
                this.setAnimation("ascending");
            }
        }

        // Update animation
        updateAnimation(this.animation);

        // store onground status to be used by "flop"
        this.thisFrameOnGround = (tileUnder.solid || tileUnder.slope);

    };

    /*
     * public void .flap()
     *
     *  activates a "flap", which is yacopu gaining upwards velocity
     *
     */
    yacopu.prototype.flap = function (game) {

        // If the goal has been reached already, ignore
        if (this.goal) return null;

        // If standing on ground, give uncapped X acceleration
        if (this.thisFrameOnGround) {
            this.speedX += 6;
            this.speedY = 0;
            this.lastOnGround = this.onGround;
        };

        // Iniciate flight
        if (!this.flying) this.flying = true;

        // Upwards velocity
        if (this.speedY >= -24) this.speedY -= 16;

    };

    /*
     * public void .setAnimation(animId)
     *
     *  initializes a new animation
     *
     */
    yacopu.prototype.setAnimation = function (animId) {

        // If trying to set to already active animation, ignore
        if (this.animation.name === animId) return null;

        // Set animation variables, to step 0
        this.animation.name = animId;
        this.animation.step = 0;
        this.animation.totalSteps = animations[animId].length;
        this.animation.left = animations[animId][0].duration;
        this.animation.frame = animations[animId][0].frame;
    };

    /*
     * private void updateAnimation(anim)
     *
     *  advances animation by one frame
     *
     */
    function updateAnimation (anim) {

        // Time left being negative means no change
        if (anim.left < 0) return null;

        // else decrease by 1
        anim.left--;

        // If it reaches 0, advance one step of the animation cycle
        if (anim.left === 0) {
            // Increase step by 1
            anim.step++;

            // If step exceedes number, cycle back to 0
            if (anim.step === anim.totalSteps) anim.step = 0;

            // Set new timeleft and frame values
            anim.left = animations[anim.name][anim.step].duration;
            anim.frame = animations[anim.name][anim.step].frame;
        };

    };

    // Return object to global namespace
    return yacopu;

}());<|endoftext|>


<commit_before>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};
/**
 * @namespace Meteor js connection namespace.
 */
meteor = new Object();
/**
 * Limit for the incoming buffer. When the incoming XMLHttpRequest object buffer grows larger than this, the connection is reinitiated.
 */
meteor.BUFFER_MAX = 1 << 16; // limit for incoming buffer, exceeding this buffer triggers a reconnect
meteor.dismantle = function(xhr) {
	delete xhr.onreadystatechange;
	try { xhr.abort(); } catch (e) {};
	delete xhr.meteor;
};
/**
 * Meteor connection class. This is usually used with Atom serialization on top. Use psyc.Client if unsure.
 * @param {String} url URL of the Meteor connection endpoint.
 * @param {Function} callback Function to be called when data has been received.
 * @param {Function} error Function to be called when a fatal error occures.
 * @constructor
 * @example
 * var connection;
 * var incoming = function(data) {
 * 	document.write("Received data: " + data);
 * 	connection.send("Hello World.\n");
 * }
 * connection = new meteor.Connection("http://example.org/meteor/", incoming, alert);
 * connection.init();
 */
meteor.Connection = function(url, callback, error) {
    this.url = url;
    this.buffer = "";
    this.callback = callback;
    this.error = error;
	this.client_id = 0;
	this.new_incoming = 0;
	this.incoming = 0;
	this.outgoing = 0;
	this.init_xhr = 0;
	this.reconnect = 1; // do a reconnect on close
};
meteor.debug = function() {
	if (console && console.log) {
		console.log.apply(window, arguments);
	}
};
meteor.Connection.prototype = {
	reconnect_incoming : function() {
		meteor.debug("reconnecting due to timeout.\n");
		if (this.new_incoming) {
			meteor.dismantle(this.new_incoming);
			delete this.new_incoming;
		}
		if (this.incoming) {
			meteor.dismantle(this.incoming);
			delete this.incoming;
		}
		this.connect_new_incoming();
	},
	new_incoming_state_change : function() {
		var con = this.meteor;
		meteor.debug("new_incoming state is " + this.readyState);
		// we should check here for buffer length. maybe set a max
		// amount to shut down the main one ungracefully
		if (this.readyState >= 3) {
			con.connect_incoming();
		}
	},
	connect_new_incoming : function() {
		if (this.new_incoming) {
			// we already have one new incoming and are waiting for the
			// main one to shut down

			if (this.new_incoming.readyState == 4) {
			// someone is too fast for us.
			// TODO: we have to check for data in new_incoming,
			// not sure what to do with it. we can probably savely
			// parse it in case of atoms.
				meteor.debug("New connection already finished.\n");
			} else return this.connect_incoming();
		}

		meteor.debug("Connecting new incoming.\n");

		var xhr = new XMLHttpRequest();
		this.new_incoming = xhr;
		xhr.pos = 0;

		xhr.open("POST", this.url + "&id=" + escape(this.client_id).replace(/\+/g, "%2B"), true);
		// both opera and IE dont handle binary data correctly.
		if (!window.opera && navigator.appName != 'Microsoft Internet Explorer') {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
		}
		//xhr.overrideMimeType("text/plain; charset=ISO-8859-1");
		if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain; charset=x-user-defined');
		xhr.onreadystatechange = this.new_incoming_state_change;
		xhr.meteor = this;
		xhr.send("");
	},
	incoming_state_change : function() {
		var con = this.meteor;
		var status;

		if (!con) {
			meteor.debug("xhr lost connection to reality.");
			return;
		}
		if (this.readyState >= 3) {
			//this.readyState = 2;

			// workaround for IE
			try {
				status = this.status;
			} catch(e) {
				// this is ie country
				// this is ie
				meteor.debug("fucking ie");
			}

			if (status == 200) {
				var length = this.responseBody ? this.responseBody.length : this.responseText.length;

				if (length > this.pos) {
					meteor.debug((length-this.pos)+" bytes received in readyState "+this.readyState);
					var str;

					try {
						if (window.opera) {
							str = this.responseText.slice(this.pos);
						} else if (this.responseBody) {
							str = this.responseBody.join("");
						} else {
							str = this.responseText.slice(this.pos);
							var t = str.split("");
							for (var i = 0; i < str.length; i++) {
								t[i] = t[i].charCodeAt(0) & 0xff;
							}
							str = String.fromCharCode.apply(window, t);
						}

						if (con.callback.obj) {
							con.callback.call(con.callback.obj, str);
						} else {
							con.callback(str);
						}
					} catch (error) {
						meteor.debug("ERROR: "+error);
					}

					this.pos = length;
				}

				if (this.readyState == 4 || this.pos >= meteor.BUFFER_MAX) {
					if (this.operatimer) {
						clearTimeout(this.operatimer);
						delete this.operatimer;
					}
					if (con.reconnect) con.connect_new_incoming();
				}
			} else {
			// this throws an exception in firefox. brain
			//	con.error(this.statusText);
			}
		}
	},
	incoming_on_error : function() {
		meteor.debug("INCOMING ERROR!");
		var self = this;
		var cb = function() {
			self.meteor.connect_new_incoming();
		};
		window.setTimeout(cb, 500);
	},
	connect_incoming : function(xhr) {
		if (!xhr) {
			if (this.new_incoming) {
				xhr = this.new_incoming;
			} else throw("you need to call new_incoming() first. no this.new_incoming.");
		}

		if (this.incoming) {
			if (this.incoming.readyState != 4) {
				return;
			}

			meteor.dismantle(this.incoming);
		}

		if (this.operatimer) {
			clearTimeout(this.operatimer);
			delete this.operatimer;
		}

		xhr.onreadystatechange = this.incoming_state_change;
		xhr.onerror = this.incoming_on_error;
		meteor.debug("moved new incoming to incoming.");
		this.new_incoming = 0;
		this.incoming = xhr;
		meteor.Connection.prototype.incoming_state_change.call(xhr);

		// This code polls the xhr for new data in case opera is used. its necessary
		// because opera does not trigger an event if new data is available in state 3.
		if (window.opera) {
			var fun = function() {
				meteor.Connection.prototype.incoming_state_change.call(xhr);
			};
			this.operatimer = setInterval(fun, 100);
			meteor.debug("timer: "+this.operatimer);
		}
	},
	outgoing_state_change : function() {
		var con = this.meteor;

		if (this.readyState == 4) {

			if (this.status == 200) {

				con.connect_outgoing();
			} else {
				con.error(this.statusText);
			}
		}
	},
	connect_outgoing : function() {
		var xhr;

		if (this.outgoing) {
			this.outgoing.abort();
			xhr = this.outgoing;
		} else {
			xhr = new XMLHttpRequest();
			this.outgoing = xhr;
		}
		//this.error("outgoing state is " + xhr.readyState);

		xhr.open("POST", this.url + "&id=" + escape(this.client_id).replace(/\+/g, "%2B"), true);
		// we do this charset hackery because we have internal utf8 and plain ascii
		// for the rest of atom. this is supposed to be a binary transport
		xhr.onreadystatechange = this.outgoing_state_change;
		xhr.meteor = this;
		this.ready = 1;

		if (this.buffer.length > 0) this.write();
	},
	init_state_change : function(change_event) { // fetch the client_id and go
		var con = this.meteor;
		if (this.readyState == 4) {
			if (this.status == 200) {
				con.client_id = this.responseText;
				meteor.debug("got client ID " + con.client_id);

				meteor.dismantle(con.init_xhr);
				delete con.init_xhr;

				con.connect_outgoing();
				con.connect_new_incoming();
			} else if (this.status == 404) {
				con.error(this.responseText);
			} else {
				con.error(this.statusText);
			}

			delete this.meteor;
			delete con.init_xhr;
		}
	},
	/**
	 * Initialize the connection. This needs to be called before any data can be sent or received.
	 */
	init : function() { // fetch the client_id and go
		var xhr = new XMLHttpRequest();
		xhr.meteor = this;
		this.reconnect = 1;
		this.init_xhr = xhr;
		//this.error("initialization state is " + xhr.readyState);

		xhr.onreadystatechange = this.init_state_change;
		xhr.meteor = this;
		xhr.open("GET", this.url, true);
		xhr.send("");
	},
	/**
	 * Close incoming connection and clean up cyclic references.
	 */
	close : function() {
		var list = [this.init_xhr, this.new_incoming, this.incoming, this.outgoing];
		for (var i = 0; i < list.length; i++) {
			var t = list[i];
			try {
				if (t) {
					meteor.dismantle(t);
				}
			} catch(e) { }
		}
		delete this.init_xhr;
		delete this.incoming;
		delete this.new_incoming;
		delete this.outgoing;
		delete this.callback;
		delete this.error;
	},
	/**
	 * Send some data.
	 * @param {String} data String to be sent.
	 */
	send : function(data) {
		// check for status
		this.buffer += data;

		if (this.client_id && this.ready && !this.will_write) {
			// ifdef firefox
			//this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			// endif
			var self = this;
			var cb = function() {
				self.will_write = 0;
				self.write();
			}
			this.will_write = 1;
			window.setTimeout(cb, 20);
		}
	},
	write : function() {
		if (this.outgoing.sendAsBinary) {
			this.outgoing.setRequestHeader("Content-Type", "application/octet-stream");
			this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			this.outgoing.sendAsBinary(this.buffer);
		} else {
			this.outgoing.send(this.buffer);
		}
		meteor.debug("Sending ("+this.buffer.substr(this.buffer.length-40, 39)+")\n");
		this.ready = 0;
		this.buffer = "";
	}
};
// the params handed by the user could be prototyped with a
// msg and something more
meteor.CallbackWrapper = function(params, mapping) {
	this.mapping = mapping;
	this.params = params;
};
meteor.CallbackWrapper.prototype = {
	msg : function(p, message) {
		var ok = true;
		if ((this.params.source && this.params.source != p.source())
		||  (this.params.context && this.params.context != p.v("_context"))
		||  (this.params.target && this.params.target != p.target())
		) {
			ok = false;
			meteor.debug(p.toString()+" is not the one.\n");
		}

		if (ok) {
			if (this.params.object) {
				if (this.params.cb) {
					return this.params.cb.call(this.params.object, p, message, this);
				}

				return this.params.object.msg(p, message, this);
			} else {
				return this.params.cb(p, message, this);
			}
		}
	},
	active : function() {
		return this.mapping == 0 ? 0 : 1;
	},
	unregister : function() {
		if (this.mapping == 0) return;

		var list = this.mapping.get(this.params.method);

		for (var i = 0; i < list.length; i++) {
			if (list[i] == this) {
				list.splice(i, 1);
			}
		}

		this.mapping = 0;
	}
};
<commit_msg>support for ie<commit_after>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};
/**
 * @namespace Meteor js connection namespace.
 */
meteor = new Object();
/**
 * Limit for the incoming buffer. When the incoming XMLHttpRequest object buffer grows larger than this, the connection is reinitiated.
 */
meteor.BUFFER_MAX = 1 << 16; // limit for incoming buffer, exceeding this buffer triggers a reconnect
meteor.dismantle = function(xhr) {
	delete xhr.onreadystatechange;
	try { xhr.abort(); } catch (e) {};
	delete xhr.meteor;
};
/**
 * Meteor connection class. This is usually used with Atom serialization on top. Use psyc.Client if unsure.
 * @param {String} url URL of the Meteor connection endpoint.
 * @param {Function} callback Function to be called when data has been received.
 * @param {Function} error Function to be called when a fatal error occures.
 * @constructor
 * @example
 * var connection;
 * var incoming = function(data) {
 * 	document.write("Received data: " + data);
 * 	connection.send("Hello World.\n");
 * }
 * connection = new meteor.Connection("http://example.org/meteor/", incoming, alert);
 * connection.init();
 */
meteor.Connection = function(url, callback, error) {
    this.url = url;
    this.buffer = "";
    this.callback = callback;
    this.error = error;
	this.client_id = 0;
	this.new_incoming = 0;
	this.incoming = 0;
	this.outgoing = 0;
	this.init_xhr = 0;
	this.reconnect = 1; // do a reconnect on close
};
meteor.debug = function() {
	if (window.console && window.console.log) {
		if (window.console.firebug) {
			window.console.log.apply(window, arguments);
		} else { //this is IE
			window.console.log(arguments[0]);
		}
	}
};
meteor.Connection.prototype = {
	reconnect_incoming : function() {
		meteor.debug("reconnecting due to timeout.\n");
		if (this.new_incoming) {
			meteor.dismantle(this.new_incoming);
			delete this.new_incoming;
		}
		if (this.incoming) {
			meteor.dismantle(this.incoming);
			delete this.incoming;
		}
		this.connect_new_incoming();
	},
	new_incoming_state_change : function() {
		var con = this.meteor;
		meteor.debug("new_incoming state is " + this.readyState);
		// we should check here for buffer length. maybe set a max
		// amount to shut down the main one ungracefully
		if (this.readyState >= 3) {
			con.connect_incoming();
		}
	},
	connect_new_incoming : function() {
		if (this.new_incoming) {
			// we already have one new incoming and are waiting for the
			// main one to shut down

			if (this.new_incoming.readyState == 4) {
			// someone is too fast for us.
			// TODO: we have to check for data in new_incoming,
			// not sure what to do with it. we can probably savely
			// parse it in case of atoms.
				meteor.debug("New connection already finished.\n");
			} else return this.connect_incoming();
		}

		meteor.debug("Connecting new incoming.\n");

		var xhr = new XMLHttpRequest();
		this.new_incoming = xhr;
		xhr.pos = 0;

		xhr.open("POST", this.url + "&id=" + escape(this.client_id).replace(/\+/g, "%2B"), true);
		// both opera and IE dont handle binary data correctly.
		if (!window.opera && navigator.appName != 'Microsoft Internet Explorer') {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
		}
		//xhr.overrideMimeType("text/plain; charset=ISO-8859-1");
		if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain; charset=x-user-defined');
		xhr.onreadystatechange = this.new_incoming_state_change;
		xhr.meteor = this;
		xhr.send("");
	},
	incoming_state_change : function() {
		var con = this.meteor;
		var status;

		if (!con) {
			meteor.debug("xhr lost connection to reality.");
			return;
		}
		if (this.readyState >= 3) {
			//this.readyState = 2;

			// workaround for IE
			try {
				status = this.status;
			} catch(e) {
				// this is ie country
				// this is ie
				meteor.debug("fucking ie");
			}

			if (status == 200) {
				var length = this.responseBody ? this.responseBody.length : this.responseText.length;

				if (length > this.pos) {
					meteor.debug((length-this.pos)+" bytes received in readyState "+this.readyState);
					var str;

					try {
						if (window.opera) {
							str = this.responseText.slice(this.pos);
						} else if (this.responseBody) {
							str = this.responseBody.join("");
						} else {
							str = this.responseText.slice(this.pos);
							var t = str.split("");
							for (var i = 0; i < str.length; i++) {
								t[i] = t[i].charCodeAt(0) & 0xff;
							}
							str = String.fromCharCode.apply(window, t);
						}

						if (con.callback.obj) {
							con.callback.call(con.callback.obj, str);
						} else {
							con.callback(str);
						}
					} catch (error) {
						meteor.debug("ERROR: "+error);
					}

					this.pos = length;
				}

				if (this.readyState == 4 || this.pos >= meteor.BUFFER_MAX) {
					if (this.operatimer) {
						clearTimeout(this.operatimer);
						delete this.operatimer;
					}
					if (con.reconnect) con.connect_new_incoming();
				}
			} else {
			// this throws an exception in firefox. brain
			//	con.error(this.statusText);
			}
		}
	},
	incoming_on_error : function() {
		meteor.debug("INCOMING ERROR!");
		var self = this;
		var cb = function() {
			self.meteor.connect_new_incoming();
		};
		window.setTimeout(cb, 500);
	},
	connect_incoming : function(xhr) {
		if (!xhr) {
			if (this.new_incoming) {
				xhr = this.new_incoming;
			} else throw("you need to call new_incoming() first. no this.new_incoming.");
		}

		if (this.incoming) {
			if (this.incoming.readyState != 4) {
				return;
			}

			meteor.dismantle(this.incoming);
		}

		if (this.operatimer) {
			clearTimeout(this.operatimer);
			delete this.operatimer;
		}

		xhr.onreadystatechange = this.incoming_state_change;
		xhr.onerror = this.incoming_on_error;
		meteor.debug("moved new incoming to incoming.");
		this.new_incoming = 0;
		this.incoming = xhr;
		meteor.Connection.prototype.incoming_state_change.call(xhr);

		// This code polls the xhr for new data in case opera is used. its necessary
		// because opera does not trigger an event if new data is available in state 3.
		if (window.opera) {
			var fun = function() {
				meteor.Connection.prototype.incoming_state_change.call(xhr);
			};
			this.operatimer = setInterval(fun, 100);
			meteor.debug("timer: "+this.operatimer);
		}
	},
	outgoing_state_change : function() {
		var con = this.meteor;

		if (this.readyState == 4) {

			if (this.status == 200) {

				con.connect_outgoing();
			} else {
				con.error(this.statusText);
			}
		}
	},
	connect_outgoing : function() {
		var xhr;

		if (this.outgoing) {
			this.outgoing.abort();
			xhr = this.outgoing;
		} else {
			xhr = new XMLHttpRequest();
			this.outgoing = xhr;
		}
		//this.error("outgoing state is " + xhr.readyState);

		xhr.open("POST", this.url + "&id=" + escape(this.client_id).replace(/\+/g, "%2B"), true);
		// we do this charset hackery because we have internal utf8 and plain ascii
		// for the rest of atom. this is supposed to be a binary transport
		xhr.onreadystatechange = this.outgoing_state_change;
		xhr.meteor = this;
		this.ready = 1;

		if (this.buffer.length > 0) this.write();
	},
	init_state_change : function(change_event) { // fetch the client_id and go
		var con = this.meteor;
		if (this.readyState == 4) {
			if (this.status == 200) {
				con.client_id = this.responseText;
				meteor.debug("got client ID " + con.client_id);

				meteor.dismantle(con.init_xhr);
				delete con.init_xhr;

				con.connect_outgoing();
				con.connect_new_incoming();
			} else if (this.status == 404) {
				con.error(this.responseText);
			} else {
				con.error(this.statusText);
			}

			delete this.meteor;
			delete con.init_xhr;
		}
	},
	/**
	 * Initialize the connection. This needs to be called before any data can be sent or received.
	 */
	init : function() { // fetch the client_id and go
		var xhr = new XMLHttpRequest();
		xhr.meteor = this;
		this.reconnect = 1;
		this.init_xhr = xhr;
		//this.error("initialization state is " + xhr.readyState);

		xhr.onreadystatechange = this.init_state_change;
		xhr.meteor = this;
		xhr.open("GET", this.url, true);
		xhr.send("");
	},
	/**
	 * Close incoming connection and clean up cyclic references.
	 */
	close : function() {
		var list = [this.init_xhr, this.new_incoming, this.incoming, this.outgoing];
		for (var i = 0; i < list.length; i++) {
			var t = list[i];
			try {
				if (t) {
					meteor.dismantle(t);
				}
			} catch(e) { }
		}
		delete this.init_xhr;
		delete this.incoming;
		delete this.new_incoming;
		delete this.outgoing;
		delete this.callback;
		delete this.error;
	},
	/**
	 * Send some data.
	 * @param {String} data String to be sent.
	 */
	send : function(data) {
		// check for status
		this.buffer += data;

		if (this.client_id && this.ready && !this.will_write) {
			// ifdef firefox
			//this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			// endif
			var self = this;
			var cb = function() {
				self.will_write = 0;
				self.write();
			}
			this.will_write = 1;
			window.setTimeout(cb, 20);
		}
	},
	write : function() {
		if (this.outgoing.sendAsBinary) {
			this.outgoing.setRequestHeader("Content-Type", "application/octet-stream");
			this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			this.outgoing.sendAsBinary(this.buffer);
		} else {
			this.outgoing.send(this.buffer);
		}
		meteor.debug("Sending ("+this.buffer.substr(this.buffer.length-40, 39)+")\n");
		this.ready = 0;
		this.buffer = "";
	}
};
// the params handed by the user could be prototyped with a
// msg and something more
meteor.CallbackWrapper = function(params, mapping) {
	this.mapping = mapping;
	this.params = params;
};
meteor.CallbackWrapper.prototype = {
	msg : function(p, message) {
		var ok = true;
		if ((this.params.source && this.params.source != p.source())
		||  (this.params.context && this.params.context != p.v("_context"))
		||  (this.params.target && this.params.target != p.target())
		) {
			ok = false;
			meteor.debug(p.toString()+" is not the one.\n");
		}

		if (ok) {
			if (this.params.object) {
				if (this.params.cb) {
					return this.params.cb.call(this.params.object, p, message, this);
				}

				return this.params.object.msg(p, message, this);
			} else {
				return this.params.cb(p, message, this);
			}
		}
	},
	active : function() {
		return this.mapping == 0 ? 0 : 1;
	},
	unregister : function() {
		if (this.mapping == 0) return;

		var list = this.mapping.get(this.params.method);

		for (var i = 0; i < list.length; i++) {
			if (list[i] == this) {
				list.splice(i, 1);
			}
		}

		this.mapping = 0;
	}
};
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types'
import {View, StyleSheet, Animated} from 'react-native';

import Expo, { Svg } from 'expo';
const AnimatedSvg = Animated.createAnimatedComponent(Svg);
const {interpolate} = require('d3-interpolate');

export default class SvgAnimatedLinearGradient extends Component {
    constructor(props) {
        super(props);

        this.state = {
            offsetValues: [
                '-2', '-1.5', '-1'
            ],
            offsets: [
                '0.0001', '0.0002', '0.0003' // Avoid duplicate value cause error in Android
            ],
            frequence: props.duration / 2
        }
        this._isMounted = false;
        this._animate = new Animated.Value(0)
        this.loopAnimation = this
            .loopAnimation
            .bind(this)
    }
    offsetValueBound(x) {
        if (x > 1) {
            return '1'
        }
        if (x < 0) {
            return '0'
        }
        return x
    }
    componentDidMount(props) {
        this._isMounted = true
        this.loopAnimation()
    }
    componentWillUnmount() {
        this._isMounted = false
    }
    loopAnimation() {
        if (!this._isMounted) return;
        // setup interpolate
        let interpolator = interpolate(this.state, {
            offsetValues: ['1', '1.5', '2']
        });

        // start animation
        let start = Date.now();
        this._animation = () => {
            const now = Date.now();
            let t = (now - start) / this.props.duration;
            if (t > 1) {
                t = 1
            }

            let newState = interpolator(t);
            let offsetValues = [];
            offsetValues[0] = this.offsetValueBound(newState.offsetValues[0]);
            offsetValues[1] = this.offsetValueBound(newState.offsetValues[1]);
            offsetValues[2] = this.offsetValueBound(newState.offsetValues[2]);

            // Make sure at least two offsets is different
            if (offsetValues[0] !== offsetValues[1] || offsetValues[0] !==  offsetValues[2] || offsetValues[1] !== offsetValues[2]) {
                this._isMounted && this.setState({offsets: offsetValues});
            }
            if (t < 1) {
                requestAnimationFrame(this._animation);
            }
        }
        requestAnimationFrame(this._animation);

        // Setup loop animation
        Animated.sequence([
            Animated.timing(this._animate, {
                toValue: 1,
                duration: this.state.frequence
            }),
            Animated.timing(this._animate, {
                toValue: 0,
                duration: this.state.frequence
            })
        ]).start((event) => {
            if (event.finished) {
                this.loopAnimation()
            }
        })
    }
    render() {

        return (
            <AnimatedSvg height={this.props.height} width={this.props.width}>
                <Svg.Defs>
                    <Svg.LinearGradient id="grad" x1={this.props.x1} y1={this.props.y1} x2={this.props.x2} y2={this.props.y2}>
                        <Svg.Stop
                            offset={this.state.offsets[0]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                        <Svg.Stop
                            offset={this.state.offsets[1]}
                            stopColor={this.props.secondaryColor}
                            stopOpacity="1"/>
                        <Svg.Stop
                            offset={this.state.offsets[2]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                    </Svg.LinearGradient>
                    <Svg.ClipPath id="clip">
                        <Svg.G>
                            {this.props.children}
                        </Svg.G>
                    </Svg.ClipPath>
                </Svg.Defs>

                <Svg.Rect
                    x="0"
                    y="0"
                    height={this.props.height}
                    width={this.props.width}
                    fill="url(#grad)"
                    clipPath="url(#clip)"/>
            </AnimatedSvg>
        );
    }
}
SvgAnimatedLinearGradient.propTypes = {
    primaryColor: PropTypes.string,
    secondaryColor: PropTypes.string,
    duration: PropTypes.number,
    width: PropTypes.number,
    height: PropTypes.number,
    x1: PropTypes.string,
    y1: PropTypes.string,
    x2: PropTypes.string,
    y2: PropTypes.string,
}
SvgAnimatedLinearGradient.defaultProps = {
    primaryColor: '#eeeeee',
    secondaryColor: '#dddddd',
    duration: 2000,
    width: 300,
    height: 200,
    x1: '0',
    y1: '0',
    x2: '100%',
    y2: '0'

}
<commit_msg>Update index.js<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types'
import {View, StyleSheet, Animated} from 'react-native';

//import Expo, { Svg } from 'expo';
import Svg, {
    Circle,
    ClipPath,
    G,
    LinearGradient,
    Rect,
    Defs,
    Stop
}  from 'react-native-svg';

const AnimatedSvg = Animated.createAnimatedComponent(Svg);
const {interpolate} = require('d3-interpolate');

export default class SvgAnimatedLinearGradient extends Component {
    constructor(props) {
        super(props);

        this.state = {
            offsetValues: [
                '-2', '-1.5', '-1'
            ],
            offsets: [
                '0.0001', '0.0002', '0.0003' // Avoid duplicate value cause error in Android
            ],
            frequence: props.duration / 2
        }
        this._isMounted = false;
        this._animate = new Animated.Value(0)
        this.loopAnimation = this
            .loopAnimation
            .bind(this)
    }
    offsetValueBound(x) {
        if (x > 1) {
            return '1'
        }
        if (x < 0) {
            return '0'
        }
        return x
    }
    componentDidMount(props) {
        this._isMounted = true
        this.loopAnimation()
    }
    componentWillUnmount() {
        this._isMounted = false
    }
    loopAnimation() {
        if (!this._isMounted) return;
        // setup interpolate
        let interpolator = interpolate(this.state, {
            offsetValues: ['1', '1.5', '2']
        });

        // start animation
        let start = Date.now();
        this._animation = () => {
            const now = Date.now();
            let t = (now - start) / this.props.duration;
            if (t > 1) {
                t = 1
            }

            let newState = interpolator(t);
            let offsetValues = [];
            offsetValues[0] = this.offsetValueBound(newState.offsetValues[0]);
            offsetValues[1] = this.offsetValueBound(newState.offsetValues[1]);
            offsetValues[2] = this.offsetValueBound(newState.offsetValues[2]);

            // Make sure at least two offsets is different
            if (offsetValues[0] !== offsetValues[1] || offsetValues[0] !==  offsetValues[2] || offsetValues[1] !== offsetValues[2]) {
                this._isMounted && this.setState({offsets: offsetValues});
            }
            if (t < 1) {
                requestAnimationFrame(this._animation);
            }
        }
        requestAnimationFrame(this._animation);

        // Setup loop animation
        Animated.sequence([
            Animated.timing(this._animate, {
                toValue: 1,
                duration: this.state.frequence
            }),
            Animated.timing(this._animate, {
                toValue: 0,
                duration: this.state.frequence
            })
        ]).start((event) => {
            if (event.finished) {
                this.loopAnimation()
            }
        })
    }
    render() {

        return (
            <AnimatedSvg height={this.props.height} width={this.props.width}>
                <Defs>
                    <LinearGradient id="grad" x1={this.props.x1} y1={this.props.y1} x2={this.props.x2} y2={this.props.y2}>
                        <Stop
                            offset={this.state.offsets[0]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                        <Stop
                            offset={this.state.offsets[1]}
                            stopColor={this.props.secondaryColor}
                            stopOpacity="1"/>
                        <Stop
                            offset={this.state.offsets[2]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                    </LinearGradient>
                    <ClipPath id="clip">
                        <G rotation="50"
                        origin="100, 50">
                            {this.props.children}
                        </G>
                    </ClipPath>
                </Defs>

                <Rect
                    x="0"
                    y="0"
                    height={this.props.height}
                    width={this.props.width}
                    fill="url(#grad)"
                    clipPath="url(#clip)"/>
            </AnimatedSvg>
        );
    }
}
SvgAnimatedLinearGradient.propTypes = {
    primaryColor: PropTypes.string,
    secondaryColor: PropTypes.string,
    duration: PropTypes.number,
    width: PropTypes.number,
    height: PropTypes.number,
    x1: PropTypes.string,
    y1: PropTypes.string,
    x2: PropTypes.string,
    y2: PropTypes.string,
}
SvgAnimatedLinearGradient.defaultProps = {
    primaryColor: '#eeeeee',
    secondaryColor: '#dddddd',
    duration: 2000,
    width: 300,
    height: 200,
    x1: '0',
    y1: '0',
    x2: '100%',
    y2: '0'

}
<|endoftext|>


<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const ndax = require ('./ndax.js');

//  ---------------------------------------------------------------------------

module.exports = class zipmex extends ndax {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'zipmex',
            'name': 'Zipmex',
            'countries': [ 'AU', 'SG', 'TH', 'ID' ], // Australia, Singapore, Thailand, Indonesia
            'certified': false,
            'pro': true,
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/146103275-c39a34d9-68a4-4cd2-b1f1-c684548d311b.jpg',
                'test': undefined,
                'api': {
                    'public': 'https://apws.zipmex.com:8443/AP',
                    'private': 'https://apws.zipmex.com:8443/AP',
                    // 'ws': 'wss://apws.zipmex.com/WSGateway'
                },
                'www': 'https://zipmex.com/',
                'referral': 'https://trade.zipmex.com/global/accounts/sign-up?aff=KLm7HyCsvN',
                'fees': 'https://zipmex.com/fee-schedule',
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'percentage': true,
                    'taker': this.parseNumber ('0.002'),
                    'maker': this.parseNumber ('0.002'),
                },
            },
        });
    }
};

<commit_msg>zipmex ws wip<commit_after>'use strict';

//  ---------------------------------------------------------------------------

const ndax = require ('./ndax.js');

//  ---------------------------------------------------------------------------

module.exports = class zipmex extends ndax {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'zipmex',
            'name': 'Zipmex',
            'countries': [ 'AU', 'SG', 'TH', 'ID' ], // Australia, Singapore, Thailand, Indonesia
            'certified': false,
            'pro': false,
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/146103275-c39a34d9-68a4-4cd2-b1f1-c684548d311b.jpg',
                'test': undefined,
                'api': {
                    'public': 'https://apws.zipmex.com:8443/AP',
                    'private': 'https://apws.zipmex.com:8443/AP',
                    // 'ws': 'wss://apws.zipmex.com/WSGateway'
                },
                'www': 'https://zipmex.com/',
                'referral': 'https://trade.zipmex.com/global/accounts/sign-up?aff=KLm7HyCsvN',
                'fees': 'https://zipmex.com/fee-schedule',
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'percentage': true,
                    'taker': this.parseNumber ('0.002'),
                    'maker': this.parseNumber ('0.002'),
                },
            },
        });
    }
};

<|endoftext|>


<commit_before>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};
/**
 * @namespace Meteor js connection namespace.
 */
meteor = new Object();
/**
 * Limit for the incoming buffer. When the incoming XMLHttpRequest object buffer grows larger than this, the connection is reinitiated.
 */
meteor.BUFFER_MAX = 1 << 16; // limit for incoming buffer, exceeding this buffer triggers a reconnect
meteor.dismantle = function(xhr) {
	delete xhr.onreadystatechange;
	try { xhr.abort(); } catch (e) {};
	delete xhr.meteor;
};
/**
 * Meteor connection class. This is usually used with Atom serialization on top. Use psyc.Client if unsure.
 * @param {String} url URL of the Meteor connection endpoint.
 * @param {Function} callback Function to be called when data has been received.
 * @param {Function} error Function to be called when a fatal error occures.
 * @constructor
 * @example
 * var connection;
 * var incoming = function(data) {
 * 	document.write("Received data: " + data);
 * 	connection.send("Hello World.\n");
 * }
 * connection = new meteor.Connection("http://example.org/meteor/", incoming, alert);
 * connection.init();
 */
meteor.Connection = function(url, vars, callback, error) {
    this.url = url;
    this.vars = vars;
    this.buffer = "";
    this.callback = callback;
    this.error = error;
    this.async = true;
    this.new_incoming = 0;
    this.incoming = 0;
    this.outgoing = 0;
    this.init_xhr = 0;
    this.reconnect = 1; // do a reconnect on close
};
meteor.debug = function() {
	if (window.console && window.console.log) {
		if (window.console.firebug) {
			window.console.log.apply(window, arguments);
		} else { //this is IE
			window.console.log(arguments[0]);
		}
	}
};
meteor.Connection.prototype = {
	reconnect_incoming : function() {
		meteor.debug("reconnecting due to timeout.\n");
		if (this.new_incoming) {
			meteor.dismantle(this.new_incoming);
			delete this.new_incoming;
		}
		if (this.incoming) {
			meteor.dismantle(this.incoming);
			delete this.incoming;
		}
		this.connect_new_incoming();
	},
	new_incoming_state_change : function() {
		var con = this.meteor;
		meteor.debug("new_incoming state is " + this.readyState);
		// we should check here for buffer length. maybe set a max
		// amount to shut down the main one ungracefully
		if (this.readyState >= 3) {
			con.connect_incoming();
		}
	},
	connect_new_incoming : function() {
		if (this.new_incoming) {
			// we already have one new incoming and are waiting for the
			// main one to shut down

			if (this.new_incoming.readyState == 4) {
			// someone is too fast for us.
			// TODO: we have to check for data in new_incoming,
			// not sure what to do with it. we can probably savely
			// parse it in case of atoms.
				meteor.debug("New connection already finished.\n");
			} else return this.connect_incoming();
		}

		meteor.debug("Connecting new incoming.\n");

		var xhr = new XMLHttpRequest();
		this.new_incoming = xhr;
		xhr.pos = 0;

		xhr.open("POST", UTIL.make_url(this.url, this.vars), true);
		// both opera and IE dont handle binary data correctly.
		if (!window.opera && navigator.appName != 'Microsoft Internet Explorer') {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
		}
		//xhr.overrideMimeType("text/plain; charset=ISO-8859-1");
		if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain; charset=x-user-defined');
		xhr.onreadystatechange = this.new_incoming_state_change;
		xhr.meteor = this;
		xhr.send("");
	},
	set_nonblocking : function() {
		this.async = true;
		this.outgoing.async = true;
		this.outgoing.onreadystatechange = outgoing_state_change;
	},
	set_blocking : function() {
		this.async = false;
		this.outgoing.onreadystatechange = null;
		this.outgoing.async = false;
	},
	incoming_state_change : function() {
		var con = this.meteor;
		var status;

		if (!con) {
			meteor.debug("xhr lost connection to reality.");
			return;
		}
		if (this.readyState >= 3) {
			//this.readyState = 2;

			// workaround for IE
			try {
				status = this.status;
			} catch(e) {
				// this is ie country
				// this is ie
				meteor.debug("fucking ie");
			}

			if (status == 200) {
				var length = this.responseBody ? this.responseBody.length : this.responseText.length;

				if (length > this.pos) {
					meteor.debug((length-this.pos)+" bytes received in readyState "+this.readyState);
					var str;

					try {
						if (window.opera) {
							str = this.responseText.slice(this.pos);
						} else if (this.responseBody) {
							str = this.responseBody.join("");
						} else {
							str = this.responseText.slice(this.pos);
							var t = str.split("");
							for (var i = 0; i < str.length; i++) {
								t[i] = t[i].charCodeAt(0) & 0xff;
							}
							str = String.fromCharCode.apply(window, t);
						}

						if (con.callback.obj) {
							con.callback.call(con.callback.obj, str);
						} else {
							con.callback(str);
						}
					} catch (error) {
						meteor.debug("ERROR: "+error);
					}

					this.pos = length;
				}

				if (this.readyState == 4 || this.pos >= meteor.BUFFER_MAX) {
					if (this.operatimer) {
						clearTimeout(this.operatimer);
						delete this.operatimer;
					}
					if (con.reconnect) con.connect_new_incoming();
				}
			} else {
			// this throws an exception in firefox. brain
			//	con.error(this.statusText);
			}
		}
	},
	incoming_on_error : function() {
		meteor.debug("INCOMING ERROR!");
		var self = this;
		var cb = function() {
			self.meteor.connect_new_incoming();
		};
		window.setTimeout(cb, 500);
	},
	connect_incoming : function(xhr) {
		if (!xhr) {
			if (this.new_incoming) {
				xhr = this.new_incoming;
			} else throw("you need to call new_incoming() first. no this.new_incoming.");
		}

		if (this.incoming) {
			if (this.incoming.readyState != 4) {
				return;
			}

			meteor.dismantle(this.incoming);
		}

		if (this.operatimer) {
			clearTimeout(this.operatimer);
			delete this.operatimer;
		}

		xhr.onreadystatechange = this.incoming_state_change;
		xhr.onerror = this.incoming_on_error;
		meteor.debug("moved new incoming to incoming.");
		this.new_incoming = 0;
		this.incoming = xhr;
		meteor.Connection.prototype.incoming_state_change.call(xhr);

		// This code polls the xhr for new data in case opera is used. its necessary
		// because opera does not trigger an event if new data is available in state 3.
		if (window.opera) {
			var fun = function() {
				meteor.Connection.prototype.incoming_state_change.call(xhr);
			};
			this.operatimer = setInterval(fun, 100);
			meteor.debug("timer: "+this.operatimer);
		}
	},
	outgoing_state_change : function() {
		var con = this.meteor;

		if (this.readyState == 4) {

			if (this.status == 200) {
				con.connect_outgoing();
			} else {
				con.error(this.statusText);
			}
		}
	},
	connect_outgoing : function() {
		var xhr;

		if (this.outgoing) {
			this.outgoing.abort();
			xhr = this.outgoing;
		} else {
			xhr = new XMLHttpRequest();
			this.outgoing = xhr;
		}
		//this.error("outgoing state is " + xhr.readyState);

		xhr.open("POST", UTIL.make_url(this.url, this.vars), this.async);
		// we do this charset hackery because we have internal utf8 and plain ascii
		// for the rest of atom. this is supposed to be a binary transport
		if (this.async) {
		    xhr.onreadystatechange = this.outgoing_state_change;
		}
		xhr.meteor = this;
		this.ready = 1;

		if (this.buffer.length > 0) this.write();
	},
	init_state_change : function(change_event) { // fetch the client_id and go
		var con = this.meteor;
		if (this.readyState == 4) {
			if (this.status == 200) {
				con.vars["id"] = this.responseText;
				meteor.debug("got client ID " + con.vars["id"]);

				meteor.dismantle(con.init_xhr);
				delete con.init_xhr;

				con.connect_outgoing();
				con.connect_new_incoming();
			} else if (this.status == 404) {
				con.error(this.responseText);
			} else {
				con.error(this.statusText);
			}

			delete this.meteor;
			delete con.init_xhr;
		}
	},
	/**
	 * Initialize the connection. This needs to be called before any data can be sent or received.
	 */
	init : function() { // fetch the client_id and go
		var xhr = new XMLHttpRequest();
		xhr.meteor = this;
		this.reconnect = 1;
		this.init_xhr = xhr;
		//this.error("initialization state is " + xhr.readyState);

		xhr.onreadystatechange = this.init_state_change;
		xhr.meteor = this;
		xhr.open("GET", this.url, true);
		xhr.send("");
	},
	/**
	 * Close incoming connection and clean up cyclic references.
	 */
	close : function() {
		var list = [this.init_xhr, this.new_incoming, this.incoming, this.outgoing];
		for (var i = 0; i < list.length; i++) {
			var t = list[i];
			try {
				if (t) {
					meteor.dismantle(t);
				}
			} catch(e) { }
		}
		delete this.init_xhr;
		delete this.incoming;
		delete this.new_incoming;
		delete this.outgoing;
		delete this.callback;
		delete this.error;
	},
	/**
	 * Send some data.
	 * @param {String} data String to be sent.
	 */
	send : function(data) {
		// check for status
		this.buffer += data;

		if (this.vars["id"] && this.ready) {
		    if (!this.async) {
			this.write();
		    } else if (!this.will_write) {
			// ifdef firefox
			//this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			// endif
			var self = this;
			var cb = function() {
				self.will_write = 0;
				self.write();
			}
			this.will_write = 1;
			window.setTimeout(cb, 20);
		    }
		}
	},
	write : function() {
		if (this.outgoing.sendAsBinary) {
			this.outgoing.setRequestHeader("Content-Type", "application/octet-stream");
			this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			this.outgoing.sendAsBinary(this.buffer);
		} else {
			this.outgoing.send(this.buffer);
		}
		meteor.debug("Sending ("+this.buffer.substr(this.buffer.length-40, 39)+")\n");
		this.ready = 0;
		this.buffer = "";
	}
};
// the params handed by the user could be prototyped with a
// msg and something more
meteor.CallbackWrapper = function(params, mapping) {
	this.mapping = mapping;
	this.params = params;
};
meteor.CallbackWrapper.prototype = {
	msg : function(p, message) {
		var ok = true;
		if ((this.params.source && this.params.source != p.source())
		||  (this.params.context && this.params.context != p.v("_context"))
		||  (this.params.target && this.params.target != p.target())
		) {
			ok = false;
			meteor.debug(p.toString()+" is not the one.\n");
		}

		if (ok) {
			if (this.params.object) {
				if (this.params.cb) {
					return this.params.cb.call(this.params.object, p, message, this);
				}

				return this.params.object.msg(p, message, this);
			} else {
				return this.params.cb(p, message, this);
			}
		}
	},
	active : function() {
		return this.mapping == 0 ? 0 : 1;
	},
	unregister : function() {
		if (this.mapping == 0) return;

		var list = this.mapping.get(this.params.method);

		for (var i = 0; i < list.length; i++) {
			if (list[i] == this) {
				list.splice(i, 1);
			}
		}

		this.mapping = 0;
	}
};
<commit_msg>include nick<commit_after>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};
/**
 * @namespace Meteor js connection namespace.
 */
meteor = new Object();
/**
 * Limit for the incoming buffer. When the incoming XMLHttpRequest object buffer grows larger than this, the connection is reinitiated.
 */
meteor.BUFFER_MAX = 1 << 16; // limit for incoming buffer, exceeding this buffer triggers a reconnect
meteor.dismantle = function(xhr) {
	delete xhr.onreadystatechange;
	try { xhr.abort(); } catch (e) {};
	delete xhr.meteor;
};
/**
 * Meteor connection class. This is usually used with Atom serialization on top. Use psyc.Client if unsure.
 * @param {String} url URL of the Meteor connection endpoint.
 * @param {Function} callback Function to be called when data has been received.
 * @param {Function} error Function to be called when a fatal error occures.
 * @constructor
 * @example
 * var connection;
 * var incoming = function(data) {
 * 	document.write("Received data: " + data);
 * 	connection.send("Hello World.\n");
 * }
 * connection = new meteor.Connection("http://example.org/meteor/", incoming, alert);
 * connection.init();
 */
meteor.Connection = function(url, vars, callback, error) {
    this.url = url;
    this.vars = vars;
    this.buffer = "";
    this.callback = callback;
    this.error = error;
    this.async = true;
    this.new_incoming = 0;
    this.incoming = 0;
    this.outgoing = 0;
    this.init_xhr = 0;
    this.reconnect = 1; // do a reconnect on close
};
meteor.debug = function() {
	if (window.console && window.console.log) {
		if (window.console.firebug) {
			window.console.log.apply(window, arguments);
		} else { //this is IE
			window.console.log(arguments[0]);
		}
	}
};
meteor.Connection.prototype = {
	reconnect_incoming : function() {
		meteor.debug("reconnecting due to timeout.\n");
		if (this.new_incoming) {
			meteor.dismantle(this.new_incoming);
			delete this.new_incoming;
		}
		if (this.incoming) {
			meteor.dismantle(this.incoming);
			delete this.incoming;
		}
		this.connect_new_incoming();
	},
	new_incoming_state_change : function() {
		var con = this.meteor;
		meteor.debug("new_incoming state is " + this.readyState);
		// we should check here for buffer length. maybe set a max
		// amount to shut down the main one ungracefully
		if (this.readyState >= 3) {
			con.connect_incoming();
		}
	},
	connect_new_incoming : function() {
		if (this.new_incoming) {
			// we already have one new incoming and are waiting for the
			// main one to shut down

			if (this.new_incoming.readyState == 4) {
			// someone is too fast for us.
			// TODO: we have to check for data in new_incoming,
			// not sure what to do with it. we can probably savely
			// parse it in case of atoms.
				meteor.debug("New connection already finished.\n");
			} else return this.connect_incoming();
		}

		meteor.debug("Connecting new incoming.\n");

		var xhr = new XMLHttpRequest();
		this.new_incoming = xhr;
		xhr.pos = 0;

		xhr.open("POST", UTIL.make_url(this.url, this.vars), true);
		// both opera and IE dont handle binary data correctly.
		if (!window.opera && navigator.appName != 'Microsoft Internet Explorer') {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
		}
		//xhr.overrideMimeType("text/plain; charset=ISO-8859-1");
		if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain; charset=x-user-defined');
		xhr.onreadystatechange = this.new_incoming_state_change;
		xhr.meteor = this;
		xhr.send("");
	},
	set_nonblocking : function() {
		this.async = true;
		this.outgoing.async = true;
		this.outgoing.onreadystatechange = outgoing_state_change;
	},
	set_blocking : function() {
		this.async = false;
		this.outgoing.onreadystatechange = null;
		this.outgoing.async = false;
	},
	incoming_state_change : function() {
		var con = this.meteor;
		var status;

		if (!con) {
			meteor.debug("xhr lost connection to reality.");
			return;
		}
		if (this.readyState >= 3) {
			//this.readyState = 2;

			// workaround for IE
			try {
				status = this.status;
			} catch(e) {
				// this is ie country
				// this is ie
				meteor.debug("fucking ie");
			}

			if (status == 200) {
				var length = this.responseBody ? this.responseBody.length : this.responseText.length;

				if (length > this.pos) {
					meteor.debug((length-this.pos)+" bytes received in readyState "+this.readyState);
					var str;

					try {
						if (window.opera) {
							str = this.responseText.slice(this.pos);
						} else if (this.responseBody) {
							str = this.responseBody.join("");
						} else {
							str = this.responseText.slice(this.pos);
							var t = str.split("");
							for (var i = 0; i < str.length; i++) {
								t[i] = t[i].charCodeAt(0) & 0xff;
							}
							str = String.fromCharCode.apply(window, t);
						}

						if (con.callback.obj) {
							con.callback.call(con.callback.obj, str);
						} else {
							con.callback(str);
						}
					} catch (error) {
						meteor.debug("ERROR: "+error);
					}

					this.pos = length;
				}

				if (this.readyState == 4 || this.pos >= meteor.BUFFER_MAX) {
					if (this.operatimer) {
						clearTimeout(this.operatimer);
						delete this.operatimer;
					}
					if (con.reconnect) con.connect_new_incoming();
				}
			} else {
			// this throws an exception in firefox. brain
			//	con.error(this.statusText);
			}
		}
	},
	incoming_on_error : function() {
		meteor.debug("INCOMING ERROR!");
		var self = this;
		var cb = function() {
			self.meteor.connect_new_incoming();
		};
		window.setTimeout(cb, 500);
	},
	connect_incoming : function(xhr) {
		if (!xhr) {
			if (this.new_incoming) {
				xhr = this.new_incoming;
			} else throw("you need to call new_incoming() first. no this.new_incoming.");
		}

		if (this.incoming) {
			if (this.incoming.readyState != 4) {
				return;
			}

			meteor.dismantle(this.incoming);
		}

		if (this.operatimer) {
			clearTimeout(this.operatimer);
			delete this.operatimer;
		}

		xhr.onreadystatechange = this.incoming_state_change;
		xhr.onerror = this.incoming_on_error;
		meteor.debug("moved new incoming to incoming.");
		this.new_incoming = 0;
		this.incoming = xhr;
		meteor.Connection.prototype.incoming_state_change.call(xhr);

		// This code polls the xhr for new data in case opera is used. its necessary
		// because opera does not trigger an event if new data is available in state 3.
		if (window.opera) {
			var fun = function() {
				meteor.Connection.prototype.incoming_state_change.call(xhr);
			};
			this.operatimer = setInterval(fun, 100);
			meteor.debug("timer: "+this.operatimer);
		}
	},
	outgoing_state_change : function() {
		var con = this.meteor;

		if (this.readyState == 4) {

			if (this.status == 200) {
				con.connect_outgoing();
			} else {
				con.error(this.statusText);
			}
		}
	},
	connect_outgoing : function() {
		var xhr;

		if (this.outgoing) {
			this.outgoing.abort();
			xhr = this.outgoing;
		} else {
			xhr = new XMLHttpRequest();
			this.outgoing = xhr;
		}
		//this.error("outgoing state is " + xhr.readyState);

		xhr.open("POST", UTIL.make_url(this.url, this.vars), this.async);
		// we do this charset hackery because we have internal utf8 and plain ascii
		// for the rest of atom. this is supposed to be a binary transport
		if (this.async) {
		    xhr.onreadystatechange = this.outgoing_state_change;
		}
		xhr.meteor = this;
		this.ready = 1;

		if (this.buffer.length > 0) this.write();
	},
	init_state_change : function(change_event) { // fetch the client_id and go
		var con = this.meteor;
		if (this.readyState == 4) {
			if (this.status == 200) {
				con.vars["id"] = this.responseText;
				meteor.debug("got client ID " + con.vars["id"]);

				meteor.dismantle(con.init_xhr);
				delete con.init_xhr;

				con.connect_outgoing();
				con.connect_new_incoming();
			} else if (this.status == 404) {
				con.error(this.responseText);
			} else {
				con.error(this.statusText);
			}

			delete this.meteor;
			delete con.init_xhr;
		}
	},
	/**
	 * Initialize the connection. This needs to be called before any data can be sent or received.
	 */
	init : function() { // fetch the client_id and go
		var xhr = new XMLHttpRequest();
		xhr.meteor = this;
		this.reconnect = 1;
		this.init_xhr = xhr;
		//this.error("initialization state is " + xhr.readyState);

		xhr.onreadystatechange = this.init_state_change;
		xhr.meteor = this;
		xhr.open("GET", UTIL.make_url(this.url, this.vars), true);
		xhr.send("");
	},
	/**
	 * Close incoming connection and clean up cyclic references.
	 */
	close : function() {
		var list = [this.init_xhr, this.new_incoming, this.incoming, this.outgoing];
		for (var i = 0; i < list.length; i++) {
			var t = list[i];
			try {
				if (t) {
					meteor.dismantle(t);
				}
			} catch(e) { }
		}
		delete this.init_xhr;
		delete this.incoming;
		delete this.new_incoming;
		delete this.outgoing;
		delete this.callback;
		delete this.error;
	},
	/**
	 * Send some data.
	 * @param {String} data String to be sent.
	 */
	send : function(data) {
		// check for status
		this.buffer += data;

		if (this.vars["id"] && this.ready) {
		    if (!this.async) {
			this.write();
		    } else if (!this.will_write) {
			// ifdef firefox
			//this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			// endif
			var self = this;
			var cb = function() {
				self.will_write = 0;
				self.write();
			}
			this.will_write = 1;
			window.setTimeout(cb, 20);
		    }
		}
	},
	write : function() {
		if (this.outgoing.sendAsBinary) {
			this.outgoing.setRequestHeader("Content-Type", "application/octet-stream");
			this.outgoing.setRequestHeader("Content-Length", this.buffer.length);
			this.outgoing.sendAsBinary(this.buffer);
		} else {
			this.outgoing.send(this.buffer);
		}
		meteor.debug("Sending ("+this.buffer.substr(this.buffer.length-40, 39)+")\n");
		this.ready = 0;
		this.buffer = "";
	}
};
// the params handed by the user could be prototyped with a
// msg and something more
meteor.CallbackWrapper = function(params, mapping) {
	this.mapping = mapping;
	this.params = params;
};
meteor.CallbackWrapper.prototype = {
	msg : function(p, message) {
		var ok = true;
		if ((this.params.source && this.params.source != p.source())
		||  (this.params.context && this.params.context != p.v("_context"))
		||  (this.params.target && this.params.target != p.target())
		) {
			ok = false;
			meteor.debug(p.toString()+" is not the one.\n");
		}

		if (ok) {
			if (this.params.object) {
				if (this.params.cb) {
					return this.params.cb.call(this.params.object, p, message, this);
				}

				return this.params.object.msg(p, message, this);
			} else {
				return this.params.cb(p, message, this);
			}
		}
	},
	active : function() {
		return this.mapping == 0 ? 0 : 1;
	},
	unregister : function() {
		if (this.mapping == 0) return;

		var list = this.mapping.get(this.params.method);

		for (var i = 0; i < list.length; i++) {
			if (list[i] == this) {
				list.splice(i, 1);
			}
		}

		this.mapping = 0;
	}
};
<|endoftext|>


<commit_before>import Agile from './Agile'

export default Agile

export { Agile }
<commit_msg>Component install<commit_after>import Agile from './Agile'

const install = (Vue) => {
    Vue.component('agile', Agile)
}

export default {
    install
}

export {Agile}
<|endoftext|>


<commit_before>var Models = {
    Query: Backbone.Model.extend({
        defaults: {
            "filters":  {
                "free full text[filter]": {
                    name: "free full text",
                    enabled: false
                },
                "review[ptyp]": {
                    name: "review",
                    enabled: false
                },
                "comment[ptyp]": {
                    name: "comment",
                    enabled: false
                }
            },
            "days": 0,
            "term": ""
        }
    }),

    Article: Backbone.Model.extend({
        augmentors: {
            altmetric: function() {
                var model = this,
                    service = app.services.altmetric,
                    data = this.toJSON(),
                    path = service.path({ doi: data.doi, pubmed: data.pmid });

                if(!path) return;

                service.fetch(path).done(function(data) {
                    var items = service.parse(data);
                    model.metrics.add(items);
                });
            },

            scopus: function() {
                var model = this,
                    service = app.services.scopus,
                    doi = this.get("doi");

                if(!doi) return;

                service.fetch(doi).done(function(data) {
                    var item = service.parse(data);
                    if(item) model.metrics.add(item);
                });
            }
        },

        events: {
            "change:pmid": "setLinks",
            "change:doi": "setLinks"
        },

        initialize: function() {
            this.metrics = new Collections.Metrics();
            this.links = new Collections.Links({ model: Models.Link });
            this.setLinks();

            if (app.models.options.get("metrics")) {
                var model = this;
                $.each(this.augmentors, function(name, augmentor) {
                    augmentor.call(model);
                });
            }
        },

        setLinks: function() {
            var pmid = this.get("pmid");
            var doi = this.get("doi");

            var items = [
                {
                    pmid: pmid,
                    text: "Related",
                    attributes: {
                        rel: "related",
                        href: "./?term=related:" + pmid,
                        title: "Show related items",
                    }
                },

                {
                    text: "PubMed",
                    attributes: {
                        rel: "alternate",
                        href: "http://www.ncbi.nlm.nih.gov/pubmed/" + pmid,
                        title: "View in PubMed",
                        target: "_blank"
                    }
                },

                {
                    text: "Google Scholar",
                    attributes: {
                        rel: "full-text",
                        href: "http://scholar.google.com/scholar?" + (doi ? "cluster=http://dx.doi.org/" + encodeURIComponent(doi) : "q=" + encodeURIComponent(title)),
                        title: "Find in Google Scholar",
                        target: "_blank"
                    }
                },

                {
                    text: "✫ Save",
                    attributes: {
                        rel: "save",
                        href: "http://www.mendeley.com/import/?url=" + encodeURIComponent("http://www.ncbi.nlm.nih.gov/pubmed/" + pmid),
                        title: "Save to Mendeley",
                        type: "com.mendeley",
                        target: "_blank"
                    }
                },

                {
                    text: "⇣ RIS",
                    attributes: {
                        rel: "save",
                        download: "hubmed-" + pmid,
                        href: "http://pubmed.macropus.org/articles/?format=application%2Fresearch-info-systems&id=" + pmid,
                        type: "application/research-info-systems",
                        title: "Download as RIS",
                    }
                },

                {
                    text: "⇣ BibTeX",
                    attributes: {
                        rel: "save",
                        download: "hubmed-" + pmid,
                        href: "http://pubmed.macropus.org/articles/?format=text%2Fbibtex&id=" + pmid,
                        type: "text/bibtex",
                        title: "Download as BibTeX"
                    }
                }
            ];

            this.links.reset(items);
        }
    }),

    Link: Backbone.Model.extend({}),
    Info: Backbone.Model.extend({}),
    Options: Backbone.Model.extend({})
};<commit_msg>add missing title<commit_after>var Models = {
    Query: Backbone.Model.extend({
        defaults: {
            "filters":  {
                "free full text[filter]": {
                    name: "free full text",
                    enabled: false
                },
                "review[ptyp]": {
                    name: "review",
                    enabled: false
                },
                "comment[ptyp]": {
                    name: "comment",
                    enabled: false
                }
            },
            "days": 0,
            "term": ""
        }
    }),

    Article: Backbone.Model.extend({
        augmentors: {
            altmetric: function() {
                var model = this,
                    service = app.services.altmetric,
                    data = this.toJSON(),
                    path = service.path({ doi: data.doi, pubmed: data.pmid });

                if(!path) return;

                service.fetch(path).done(function(data) {
                    var items = service.parse(data);
                    model.metrics.add(items);
                });
            },

            scopus: function() {
                var model = this,
                    service = app.services.scopus,
                    doi = this.get("doi");

                if(!doi) return;

                service.fetch(doi).done(function(data) {
                    var item = service.parse(data);
                    if(item) model.metrics.add(item);
                });
            }
        },

        events: {
            "change:pmid": "setLinks",
            "change:doi": "setLinks"
        },

        initialize: function() {
            this.metrics = new Collections.Metrics();
            this.links = new Collections.Links({ model: Models.Link });
            this.setLinks();

            if (app.models.options.get("metrics")) {
                var model = this;
                $.each(this.augmentors, function(name, augmentor) {
                    augmentor.call(model);
                });
            }
        },

        setLinks: function() {
            var pmid = this.get("pmid");
            var doi = this.get("doi");
            var title = this.get("title");

            var items = [
                {
                    pmid: pmid,
                    text: "Related",
                    attributes: {
                        rel: "related",
                        href: "./?term=related:" + pmid,
                        title: "Show related items",
                    }
                },

                {
                    text: "PubMed",
                    attributes: {
                        rel: "alternate",
                        href: "http://www.ncbi.nlm.nih.gov/pubmed/" + pmid,
                        title: "View in PubMed",
                        target: "_blank"
                    }
                },

                {
                    text: "Google Scholar",
                    attributes: {
                        rel: "full-text",
                        href: "http://scholar.google.com/scholar?" + (doi ? "cluster=http://dx.doi.org/" + encodeURIComponent(doi) : "q=" + encodeURIComponent(title)),
                        title: "Find in Google Scholar",
                        target: "_blank"
                    }
                },

                {
                    text: "✫ Save",
                    attributes: {
                        rel: "save",
                        href: "http://www.mendeley.com/import/?url=" + encodeURIComponent("http://www.ncbi.nlm.nih.gov/pubmed/" + pmid),
                        title: "Save to Mendeley",
                        type: "com.mendeley",
                        target: "_blank"
                    }
                },

                {
                    text: "⇣ RIS",
                    attributes: {
                        rel: "save",
                        download: "hubmed-" + pmid,
                        href: "http://pubmed.macropus.org/articles/?format=application%2Fresearch-info-systems&id=" + pmid,
                        type: "application/research-info-systems",
                        title: "Download as RIS",
                    }
                },

                {
                    text: "⇣ BibTeX",
                    attributes: {
                        rel: "save",
                        download: "hubmed-" + pmid,
                        href: "http://pubmed.macropus.org/articles/?format=text%2Fbibtex&id=" + pmid,
                        type: "text/bibtex",
                        title: "Download as BibTeX"
                    }
                }
            ];

            this.links.reset(items);
        }
    }),

    Link: Backbone.Model.extend({}),
    Info: Backbone.Model.extend({}),
    Options: Backbone.Model.extend({})
};<|endoftext|>


<commit_before>var settings = require("./settings");

var Q = codebox.require("q");
var _ = codebox.require("hr.utils");
var commands = codebox.require("core/commands");
var rpc = codebox.require("core/rpc");
var dialogs = codebox.require("utils/dialogs");

// Commands
commands.register([
    {
        id: "corvisa.callme",
        title: "Corvisa: Call Me",
        run: function() {
            return Q()
            .then(function(r) {
                if (!settings.data.get("number")) {
                    return dialogs.prompt("Enter your phone number:");
                }
                return settings.data.get("number");
            })
            .then(function(nb) {
                settings.data.set("number", nb);
                codebox.settings.save();

                return rpc.execute("corvisa/callme", {
                    number: nb
                });
            });
        }
    },
    {
        id: "corvisa.simulator",
        title: "Corvisa: Run Simulator",
        run: function() {
            return rpc.execute("corvisa/simulator")
            .then(function(r) {
                return commands.run("terminal.open", {
                    shellId: r.shellId
                });
            });
        }
    },
    {
        id: "corvisa.test",
        title: "Corvisa: Start Test Runner",
        run: function() {
            return rpc.execute("corvisa/test")
            .then(function(r) {
                return commands.run("terminal.open", {
                    shellId: r.shellId
                });
            });
        }
    }
]);

// Replace run comman with run of corvisa simulator
var runCommand = commands.get("run.project");
runCommand.set("run", function() {
    return commands.run("corvisa.simulator");
});

codebox.menubar.createMenu({
    caption: "Corvisa Summit",
    items: [
        {
            caption: "Call Me",
            command: "corvisa.callme"
        },
        { type: "separator" },
        {
            caption: "Run Tests",
            command: "corvisa.test"
        },
        {
            caption: "Run Simulator",
            command: "run.project"
        },
        {
            caption: "Debug Application",
            command: "corvisa.debug"
        },
        { type: "separator" },
        {
            caption: "Deploy Application",
            command: "corvisa.deploy"
        },
        { type: "separator" },
        {
            caption: "Return to Dashboard",
            command: "corvisa.dashboard"
        }
    ]
});

<commit_msg>Add command to return to dashboard<commit_after>var settings = require("./settings");

var Q = codebox.require("q");
var _ = codebox.require("hr.utils");
var commands = codebox.require("core/commands");
var rpc = codebox.require("core/rpc");
var dialogs = codebox.require("utils/dialogs");

// Commands
commands.register([
    {
        id: "corvisa.callme",
        title: "Corvisa: Call Me",
        run: function() {
            return Q()
            .then(function(r) {
                if (!settings.data.get("number")) {
                    return dialogs.prompt("Enter your phone number:");
                }
                return settings.data.get("number");
            })
            .then(function(nb) {
                settings.data.set("number", nb);
                codebox.settings.save();

                return rpc.execute("corvisa/callme", {
                    number: nb
                });
            });
        }
    },
    {
        id: "corvisa.simulator",
        title: "Corvisa: Run Simulator",
        run: function() {
            return rpc.execute("corvisa/simulator")
            .then(function(r) {
                return commands.run("terminal.open", {
                    shellId: r.shellId
                });
            });
        }
    },
    {
        id: "corvisa.test",
        title: "Corvisa: Start Test Runner",
        run: function() {
            return rpc.execute("corvisa/test")
            .then(function(r) {
                return commands.run("terminal.open", {
                    shellId: r.shellId
                });
            });
        }
    },
    {
        id: "corvisa.dashboard",
        title: "Corvisa: Return to Dashboard",
        run: function() {
            window.open("https://platform.corvisacloud.com/#/home");
        }
    }
]);

// Replace run comman with run of corvisa simulator
var runCommand = commands.get("run.project");
runCommand.set("run", function() {
    return commands.run("corvisa.simulator");
});

codebox.menubar.createMenu({
    caption: "Corvisa Summit",
    items: [
        {
            caption: "Call Me",
            command: "corvisa.callme"
        },
        { type: "separator" },
        {
            caption: "Run Tests",
            command: "corvisa.test"
        },
        {
            caption: "Run Simulator",
            command: "run.project"
        },
        {
            caption: "Debug Application",
            command: "corvisa.debug"
        },
        { type: "separator" },
        {
            caption: "Deploy Application",
            command: "corvisa.deploy"
        },
        { type: "separator" },
        {
            caption: "Return to Dashboard",
            command: "corvisa.dashboard"
        }
    ]
});

<|endoftext|>