<commit_before>var oauth = require('oauth');
var qs = require('querystring');

module.exports = function(options){
	var Bird = function(options){
		var oauth_token = options.oauth_token;
		var oauth_token_secret = options.oauth_token_secret;
		this.base_url = 'http://api.twitter.com/1/';

		/**
			Util functions
		 **/
		this.consumer = (function(){
			return new oauth.OAuth(
				"https://twitter.com/oauth/request_token",
				"https://twitter.com/oauth/access_token",
				oauth_token, oauth_token_secret, "1.0A", options.callback, "HMAC-SHA1");
		})();

		this.get = function(url, req, cb){
			if (req.session.access_token && req.session.access_token_secret) {
				this.consumer.get(
					url,
					req.session.access_token,
					req.session.access_token_secret,
					function(err, data, response){
						cb(err, data, response);
					}
				);
			} else {
				cb(throw new Error('missing access token'));
			}
		};

		this.post = function(url, req, cb){
			if (req.session.access_token && req.session.access_token_secret) {
				this.consumer.post(
					url,
					req.session.access_token,
					req.session.access_token_secret,
					null,
					null,
					function(err, data, response){
						cb(err, data, response);
					}
				);
			} else {
				cb(throw new Error('missing access token'));
			}
		};

		this.send = function(url, req, type, options, cb){
			if (typeof options == 'function') {
				cb = options;
			}
			//stringify options params
			if (typeof options == 'object') {
				url += '?'+qs.stringify(options);
			}

			// use the default base url
			if(!url.match(/http/)) {
				url = this.base_url + url;
			}
			this[type](url, req, cb);
		}

		/**
			Auth functions
		**/
		this.login = function(req, cb){
			this.consumer.getOAuthRequestToken(
				function(err, oauth_token, oauth_token_secret, results){
					cb(err, oauth_token, oauth_token_secret, results);
			});
		};

		this.auth_callback = function(req, cb){
			this.consumer.getOAuthAccessToken(
				req.session.oauth_token,
				req.session.oauth_token_secret,
				req.query.oauth_verifier,
				function(err, access_token, access_token_secret, results) {
					cb(err, access_token, access_token_secret, results);
				}
			);
		};

		/**
			Routes
		**/
		var routes = {

			home_timeline : {
				url  : 'statuses/home_timeline.json',
				type : 'get'
			},

			mentions : {
				url  : 'statuses/mentions.json',
				type : 'get'
			},

			retweeted_by_me : {
				url  : 'statuses/retweeted_by_me.json',
				type : 'get'
			},

			retweeted_to_me : {
				url  : 'statuses/retweeted_by_me.json',
				type : 'get'
			},

			user_timeline : {
				url  : 'statuses/user_timeline.json',
				type : 'get'
			},

			retweeted_to_user : {
				url  : 'statuses/retweeted_to_user.json',
				type : 'get'
			},

			retweeted_by_user : {
				url  : 'statuses/retweeted_by_user.json',
				type : 'get'
			},

			tweet : {
				url  : 'statuses/update.json',
				type : 'post'
			},

			show : {
				url  : 'statuses/show.json',
				type : 'get'
			},

			retweet_ids : {
				url  : 'statuses/retweets/',
				type : 'get'
			},

			delete_tweet : {
				url  : 'statuses/destroy/',
				type : 'post'
			},

			retweet : {
				url  : 'statuses/retweet/',
				type : 'post'
			},

			oembed : {
				url  : 'statuses/oembed.json',
				type : 'post'
			},

			search : {
				url  : 'http://search.twitter.com/search.json',
				type : 'post'
			},

			direct_messages : {
				url  : 'direct_messages.json',
				type : 'get'
			},

			direct_messages_sent : {
				url  : 'direct_messages/sent.json',
				type : 'get'
			},

			direct_messages_destroy : {
				url  : 'direct_messages/destroy/',
				type : 'post'
			},

			direct_messages_new : {
				url  : 'direct_messages/new/',
				type : 'post'
			},

			direct_messages_show : {
				url  : 'direct_messages/show/',
				type : 'get'
			},

			followers : {
				url  : 'followers/ids.json',
				type : 'get'
			},

			friends : {
				url  : 'friends/ids.json',
				type : 'get'
			},

			friendships_exists : {
				url  : 'friendships/exists.json',
				type : 'get'
			},

			friendships_incomming : {
				url  : 'friendships/incomming.json',
				type : 'get'
			},

			friendships_outgoing : {
				url  : 'friendships/outgoing.json',
				type : 'get'
			},

			friendships_show : {
				url  : 'friendships/show.json',
				type : 'get'
			},

			friendships_create : {
				url  : 'friendships/create.json',
				type : 'post'
			},

			friendships_destroy : {
				url  : 'friendships/destroy.json',
				type : 'post'
			},

			friendships_lookup : {
				url  : 'friendships/lookup.json',
				type : 'get'
			},

			friendships_update : {
				url  : 'friendships/update.json',
				type : 'post'
			},

			friendships_no_retweet_ids : {
				url  : 'friendships/no_retweet_ids.json',
				type : 'get'
			},

			users_lookup : {
				url  : 'users/lookup.json',
				type : 'get'
			},

			users_search : {
				url  : 'users/search.json',
				type : 'get'
			},

			users_show : {
				url  : 'users/show.json',
				type : 'get'
			},

			users_contributees : {
				url  : 'users/contributees.json',
				type : 'get'
			},

			users_contributors : {
				url  : 'users/contributors.json',
				type : 'get'
			},

			favorites : {
				url  : 'favorites.json',
				type : 'get'
			},

			favorites_create : {
				url  : 'favorites/create/',
				type : 'post'
			},

			favorites_delete : {
				url  : 'favorites/destroy/',
				type : 'post'
			},

			account_rate_limit_status : {
				url  : 'account/rate_limit_status.json',
				type : 'get'
			},

			account_verify_credentials : {
				url  : 'account/verify_credentials.json',
				type : 'get'
			},

			acount_end_session : {
				url  : 'account/end_session.json',
				type : 'post'
			},

			account_update_profile : {
				url  : 'account/update_profile.json',
				type : 'post'
			},

			account_update_profile_background_image : {
				url  : 'account/update_profile_background_image.json',
				type : 'post'
			},

			account_update_profile_colors : {
				url  : 'account/update_profile_colors.json',
				type : 'post'
			},

			account_update_profile_image : {
				url  : 'account/update_profile_image.json',
				type : 'post'
			},

			account_totals : {
				url  : 'account/totals.json',
				type : 'get'
			},

			account_get_settings : {
				url  : 'account/settings.json',
				type : 'get'
			},

			account_update_settings : {
				url  : 'account/settings.json',
				type : 'post'
			},

			/* Undocumented APIs */

			related : {
				url  : 'related_results/show/',
				type : 'get'
			},

			tweet_summary : {
				url  : ['statuses/', '/activity/summary.json'],
				type : 'get'
			}
		}

		//use routes to proxy to send functions
		for(var r in routes) {
			if(routes.hasOwnProperty(r)) {
				this[r] = (function(){
					var url = routes[r].url;
					var type = routes[r].type;

					return function(req, options, cb) {
						//if the route is an array use the options.id to create the url
						if (typeof url !== 'string') {
							if(options.id) {
								url = routes[r].url[0] + options.id + routes[r].url[1];
								delete options.id;
							}	else {
								cb(throw new Error('missing parameter id in options'));
							}
						}

						if (typeof url == 'string' && options.id) {
							if (options.id) {
								url += options.id + '.json';
								delete options.id;
							} else {
								cb(throw new Error('missing parameter id in options'));
							}
						}

						this.send(url, req, type, options, cb);
					}
				})();
			}
		}
	};

	return new Bird(options);
};<commit_msg>converted tabs to spaces so the code is readable on github<commit_after>var oauth = require('oauth');
var qs = require('querystring');

module.exports = function(options){
  var Bird = function(options){
    var oauth_token = options.oauth_token;
    var oauth_token_secret = options.oauth_token_secret;
    this.base_url = 'http://api.twitter.com/1/';

    /**
      Util functions
     **/
    this.consumer = (function(){
      return new oauth.OAuth(
        "https://twitter.com/oauth/request_token",
        "https://twitter.com/oauth/access_token",
        oauth_token, oauth_token_secret, "1.0A", options.callback, "HMAC-SHA1");
    })();

    this.get = function(url, req, cb){
      if (req.session.access_token && req.session.access_token_secret) {
        this.consumer.get(
          url,
          req.session.access_token,
          req.session.access_token_secret,
          function(err, data, response){
            cb(err, data, response);
          }
        );
      } else {
        cb(throw new Error('missing access token'));
      }
    };

    this.post = function(url, req, cb){
      if (req.session.access_token && req.session.access_token_secret) {
        this.consumer.post(
          url,
          req.session.access_token,
          req.session.access_token_secret,
          null,
          null,
          function(err, data, response){
            cb(err, data, response);
          }
        );
      } else {
        cb(throw new Error('missing access token'));
      }
    };

    this.send = function(url, req, type, options, cb){
      if (typeof options == 'function') {
        cb = options;
      }
      //stringify options params
      if (typeof options == 'object') {
        url += '?'+qs.stringify(options);
      }

      // use the default base url
      if(!url.match(/http/)) {
        url = this.base_url + url;
      }
      this[type](url, req, cb);
    }

    /**
      Auth functions
    **/
    this.login = function(req, cb){
      this.consumer.getOAuthRequestToken(
        function(err, oauth_token, oauth_token_secret, results){
          cb(err, oauth_token, oauth_token_secret, results);
      });
    };

    this.auth_callback = function(req, cb){
      this.consumer.getOAuthAccessToken(
        req.session.oauth_token,
        req.session.oauth_token_secret,
        req.query.oauth_verifier,
        function(err, access_token, access_token_secret, results) {
          cb(err, access_token, access_token_secret, results);
        }
      );
    };

    /**
      Routes
    **/
    var routes = {

      home_timeline : {
        url  : 'statuses/home_timeline.json',
        type : 'get'
      },

      mentions : {
        url  : 'statuses/mentions.json',
        type : 'get'
      },

      retweeted_by_me : {
        url  : 'statuses/retweeted_by_me.json',
        type : 'get'
      },

      retweeted_to_me : {
        url  : 'statuses/retweeted_by_me.json',
        type : 'get'
      },

      user_timeline : {
        url  : 'statuses/user_timeline.json',
        type : 'get'
      },

      retweeted_to_user : {
        url  : 'statuses/retweeted_to_user.json',
        type : 'get'
      },

      retweeted_by_user : {
        url  : 'statuses/retweeted_by_user.json',
        type : 'get'
      },

      tweet : {
        url  : 'statuses/update.json',
        type : 'post'
      },

      show : {
        url  : 'statuses/show.json',
        type : 'get'
      },

      retweet_ids : {
        url  : 'statuses/retweets/',
        type : 'get'
      },

      delete_tweet : {
        url  : 'statuses/destroy/',
        type : 'post'
      },

      retweet : {
        url  : 'statuses/retweet/',
        type : 'post'
      },

      oembed : {
        url  : 'statuses/oembed.json',
        type : 'post'
      },

      search : {
        url  : 'http://search.twitter.com/search.json',
        type : 'post'
      },

      direct_messages : {
        url  : 'direct_messages.json',
        type : 'get'
      },

      direct_messages_sent : {
        url  : 'direct_messages/sent.json',
        type : 'get'
      },

      direct_messages_destroy : {
        url  : 'direct_messages/destroy/',
        type : 'post'
      },

      direct_messages_new : {
        url  : 'direct_messages/new/',
        type : 'post'
      },

      direct_messages_show : {
        url  : 'direct_messages/show/',
        type : 'get'
      },

      followers : {
        url  : 'followers/ids.json',
        type : 'get'
      },

      friends : {
        url  : 'friends/ids.json',
        type : 'get'
      },

      friendships_exists : {
        url  : 'friendships/exists.json',
        type : 'get'
      },

      friendships_incomming : {
        url  : 'friendships/incomming.json',
        type : 'get'
      },

      friendships_outgoing : {
        url  : 'friendships/outgoing.json',
        type : 'get'
      },

      friendships_show : {
        url  : 'friendships/show.json',
        type : 'get'
      },

      friendships_create : {
        url  : 'friendships/create.json',
        type : 'post'
      },

      friendships_destroy : {
        url  : 'friendships/destroy.json',
        type : 'post'
      },

      friendships_lookup : {
        url  : 'friendships/lookup.json',
        type : 'get'
      },

      friendships_update : {
        url  : 'friendships/update.json',
        type : 'post'
      },

      friendships_no_retweet_ids : {
        url  : 'friendships/no_retweet_ids.json',
        type : 'get'
      },

      users_lookup : {
        url  : 'users/lookup.json',
        type : 'get'
      },

      users_search : {
        url  : 'users/search.json',
        type : 'get'
      },

      users_show : {
        url  : 'users/show.json',
        type : 'get'
      },

      users_contributees : {
        url  : 'users/contributees.json',
        type : 'get'
      },

      users_contributors : {
        url  : 'users/contributors.json',
        type : 'get'
      },

      favorites : {
        url  : 'favorites.json',
        type : 'get'
      },

      favorites_create : {
        url  : 'favorites/create/',
        type : 'post'
      },

      favorites_delete : {
        url  : 'favorites/destroy/',
        type : 'post'
      },

      account_rate_limit_status : {
        url  : 'account/rate_limit_status.json',
        type : 'get'
      },

      account_verify_credentials : {
        url  : 'account/verify_credentials.json',
        type : 'get'
      },

      acount_end_session : {
        url  : 'account/end_session.json',
        type : 'post'
      },

      account_update_profile : {
        url  : 'account/update_profile.json',
        type : 'post'
      },

      account_update_profile_background_image : {
        url  : 'account/update_profile_background_image.json',
        type : 'post'
      },

      account_update_profile_colors : {
        url  : 'account/update_profile_colors.json',
        type : 'post'
      },

      account_update_profile_image : {
        url  : 'account/update_profile_image.json',
        type : 'post'
      },

      account_totals : {
        url  : 'account/totals.json',
        type : 'get'
      },

      account_get_settings : {
        url  : 'account/settings.json',
        type : 'get'
      },

      account_update_settings : {
        url  : 'account/settings.json',
        type : 'post'
      },

      /* Undocumented APIs */

      related : {
        url  : 'related_results/show/',
        type : 'get'
      },

      tweet_summary : {
        url  : ['statuses/', '/activity/summary.json'],
        type : 'get'
      }
    }

    //use routes to proxy to send functions
    for(var r in routes) {
      if(routes.hasOwnProperty(r)) {
        this[r] = (function(){
          var url = routes[r].url;
          var type = routes[r].type;

          return function(req, options, cb) {
            //if the route is an array use the options.id to create the url
            if (typeof url !== 'string') {
              if(options.id) {
                url = routes[r].url[0] + options.id + routes[r].url[1];
                delete options.id;
              } else {
                cb(throw new Error('missing parameter id in options'));
              }
            }

            if (typeof url == 'string' && options.id) {
              if (options.id) {
                url += options.id + '.json';
                delete options.id;
              } else {
                cb(throw new Error('missing parameter id in options'));
              }
            }

            this.send(url, req, type, options, cb);
          }
        })();
      }
    }
  };

  return new Bird(options);
};<|endoftext|>


<commit_before>/* Snake.js

	Snake (player) class.
*/

(function(sys) {

"use strict";

/* Constructor for Snake object.
	context - 2D canvas context.
	board - Game board object.
	settings - Settings for snake object.
*/
function Snake(context, board, settings) {
	// Default parameters
	if ((context instanceof CanvasRenderingContext2D) === false) {
		throw new sys.c.GameError(
			"Parameter 'context' must be a valid 2D canvas context.");
	}
	else if ((board instanceof sys.c.Board) === false) {
		throw new sys.c.GameError(
			"Parameter 'board' must be a valid game board instance.");
	}

	/*
	 * PRIVATE VARIABLES
	*/

	// Reference to self.
	var mSelf = this,

	// 2D canvas context.
	mContext = context,

	// Reference to game board object.
	mBoard = board,

	// Array of joints (for deletion).
	mJoints = [],

	// Number of joints in the snake.
	mLength = 0,

	// Head joint.
	mHead = null,

	// Tail joint.
	mTail = null,

	// Snake line width.
	mWidth = typeof settings.width === "number" ?
		settings.width : mBoard.getSlotSize().width,

	// Snake line color.
	mLineColor = typeof settings.color === "string" ?
		settings.color : "#000000;",

	// Snake line cap shape.
	mLineCap = "round",

	// Snake line join shape.
	mLineJoin = "round",

	// Starting length (number of joints).
	mStartLength = -1,

	// Starting column for the head.
	mStartCol = -1,

	// Starting row for the head.
	mStartRow = -1,

	/* Starting direction for the snake.
		{
			axis: "x" or "y", // Axis of travel.
			incr: 1 or -1 // 1 for right or down, -1 for left or up.
		}
	*/
	mStartDirection = {
		axis: "x",
		incr: 1
	},

	// Current direction for the snake head. Same structure as mStartDirection.
	mHeadDirection = null,

	// Travel direction on the last game step.
	mLastDirection = null;

	/*
	 * PUBLIC VARIABLES
	*/

	/*
	 * PRIVILEGED FUNCTIONS
	*/

	/* Initialize the snake.
	*/
	this.init = function() {
		// Reset joints array
		clearJoints();

		// Create and connect joints from head to tail
		for (var i=0; i<mStartLength; i++) {
			mSelf.addJoint();
		}

		console.log(mSelf);
	};

	/* Returns the head joint travel direction data for the next game step.
	*/
	this.getDirection = function() {
		return sys.u.deepCopy(mHeadDirection);
	};

	/* Sets the head joint travel direction data for the next game step.
		direction - Travel direction string ("left", "right", "up", or "down").
	*/
	this.setDirection = function(direction) {
		direction = Snake.prototype.parseDirection(direction);
		mHeadDirection.axis = direction.axis;
		mHeadDirection.incr = direction.incr;
		mHead.setDirection(direction, true);
	};

	/* Adds a joint to the tail.
		Returns the new joint.
	*/
	this.addJoint = function() {
		var newJoint = new sys.c.Joint();

		// Add new joint and adjust length
		mJoints.push(newJoint);
		mLength++;

		if (mLength === 1) {
			// Set new joint as head
			mHead = newJoint;
			mHead.setSlot(mBoard.getSlot(mStartCol, mStartRow));
			mHead.setDirection(mStartDirection);
		}
		else {
			// Attach new joint to tail
			mTail.setPrev(newJoint);
			newJoint.setNext(mTail);

			// Set slot and direction (direction matches old tail)
			newJoint.setSlot(getNextSlot(mTail, true));
			newJoint.setDirection(mTail.getDirection());
		}

		// Set new joint as the tail
		mTail = newJoint;
		return mTail;
	};

	/* Moves the snake.
	*/
	this.move = function() {
		var newTail = mTail.getNext(),
			newSlot = getNextSlot(mHead);

		// Current tail becomes new head
		mHead.setNext(mTail);
		mTail.setPrev(mHead);
		mTail.setNext(null);
		newTail.setPrev(null);

		// Update links
		mHead = mTail;
		mTail = newTail;

		// Set slot for new head
		mHead.setSlot(newSlot);
		mHead.setDirection(mHeadDirection);
	};

	/* Update loop actions.
	*/
	this.update = function() {
		mContext.clearRect(0, 0, 640, 480);
		mSelf.move();
		mLastDirection = sys.u.deepCopy(mHeadDirection);
		paint();
	};

	/*
	 * PRIVATE FUNCTIONS
	*/

	/* Clears all joints.
	*/
	function clearJoints() {
		for (var i=mJoints.length-1; i>=0; i--) {
			mJoints[i].destroyJoint();
			mJoints.pop();
		}

		mLength = 0;
	}

	/* Iterates over all joints from head to tail and performs a specified
		action on each iteration.

		action - Function to run on each iteration.
			joint - Current joint that the iterator is pointing to.
		reverse - True to iterate over joints from tail to head, omit otherwise.
	*/
	function eachJoint(action, reverse) {
		var curr = mHead,
			next = "getPrev",
			i;

		if (reverse === true) {
			curr = mTail;
			next = "getNext";
		}

		for (i=0; i<mLength; i++) {
			if (typeof action === "function") {
				action(curr);
			}

			curr = curr[next]();
		}
	}

	/* Gets the column and row for an adjacent slot based on a given joint's
		direction.

		joint - Joint object for which to retrieve an adjacent slot.
		invert - True to get slot behind joint, omit for slot in front of joint.

		Returns a slot object in front of or behind specified joint (depending
			on invert flag).
	*/
	function getNextSlot(joint, invert) {
		if ((joint instanceof sys.c.Joint) === false) {
			throw new sys.c.GameError(
				"Parameter 'joint' must be a Joint object.");
		}

		// Get slot location for new joint
		var nextLoc = joint.getSlot().getLocation(),
			jointDir = joint.getDirection(),
			col = nextLoc.col,
			row = nextLoc.row;

		// Change invert to multiplier
		invert = invert === true ? -1 : 1;

		if (jointDir.axis === "x") {
			col += (jointDir.incr * invert);
		}
		else {
			row += (jointDir.incr);
		}

		return mBoard.getSlot(col, row);
	}

	/* Paint all joints.
	*/
	function paint() {
		mContext.save();
		mContext.beginPath();

		mContext.strokeStyle = mLineColor;
		mContext.lineWidth = mWidth;
		mContext.lineCap = mLineCap;
		mContext.lineJoin = mLineJoin;

		mHead.paint(true);
		eachJoint(paintJoint);

		mContext.stroke();
		mContext.restore();
	}

	/* Signals a joint to paint itself.
		joint - Joint object to be painted.
	*/
	function paintJoint(joint) {
		joint.paint();
	}

	// Initializer
	(function() {
		var startLength = settings.startLength,
			startCol = settings.startCol,
			startRow = settings.startRow;

		// Store start length
		if (typeof startLength === "number") {
			mStartLength = startLength > 0 ?
				parseInt(startLength, 10) : 5;
		}

		// Store start column
		if (typeof startCol === "number") {
			mStartCol = (startCol > -1 && startCol < mBoard.getColumns()) ?
				parseInt(startCol, 10) : 12;
		}

		// Store start row
		if (typeof startRow === "number") {
			mStartRow = (startRow > -1 && startRow < mBoard.getRows()) ?
				parseInt(startRow, 10) : 18;
		}

		// Set start, current head, and current tail directions
		mStartDirection = Snake.prototype.parseDirection(
			settings.startDirection || "right");
		mHeadDirection = sys.u.deepCopy(mStartDirection);
		mLastDirection = sys.u.deepCopy(mStartDirection);
	})();
}

/*
 * STATIC FUNCTIONS
*/

Snake.prototype = {
	/* Converts a travel direction string to a travel direction data object.
		direction - Travel direction string ("left", "right", "up", or "down").
		reference - If direction is a data object, setting reference to true
			will pass direction by reference instead of deep copying it.

		Returns the converted travel direction data object, or throws an error.
	*/
	parseDirection: function(direction, reference) {
		var obj = null;

		if (typeof direction === "string") {
			// Convert string
			direction = direction.toLowerCase();

			switch (direction) {
				case "left":
				obj = { axis: "x", incr: -1 };
				break;

				case "right":
				obj = { axis: "x", incr: 1 };
				break;

				case "up":
				obj = { axis: "y", incr: -1 };
				break;

				case "down":
				obj = { axis: "y", incr: 1 };
				break;

			}
		}
		else if (typeof direction === "object" &&
			direction.axis !== undefined && direction.incr !== undefined) {
			if (reference !== true) {
				// Copy data object
				obj = sys.u.deepCopy(direction);
			}
			else {
				// Return reference
				obj = direction;
			}
		}

		if (obj === null) {
			throw new sys.c.GameError(
				"Invalid direction string (expected 'left', 'right', 'up' " +
				"or 'down')");
		}

		return obj;
	}
};

/*
 * STATIC INITIALIZERS
*/

sys.c.Snake = Snake;

})(jsnake);
<commit_msg>Added basic keyboard input, with space bar for debugging<commit_after>/* Snake.js

	Snake (player) class.
*/

(function(sys) {

"use strict";

/* Constructor for Snake object.
	context - 2D canvas context.
	board - Game board object.
	settings - Settings for snake object.
*/
function Snake(context, board, settings) {
	// Default parameters
	if ((context instanceof CanvasRenderingContext2D) === false) {
		throw new sys.c.GameError(
			"Parameter 'context' must be a valid 2D canvas context.");
	}
	else if ((board instanceof sys.c.Board) === false) {
		throw new sys.c.GameError(
			"Parameter 'board' must be a valid game board instance.");
	}

	/*
	 * PRIVATE VARIABLES
	*/

	// Reference to self.
	var mSelf = this,

	// 2D canvas context.
	mContext = context,

	// Reference to game board object.
	mBoard = board,

	// Reference to key code constants.
	mKeys = sys.u.keys,

	// Array of joints (for deletion).
	mJoints = [],

	// Number of joints in the snake.
	mLength = 0,

	// Head joint.
	mHead = null,

	// Tail joint.
	mTail = null,

	// Snake line width.
	mWidth = typeof settings.width === "number" ?
		settings.width : mBoard.getSlotSize().width,

	// Snake line color.
	mLineColor = typeof settings.color === "string" ?
		settings.color : "#000000;",

	// Snake line cap shape.
	mLineCap = "round",

	// Snake line join shape.
	mLineJoin = "round",

	// Starting length (number of joints).
	mStartLength = -1,

	// Starting column for the head.
	mStartCol = -1,

	// Starting row for the head.
	mStartRow = -1,

	/* Starting direction for the snake.
		{
			axis: "x" or "y", // Axis of travel.
			incr: 1 or -1 // 1 for right or down, -1 for left or up.
		}
	*/
	mStartDirection = {
		axis: "x",
		incr: 1
	},

	// Current direction for the snake head. Same structure as mStartDirection.
	mHeadDirection = null,

	// Travel direction on the last game step.
	mLastDirection = null;

	/*
	 * PUBLIC VARIABLES
	*/

	/*
	 * PRIVILEGED FUNCTIONS
	*/

	/* Initialize the snake.
	*/
	this.init = function() {
		// Reset joints array
		clearJoints();

		// Create and connect joints from head to tail
		for (var i=0; i<mStartLength; i++) {
			mSelf.addJoint();
		}

		console.log(mSelf);
	};

	/* Returns the head joint travel direction data for the next game step.
	*/
	this.getDirection = function() {
		return sys.u.deepCopy(mHeadDirection);
	};

	/* Sets the head joint travel direction data for the next game step.
		direction - Travel direction string ("left", "right", "up", or "down").
	*/
	this.setDirection = function(direction) {
		direction = Snake.prototype.parseDirection(direction);
		mHeadDirection.axis = direction.axis;
		mHeadDirection.incr = direction.incr;
		mHead.setDirection(direction, true);
	};

	/* Adds a joint to the tail.
		Returns the new joint.
	*/
	this.addJoint = function() {
		var newJoint = new sys.c.Joint();

		// Add new joint and adjust length
		mJoints.push(newJoint);
		mLength++;

		if (mLength === 1) {
			// Set new joint as head
			mHead = newJoint;
			mHead.setSlot(mBoard.getSlot(mStartCol, mStartRow));
			mHead.setDirection(mStartDirection);
		}
		else {
			// Attach new joint to tail
			mTail.setPrev(newJoint);
			newJoint.setNext(mTail);

			// Set slot and direction (direction matches old tail)
			newJoint.setSlot(getNextSlot(mTail, true));
			newJoint.setDirection(mTail.getDirection());
		}

		// Set new joint as the tail
		mTail = newJoint;
		return mTail;
	};

	/* Moves the snake.
	*/
	this.move = function() {
		var newTail = mTail.getNext(),
			newSlot = getNextSlot(mHead);

		// Current tail becomes new head
		mHead.setNext(mTail);
		mTail.setPrev(mHead);
		mTail.setNext(null);
		newTail.setPrev(null);

		// Update links
		mHead = mTail;
		mTail = newTail;

		// Set slot for new head
		mHead.setSlot(newSlot);
		mHead.setDirection(mHeadDirection);
	};

	/* Update loop actions.
	*/
	this.update = function() {
		mContext.clearRect(0, 0, 640, 480);
		mSelf.move();
		mLastDirection = sys.u.deepCopy(mHeadDirection);
		paint();
	};

	/*
	 * PRIVATE FUNCTIONS
	*/

	/* Clears all joints.
	*/
	function clearJoints() {
		for (var i=mJoints.length-1; i>=0; i--) {
			mJoints[i].destroyJoint();
			mJoints.pop();
		}

		mLength = 0;
	}

	/* Iterates over all joints from head to tail and performs a specified
		action on each iteration.

		action - Function to run on each iteration.
			joint - Current joint that the iterator is pointing to.
		reverse - True to iterate over joints from tail to head, omit otherwise.
	*/
	function eachJoint(action, reverse) {
		var curr = mHead,
			next = "getPrev",
			i;

		if (reverse === true) {
			curr = mTail;
			next = "getNext";
		}

		for (i=0; i<mLength; i++) {
			if (typeof action === "function") {
				action(curr);
			}

			curr = curr[next]();
		}
	}

	/* Gets the column and row for an adjacent slot based on a given joint's
		direction.

		joint - Joint object for which to retrieve an adjacent slot.
		invert - True to get slot behind joint, omit for slot in front of joint.

		Returns a slot object in front of or behind specified joint (depending
			on invert flag).
	*/
	function getNextSlot(joint, invert) {
		if ((joint instanceof sys.c.Joint) === false) {
			throw new sys.c.GameError(
				"Parameter 'joint' must be a Joint object.");
		}

		// Get slot location for new joint
		var nextLoc = joint.getSlot().getLocation(),
			jointDir = joint.getDirection(),
			col = nextLoc.col,
			row = nextLoc.row;

		// Change invert to multiplier
		invert = invert === true ? -1 : 1;

		if (jointDir.axis === "x") {
			col += (jointDir.incr * invert);
		}
		else {
			row += (jointDir.incr);
		}

		return mBoard.getSlot(col, row);
	}

	/* Paint all joints.
	*/
	function paint() {
		mContext.save();
		mContext.beginPath();

		mContext.strokeStyle = mLineColor;
		mContext.lineWidth = mWidth;
		mContext.lineCap = mLineCap;
		mContext.lineJoin = mLineJoin;

		mHead.paint(true);
		eachJoint(paintJoint);

		mContext.stroke();
		mContext.restore();
	}

	/* Signals a joint to paint itself.
		joint - Joint object to be painted.
	*/
	function paintJoint(joint) {
		joint.paint();
	}

	/* Input handler for direction changing.
		key - Key code pressed.
	*/
	function changeDirection(key) {
		switch (key) {
			// Left
			case mKeys.A:
			case mKeys.ARROW_LEFT:
			if (mLastDirection.axis === "y") {
				mSelf.setDirection("left");
			}
			break;

			// Right
			case mKeys.D:
			case mKeys.ARROW_RIGHT:
			if (mLastDirection.axis === "y") {
				mSelf.setDirection("right");
			}
			break;

			// Up
			case mKeys.W:
			case mKeys.ARROW_UP:
			if (mLastDirection.axis === "x") {
				mSelf.setDirection("up");
			}
			break;

			// Down
			case mKeys.S:
			case mKeys.ARROW_DOWN:
			if (mLastDirection.axis === "x") {
				mSelf.setDirection("down");
			}
			break;
		}
	}

	// Initializer
	(function() {
		var startLength = settings.startLength,
			startCol = settings.startCol,
			startRow = settings.startRow,
			input = sys.g.inputManager,
			keys = sys.u.keys;

		// Store start length
		if (typeof startLength === "number") {
			mStartLength = startLength > 0 ?
				parseInt(startLength, 10) : 5;
		}

		// Store start column
		if (typeof startCol === "number") {
			mStartCol = (startCol > -1 && startCol < mBoard.getColumns()) ?
				parseInt(startCol, 10) : 12;
		}

		// Store start row
		if (typeof startRow === "number") {
			mStartRow = (startRow > -1 && startRow < mBoard.getRows()) ?
				parseInt(startRow, 10) : 18;
		}

		// Set start, current head, and current tail directions
		mStartDirection = Snake.prototype.parseDirection(
			settings.startDirection || "right");
		mHeadDirection = sys.u.deepCopy(mStartDirection);
		mLastDirection = sys.u.deepCopy(mStartDirection);

		// Attach input actions
		input.onInput(mKeys.A, "on", changeDirection, mKeys.A);
		input.onInput(mKeys.D, "on", changeDirection, mKeys.D);
		input.onInput(mKeys.W, "on", changeDirection, mKeys.W);
		input.onInput(mKeys.S, "on", changeDirection, mKeys.S);
		input.onInput(mKeys.ARROW_LEFT, "on", changeDirection,
			mKeys.ARROW_LEFT);
		input.onInput(mKeys.ARROW_RIGHT, "on", changeDirection,
			mKeys.ARROW_RIGHT);
		input.onInput(mKeys.ARROW_UP, "on", changeDirection, mKeys.ARROW_UP);
		input.onInput(mKeys.ARROW_DOWN, "on", changeDirection,
			mKeys.ARROW_DOWN);
		input.onInput(mKeys.SPACE, "on", mSelf.update);
	})();
}

/*
 * STATIC FUNCTIONS
*/

Snake.prototype = {
	/* Converts a travel direction string to a travel direction data object.
		direction - Travel direction string ("left", "right", "up", or "down").
		reference - If direction is a data object, setting reference to true
			will pass direction by reference instead of deep copying it.

		Returns the converted travel direction data object, or throws an error.
	*/
	parseDirection: function(direction, reference) {
		var obj = null;

		if (typeof direction === "string") {
			// Convert string
			direction = direction.toLowerCase();

			switch (direction) {
				case "left":
				obj = { axis: "x", incr: -1 };
				break;

				case "right":
				obj = { axis: "x", incr: 1 };
				break;

				case "up":
				obj = { axis: "y", incr: -1 };
				break;

				case "down":
				obj = { axis: "y", incr: 1 };
				break;

			}
		}
		else if (typeof direction === "object" &&
			direction.axis !== undefined && direction.incr !== undefined) {
			if (reference !== true) {
				// Copy data object
				obj = sys.u.deepCopy(direction);
			}
			else {
				// Return reference
				obj = direction;
			}
		}

		if (obj === null) {
			throw new sys.c.GameError(
				"Invalid direction string (expected 'left', 'right', 'up' " +
				"or 'down')");
		}

		return obj;
	}
};

/*
 * STATIC INITIALIZERS
*/

sys.c.Snake = Snake;

})(jsnake);
<|endoftext|>


<commit_before>/* global define */

'use strict';

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['deepmerge'], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory(require('deepmerge'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.deepmerge);
    }
}(this, function (deepmerge) { /* jshint ignore:line */
    var JSONSharp = {
        process: function (obj, context) {
            var isArrayOrObject = (typeof obj === 'object');
            if (!isArrayOrObject) {
                return obj;
            }

            var key, operation, node;
            var result = this._clone(obj);

            for (key in result) {
                if (!result.hasOwnProperty(key)) {
                    continue;
                }

                node = result[key];
                operation = this.operations[key];

                if (operation !== undefined) {
                    return this.process(this.operations[key](node, context), context);
                }

                result[key] = this.process(node);
            }
            return result;
        },
        operations: {
            '#merge': function (obj) {
                return deepmerge.apply(deepmerge, obj);
            },
            '#switch': function (obj, context) {
                var result;
                var value = context[obj['#property']];
                var options = obj['#case'];

                result = options[value];
                if (result !== undefined) {
                    return result;
                }

                result = options['#default'];
                if (result !== undefined) {
                    return result;
                }

                return undefined;
            }
        },
        _clone: function (obj) {
            return JSON.parse(JSON.stringify(obj));
        }
    };

    return {JSONSharp: JSONSharp};
}));
<commit_msg>Splitted node processing by type and limited to a single clone<commit_after>/* global define */

'use strict';

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['deepmerge'], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory(require('deepmerge'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.deepmerge);
    }
}(this, function (deepmerge) { /* jshint ignore:line */
    var JSONSharp = {
        process: function (obj, context) {
            var clone = this._clone(obj);
            return this.processNode(clone, context);
        },
        processNode: function (obj, context) {
            var objType = Object.prototype.toString.call(obj);
            var isArray = (objType === '[object Array]');
            var isObject = (objType === '[object Object]');

            if (isObject) {
                return this.processObject(obj, context);
            }
            else if (isArray) {
                return this.processArray(obj, context);
            }
            else {
                return obj;
            }
        },
        processObject: function (obj, context) {
            var key, operation;

            operation = this.getOperation(obj);
            if (operation !== undefined) {
                return this.processNode(operation.func(obj[operation.name], context), context);
            }

            for (key in obj) {
                if (!obj.hasOwnProperty(key)) {
                    continue;
                }

                obj[key] = this.processNode(obj[key]);
            }

            return obj;
        },
        processArray: function (obj, context) {
            for (var i = 0; i < obj.length; i++) {
                obj[i] = this.processNode(obj[i], context);
            }
            return obj;
        },
        getOperation: function (obj) {
            for (var key in this.operations) {
                if (this.operations.hasOwnProperty(key) && obj.hasOwnProperty(key)) {
                    return {name: key, func: this.operations[key]};
                }
            }
        },
        operations: {
            '#merge': function (obj) {
                return deepmerge.apply(deepmerge, obj);
            },
            '#switch': function (obj, context) {
                var result;
                var value = context[obj['#property']];
                var options = obj['#case'];

                result = options[value];
                if (result !== undefined) {
                    return result;
                }

                result = options['#default'];
                if (result !== undefined) {
                    return result;
                }

                return undefined;
            }
        },
        _clone: function (obj) {
            return JSON.parse(JSON.stringify(obj));
        }
    };

    return {JSONSharp: JSONSharp};
}));
<|endoftext|>


<commit_before>/*Materialized.css-i jaoks vajalik kood, et scroll efecti lisada*/
$(document).ready(function () {
    $(".button-collapse").sideNav();
    $(".parallax").parallax();

});

//et kohe alguses ei oleks näha seda elementi
$("#showdiv").hide();
//scroll effect, mis näitab või peidab scroll noolt mobiili versioonis
$(function () {
    $(window).scroll(function () {
        var scrollval = $(window).scrollTop();
        //kontrollin ekraani suurust, et triggeriks funktsiooni ainult mobiilsetel seadmetel
        if (screen.width < 500) {
            if (scrollval >= 160) {
                $("#showdiv").hide();
            } else {
                $("#showdiv").show();
            }
        } else {
            $("#showdiv").hide();
        }
    });
});

(function ($) {
    $(function () {

        //initialize all modals
        $('.modal').modal();

        //now you can open modal from code
        $('#viewQuestionnaireModal').modal('open');

        //or by click on trigger
        $('.trigger-modal').modal();

    }); // end of document ready
})(jQuery); // end of jQuery name space

// Export CSV faili
function Export(id, name) {
    if (window.confirm("Lae alla vastused CSV failina?") == true) {
        window.open("app/class/exporttocsv.php?id=" + id + '&name=' + name, '_blank');
    }
}
// Clean input funktsioon
function cleanInput(string){
    string = string.replace(/[<>{}]/g, '');
    return string;
}

// Uus küsimus tekstiväljaga
function newTextQuestion() {
  var div = document.createElement('div');

  div.classList.add("newDiv");
  div.classList.add("q");

  div.setAttribute('data-type', '0');

  var name = "random-" + parseInt(Math.random() * 1000000000);
  var input = document.createElement("input");

  input.type = "text";
  input.classList.add("text");
  input.placeholder = "Küsimuse tekst...";
  input.required = true;

  input.addEventListener("invalid", function(){
    this.setCustomValidity("\'See väli on kohustuslik!\'");
  });

  input.addEventListener("input", function(){
    this.setCustomValidity("");
  });

  var btn = document.createElement("a");
  btn.textContent = "Kustuta rida";
  btn.className = "center btn-flat waves-effect waves-light";

  div.appendChild(input);
  div.appendChild(btn);

  btn.addEventListener("click", function(){
    document.getElementById('questionnaireDiv').removeChild(div);
  });
    document.getElementById('questionnaireDiv').appendChild(div);
}

// Uus küsimus valikvastustega
function newSelectQuestion() {
    var div = document.createElement('div');

    div.classList.add("newDiv");
    div.classList.add("q");

    div.setAttribute('data-type', '2');

    var name = "random-" + parseInt(Math.random() * 1000000000);
    var input = document.createElement("input");

    input.type = "text";
    input.classList.add("text");
    input.placeholder = "Küsimuse tekst...";
    input.name = name;
    input.required = true;

    input.addEventListener("invalid", function(){
        this.setCustomValidity('See väli on kohustuslik!');
    });

    input.addEventListener("input", function(){
        this.setCustomValidity("");
    });

    div.appendChild(input);

    name = "random-" + parseInt(Math.random() * 1000000000);
    input = document.createElement("input");

    input.type = "text";
    input.classList.add("options");
    input.placeholder = "Vastused (eralda komaga)";
    input.name = name;
    input.required = true;

    input.addEventListener("invalid", function(){
        this.setCustomValidity("See väli on kohustuslik!");
    });

    input.addEventListener("input", function(){
        this.setCustomValidity("");
    });

    var btn = document.createElement("a");
    btn.textContent = "Kustuta rida";
    btn.className = "center btn-flat waves-effect waves-light";

    div.appendChild(input);
    div.appendChild(btn);

    btn.addEventListener("click", function(){
        document.getElementById('questionnaireDiv').removeChild(div);
    });
    document.getElementById('questionnaireDiv').appendChild(div);

}

// QR koodi genereerimine (QRIous abil)
function generateQrCode(id){
    var urlToQr = 'http://localhost/tarkvaraarenduse_praktika/quiz/?id='+id;
    console.log(urlToQr);
    var qr = new QRious({
          element: document.getElementById('qrcode'+id),
          value: urlToQr
    });
}

//Ajax päring, et saata PHP'le massiiv küsimustiku nimega ning küsimustega
function saveQuestionnaire() {
    var questionnaire = cleanInput(document.getElementById("newQuestionnaireName").value),
        questions = document.querySelectorAll(".q"),
        request = {
            name: questionnaire,
            quiz: []
        },
        toDbJson;

    for (var i = 0; i < questions.length; i++) {
        var question_type = questions[i].getAttribute('data-type'),
            requestQuiz = {
                type: question_type,
                name: cleanInput(questions[i].getElementsByClassName('text')[0].value
            };

        if (question_type === "2") {
            requestQuiz['options'] = questions[i].getElementsByClassName('options')[0].value.split(',');
        }

        request.quiz.push(requestQuiz);
    }

    toDbJson = JSON.stringify(request);

    console.log(toDbJson);

    $.ajax({
        type: "POST",
        url: "createquestionnaire.php",
        data: {toDbQuestionnaire: toDbJson},
        success: function(data){
            Materialize.toast('Küsimustik salvestatud. Värskendan...', 3000, 'rounded')
            setTimeout(function(){
                window.location.reload();
            }, 2500);
        }
    });
}

//Ajax päring, et saata PHP'le küsimustiku ID et staatust muuta
function changeStatus(quizId) {
    console.log(quizId);
    $.ajax({
        type: "POST",
        url: "changestatus.php",
        data: {quizId: quizId},
        success: function(data){
            Materialize.toast('Küsimustiku staatus edukalt muudetud', 3000)
        }
    });
}
//Ajax päring JQueriga, et saata PHP'le massivi vastustega
$(function () {
    $('a#submitanswers').on('click', function (e) {
        e.preventDefault();

        var quizId = $('#questionnairyId').val(),
            userIp = $('#userIp').val(),
            data = {
                quizId: quizId,
                userIp: userIp,
                answers: []
            };

        $('#quizzes input:text,input:checked').each(function () {
            var input = $(this),
                items = {
                    id: '',
                    value: '',
                };
            //validate if input is not empty? before posting
            if (input.attr('type') == 'radio') {
                items['id'] = input.data('questionId');
                items['value'] = cleanInput($(this).next("label").html());
            } else {
                items['id'] = input.attr('id');
                items['value'] = cleanInput(input.val());
            }
            data.answers.push(items)
        });

        console.log(data);

        $.ajax({
            type: "POST",
            url: "saveanswers.php",
            data: {answeredQuestions: JSON.stringify(data)},
            success: function(data){
                Materialize.toast('Vastused salvestatud. Redigeerin...', 3000, 'rounded')
                setTimeout(function(){
                    window.location = "http://localhost/tarkvaraarenduse_praktika/aitah.html";
                }, 2500);
            }
         });
    });
});

// jquery sortable
$(function () {
    $("#questionnaireDiv").sortable();
    $("#questionnaireDiv").disableSelection();
});

<commit_msg>cleanInput() function<commit_after>/*Materialized.css-i jaoks vajalik kood, et scroll efecti lisada*/
$(document).ready(function () {
    $(".button-collapse").sideNav();
    $(".parallax").parallax();

});

//et kohe alguses ei oleks näha seda elementi
$("#showdiv").hide();
//scroll effect, mis näitab või peidab scroll noolt mobiili versioonis
$(function () {
    $(window).scroll(function () {
        var scrollval = $(window).scrollTop();
        //kontrollin ekraani suurust, et triggeriks funktsiooni ainult mobiilsetel seadmetel
        if (screen.width < 500) {
            if (scrollval >= 160) {
                $("#showdiv").hide();
            } else {
                $("#showdiv").show();
            }
        } else {
            $("#showdiv").hide();
        }
    });
});

(function ($) {
    $(function () {

        //initialize all modals
        $('.modal').modal();

        //now you can open modal from code
        $('#viewQuestionnaireModal').modal('open');

        //or by click on trigger
        $('.trigger-modal').modal();

    }); // end of document ready
})(jQuery); // end of jQuery name space

// Export CSV faili
function Export(id, name) {
    if (window.confirm("Lae alla vastused CSV failina?") == true) {
        window.open("app/class/exporttocsv.php?id=" + id + '&name=' + name, '_blank');
    }
}
// Clean input funktsioon
function cleanInput(string){
    string = string.replace(/[<>{}]/g, '');
    return string;
}

// Uus küsimus tekstiväljaga
function newTextQuestion() {
  var div = document.createElement('div');

  div.classList.add("newDiv");
  div.classList.add("q");

  div.setAttribute('data-type', '0');

  var name = "random-" + parseInt(Math.random() * 1000000000);
  var input = document.createElement("input");

  input.type = "text";
  input.classList.add("text");
  input.placeholder = "Küsimuse tekst...";
  input.required = true;

  input.addEventListener("invalid", function(){
    this.setCustomValidity("\'See väli on kohustuslik!\'");
  });

  input.addEventListener("input", function(){
    this.setCustomValidity("");
  });

  var btn = document.createElement("a");
  btn.textContent = "Kustuta rida";
  btn.className = "center btn-flat waves-effect waves-light";

  div.appendChild(input);
  div.appendChild(btn);

  btn.addEventListener("click", function(){
    document.getElementById('questionnaireDiv').removeChild(div);
  });
    document.getElementById('questionnaireDiv').appendChild(div);
}

// Uus küsimus valikvastustega
function newSelectQuestion() {
    var div = document.createElement('div');

    div.classList.add("newDiv");
    div.classList.add("q");

    div.setAttribute('data-type', '2');

    var name = "random-" + parseInt(Math.random() * 1000000000);
    var input = document.createElement("input");

    input.type = "text";
    input.classList.add("text");
    input.placeholder = "Küsimuse tekst...";
    input.name = name;
    input.required = true;

    input.addEventListener("invalid", function(){
        this.setCustomValidity('See väli on kohustuslik!');
    });

    input.addEventListener("input", function(){
        this.setCustomValidity("");
    });

    div.appendChild(input);

    name = "random-" + parseInt(Math.random() * 1000000000);
    input = document.createElement("input");

    input.type = "text";
    input.classList.add("options");
    input.placeholder = "Vastused (eralda komaga)";
    input.name = name;
    input.required = true;

    input.addEventListener("invalid", function(){
        this.setCustomValidity("See väli on kohustuslik!");
    });

    input.addEventListener("input", function(){
        this.setCustomValidity("");
    });

    var btn = document.createElement("a");
    btn.textContent = "Kustuta rida";
    btn.className = "center btn-flat waves-effect waves-light";

    div.appendChild(input);
    div.appendChild(btn);

    btn.addEventListener("click", function(){
        document.getElementById('questionnaireDiv').removeChild(div);
    });
    document.getElementById('questionnaireDiv').appendChild(div);

}

// QR koodi genereerimine (QRIous abil)
function generateQrCode(id){
    var urlToQr = 'http://localhost/tarkvaraarenduse_praktika/quiz/?id='+id;
    console.log(urlToQr);
    var qr = new QRious({
          element: document.getElementById('qrcode'+id),
          value: urlToQr
    });
}

//Ajax päring, et saata PHP'le massiiv küsimustiku nimega ning küsimustega
function saveQuestionnaire() {
    var questionnaire = cleanInput(document.getElementById("newQuestionnaireName").value),
        questions = document.querySelectorAll(".q"),
        request = {
            name: questionnaire,
            quiz: []
        },
        toDbJson;

    for (var i = 0; i < questions.length; i++) {
        var question_type = questions[i].getAttribute('data-type'),
            requestQuiz = {
                type: question_type,
                name: cleanInput(questions[i].getElementsByClassName('text')[0].value
            };

        if (question_type === "2") {
            requestQuiz['options'] = questions[i].getElementsByClassName('options')[0].value.split(',');
        }

        request.quiz.push(requestQuiz);
    }

    toDbJson = JSON.stringify(request);

    console.log(toDbJson);

    $.ajax({
        type: "POST",
        url: "createquestionnaire.php",
        data: {toDbQuestionnaire: toDbJson},
        success: function(data){
            Materialize.toast('Küsimustik salvestatud. Värskendan...', 3000, 'rounded')
            setTimeout(function(){
                window.location.reload();
            }, 2500);
        }
    });
}

//Ajax päring, et saata PHP'le küsimustiku ID et staatust muuta
function changeStatus(quizId) {
    console.log(quizId);
    $.ajax({
        type: "POST",
        url: "changestatus.php",
        data: {quizId: quizId},
        success: function(data){
            Materialize.toast('Küsimustiku staatus edukalt muudetud', 3000)
        }
    });
}
//Ajax päring JQueriga, et saata PHP'le massivi vastustega
$(function () {
    $('a#submitanswers').on('click', function (e) {
        e.preventDefault();

        var quizId = $('#questionnairyId').val(),
            userIp = $('#userIp').val(),
            data = {
                quizId: quizId,
                userIp: userIp,
                answers: []
            };

        $('#quizzes input:text,input:checked').each(function () {
            var input = $(this),
                items = {
                    id: '',
                    value: '',
                };
            //validate if input is not empty? before posting
            if (input.attr('type') == 'radio') {
                items['id'] = input.data('questionId');
                items['value'] = cleanInput($(this).next("label").html());
            } else {
                items['id'] = input.attr('id');
                items['value'] = cleanInput(input.val());
            }
            data.answers.push(items)
        });

        console.log(data);

        $.ajax({
            type: "POST",
            url: "saveanswers.php",
            data: {answeredQuestions: JSON.stringify(data)},
            success: function(data){
                Materialize.toast('Vastused salvestatud. Redigeerin...', 3000, 'rounded')
                setTimeout(function(){
                    window.location = "http://localhost/tarkvaraarenduse_praktika/aitah.html";
                }, 2500);
            }
         });
    });
});

// jquery sortable

$(function () {
    $("#questionnaireDiv").sortable();
    $("#questionnaireDiv").disableSelection();
});

<|endoftext|>


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

(typeof require !== "undefined") &&  require("../../src/foam.js");

/**
  Serves to generate executable examples and unit test cases.
*/
foam.CLASS({
  package: 'test.helpers',
  name: 'Exemplar',

  imports: [ 'exemplarRegistry as registry' ],

  properties: [
    {
      /** this Example's unique name */
      name: 'name',
      required: true
    },
    {
      /** a one-line description of the example */
      name: 'description'
    },
    {
      /** Examplars to load and execute before this one. Output code will
        be the merged result of all dependencies. */
      class: 'StringArray',
      name: 'dependencies'
    },
    {
      /** Set to true if your code is a function that returns a promise */
      class: 'Boolean',
      name: 'isAsync',
      value: false
    },
    {
      /** The code for this example. This should be either bare code, or a
        function that returns a promise if async. */
      class: 'String',
      name: 'code',
      adapt: function(old, nu) {
        if ( foam.Function.is(nu) ) {
          var matches = nu.toString().match(/function\s*(async)?\(\s*\)\s*\{((?:.|\n)*)\}/);
          if ( matches[1] ) this.isAsync = true;
          return matches[2];
        }
        return nu.replace('\t', '  ');
      }
    },
    {
      /** Is true if any dependencies are async.
        @private */
      class: 'Boolean',
      name: 'hasAsyncDeps_',
      hidden: true,
      expression: function(dependencies) {
        var self = this;
        var ret = false;
        self.dependencies && self.dependencies.forEach(function(depName) {
          var dep = self.registry.lookup(depName);
          if ( dep.hasAsyncDeps_ || dep.isAsync ) {
            ret = true;
            return true;
          }
        });
        return ret;
      }
    },
  ],

  methods: [
    function init() {
      this.registry.register(this);
    },

    function generateExample() {
      var indent = { level: 0 };
      var ret = "";
      var self = this;
      var tabs = "";
      for ( var i = 0; i < indent.level; i++) { tabs += '  '; }

      // flatten dependencies
      var deps = this.flattenDependencies();

      deps.sync.forEach(function(dep) {
        ret += dep.outputSelf(indent);
      });

      if ( deps.async.length ) {
        indent.level += 1;
        ret += tabs + "Promise.resolve({\n";
      }
      deps.async.forEach(function(dep) {
        ret += tabs + "}).then(function() {\n";
        ret += dep.outputSelf(indent);
      });
      if ( deps.async.length ) {
        ret += tabs + "}).then(function() {\n";
      }

      ret += self.outputSelf(indent);

      // inner enclosing end
      if ( deps.async.length ) {
        ret += tabs + '})\n';
        indent.level -= 1;
      }

      return ret;
    },

    function outputSelf(indent) {

      var ret = "\n";
      var lines = this.code.split('\n');
      var tabs = "";
      for ( var i = 0; i < indent.level; i++) { tabs += '  '; }

      ret += tabs + '//=====================================================\n';
      ret += tabs + '// ' + this.name + '\n';
      ret += tabs + '// ' + this.description + '\n';
      ret += tabs + '//=====================================================\n';

      // only keep source indent relative to first line
      var firstLineIndent = -1;
      lines.forEach(function(line) {

        if ( firstLineIndent < 0 ) {
          // skip initial blank lines
          var trimmed = line.trim();
          if ( trimmed.length == 0 ) return;
          firstLineIndent = line.indexOf(trimmed);
          line = trimmed;
        } else {
          line = line.slice(firstLineIndent);
        }
        ret += tabs + line + '\n';
      });

      ret += "\n";

      return ret;
    },

    function flattenDependencies(depsLoaded) {
      var self = this;
      if ( ! self.dependencies ) {
        return {
          sync: [],
          async: []
        };
      } else {
        depsLoaded = depsLoaded || {};

        var syncDeps = [];
        var asyncDeps = [];

        self.dependencies.forEach(function(depName) {
          if ( depsLoaded[depName] ) return; // only load each dependency once

          var dep = self.registry.lookup(depName);
          var depDeps = dep.flattenDependencies(depsLoaded);

          syncDeps = syncDeps.concat(depDeps.sync);
          asyncDeps = asyncDeps.concat(depDeps.async);

          depsLoaded[dep.name] = true;

          if ( dep.hasAsyncDeps_ || dep.isAsync ) {
            asyncDeps.push(dep);
          } else {
            syncDeps.push(dep);
          }
        });
        return {
          sync: syncDeps,
          async: asyncDeps
        }
      }
    }

  ]
});

/**
  Serves to generate executable examples and unit test cases.
*/
foam.CLASS({
  package: 'test.helpers',
  name: 'ExemplarRegistry',

  exports: [ 'as exemplarRegistry' ],

  properties: [
    {
      name: 'registrants',
      factory: function() { return {}; }
    }
  ],

  methods: [
    function lookup(name) {
      var found = this.registrants[name];

      if ( ! found ) throw "Examplar " + name + " not found!";

      return found;
    },
    function register(ex) {
      /** Registers an examplar. Re-registering the same one is allowed, but
        two Examplars with the same name is not. */
      var prev = this.registrants[ex.name];
      if ( prev && prev !== ex ) throw "Exemplar " + ex.name + " already registered!";

      this.registrants[ex.name] = ex;
    }
  ]

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

(typeof require !== "undefined") &&  require("../../src/foam.js");

/**
  Serves to generate executable examples and unit test cases.
*/
foam.CLASS({
  package: 'test.helpers',
  name: 'Exemplar',

  imports: [ 'exemplarRegistry as registry' ],

  properties: [
    {
      /** this Example's unique name */
      name: 'name',
      required: true
    },
    {
      /** a one-line description of the example */
      name: 'description'
    },
    {
      /** Examplars to load and execute before this one. Output code will
        be the merged result of all dependencies. */
      class: 'StringArray',
      name: 'dependencies'
    },
    {
      /** Set to true if your code is a function that returns a promise */
      class: 'Boolean',
      name: 'isAsync',
      value: false
    },
    {
      /** The code for this example. This should be either bare code, or a
        function that returns a promise if async. */
      class: 'String',
      name: 'code',
      adapt: function(old, nu) {
        if ( foam.Function.isInstance(nu) ) {
          var matches = nu.toString().match(/function\s*(async)?\(\s*\)\s*\{((?:.|\n)*)\}/);
          if ( matches[1] ) this.isAsync = true;
          return matches[2].replace('\t', '  ');
        }
        return nu.replace('\t', '  ');
      }
    },
    {
      /** Unit test expectations to run after the main code. */
      class: 'String',
      name: 'postTestCode',
      adapt: function(old, nu) {
        if ( foam.Function.isInstance(nu) ) {
          var matches = nu.toString().match(/function\s*\(\s*\)\s*\{((?:.|\n)*)\}/);
          return matches[1].replace('\t', '  ');
        }
        return nu.replace('\t', '  ');
      }
    },
    {
      /** Is true if any dependencies are async.
        @private */
      class: 'Boolean',
      name: 'hasAsyncDeps_',
      hidden: true,
      expression: function(dependencies) {
        var self = this;
        var ret = false;
        self.dependencies && self.dependencies.forEach(function(depName) {
          var dep = self.registry.lookup(depName);
          if ( dep.hasAsyncDeps_ || dep.isAsync ) {
            ret = true;
            return true;
          }
        });
        return ret;
      }
    },
  ],

  methods: [
    function init() {
      this.registry.register(this);
    },

    function generateExample() {
      var indent = { level: 0 };
      var ret = "";
      var self = this;
      var tabs = "";
      for ( var i = 0; i < indent.level; i++) { tabs += '  '; }

      // flatten dependencies
      var deps = this.flattenDependencies();

      deps.sync.forEach(function(dep) {
        ret += dep.outputSelf(indent);
      });

      if ( deps.async.length ) {
        indent.level += 1;
        ret += tabs + "Promise.resolve({\n";
      }
      deps.async.forEach(function(dep) {
        ret += tabs + "}).then(function() {\n";
        ret += dep.outputSelf(indent);
      });
      if ( deps.async.length ) {
        ret += tabs + "}).then(function() {\n";
      }

      ret += self.outputSelf(indent);

      // inner enclosing end
      if ( deps.async.length ) {
        ret += tabs + '})\n';
        indent.level -= 1;
      }

      return ret;
    },

    function generateTest() {
      var exampleCode = this.generateExample();

      if ( this.hasAsyncDeps_ ) {
        exampleCode += ".then(function() {\n";
        indent.level += 1;
      }

      exampleCode += this.outputIndentedCode(indent, this.postTestCode);

      if ( this.hasAsyncDeps_ ) {
        exampleCode += "})\n";
      }

    },

    function outputSelf(indent) {

      var ret = "\n";
      var tabs = "";
      for ( var i = 0; i < indent.level; i++) { tabs += '  '; }

      ret += tabs + '//=====================================================\n';
      ret += tabs + '// ' + this.name + '\n';
      ret += tabs + '// ' + this.description + '\n';
      ret += tabs + '//=====================================================\n';

      ret += this.outputIndentedCode(indent, this.code);

      ret += "\n";

      return ret;
    },

    function outputIndentedCode(indent, code) {
      var ret = "";
      var lines = code.split('\n');
      var tabs = "";
      for ( var i = 0; i < indent.level; i++) { tabs += '  '; }

      // only keep source indent relative to first line
      var firstLineIndent = -1;
      lines.forEach(function(line) {

        if ( firstLineIndent < 0 ) {
          // skip initial blank lines
          var trimmed = line.trim();
          if ( trimmed.length == 0 ) return;
          firstLineIndent = line.indexOf(trimmed);
          line = trimmed;
        } else {
          line = line.slice(firstLineIndent);
        }
        ret += tabs + line + '\n';
      });

      return ret;
    },

    function flattenDependencies(depsLoaded) {
      var self = this;
      if ( ! self.dependencies ) {
        return {
          sync: [],
          async: []
        };
      } else {
        depsLoaded = depsLoaded || {};

        var syncDeps = [];
        var asyncDeps = [];

        self.dependencies.forEach(function(depName) {
          if ( depsLoaded[depName] ) return; // only load each dependency once

          var dep = self.registry.lookup(depName);
          var depDeps = dep.flattenDependencies(depsLoaded);

          syncDeps = syncDeps.concat(depDeps.sync);
          asyncDeps = asyncDeps.concat(depDeps.async);

          depsLoaded[dep.name] = true;

          if ( dep.hasAsyncDeps_ || dep.isAsync ) {
            asyncDeps.push(dep);
          } else {
            syncDeps.push(dep);
          }
        });
        return {
          sync: syncDeps,
          async: asyncDeps
        }
      }
    }

  ]
});

/**
  Serves to generate executable examples and unit test cases.
*/
foam.CLASS({
  package: 'test.helpers',
  name: 'ExemplarRegistry',

  exports: [ 'as exemplarRegistry' ],

  properties: [
    {
      name: 'registrants',
      factory: function() { return {}; }
    }
  ],

  methods: [
    function lookup(name) {
      var found = this.registrants[name];

      if ( ! found ) throw "Examplar " + name + " not found!";

      return found;
    },
    function register(ex) {
      /** Registers an examplar. Re-registering the same one is allowed, but
        two Examplars with the same name is not. */
      var prev = this.registrants[ex.name];
      if ( prev && prev !== ex ) throw "Exemplar " + ex.name + " already registered!";

      this.registrants[ex.name] = ex;
    }
  ]

});
<|endoftext|>


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

/**
 * @fileoverview
 * Registers a language handler for Swift
 *
 *
 * To use, include prettify.js and this file in your HTML page.
 * Then put your code in an HTML tag like
 *
(my swift code)

 * This file supports the following language extensions:
 *     lang-swift - Swift
 *
 * I used https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AboutTheLanguageReference.html
 * as the basis for this. In particular, I targeted the revision from
 * 2015-04-08. Swift is still evolving, and this was the latest version
 * available at the time. I will keep the code unoptimized to ease changes that come with new Swift standards.
 *
 * @author cerech@google.com
 */

PR['registerLangHandler'](
    PR['createSimpleLexer'](
        [
          //whitespace
          //unicodes are vertical tab, form feed, and null, respectively
          [PR['PR_PLAIN'],                /^[\s\n\r\t\u000B\u000C\u0000]+/, null, '\s\n\r\t\u000B\u000C\u0000'],
          //string literals
          [PR['PR_STRING'],               /^".*?"/, null, '"']
        ],
        [
          //integer literals
          [PR['PR_LITERAL'],              /^(?:0(?:(?:b[01_]+)|(?:o[0-7_]+)|(?:x[\da-fA-F_]+)))|(?:\d[\d_]*)/, null],
          //some other literals
          [PR['PR_LITERAL'],              /^(?:true|false|nil)\b/, null],
          //keywords
          [PR['PR_KEYWORD'],              /^\b(?:__COLUMN__|__FILE__|__FUNCTION__|__LINE__|associativity|as|break|case|class|continue|convenience|default|deinit|didSet|do|dynamic|dynamicType|enum|fallthrough|final|for|func|get|import|infix|init|inout|internal|in|is|lazy|left|let|mutating|none|nonmutating|operator|optional|override|postfix|precedence|prefix|private|protocol|Protocol|public|required|return|right|safe|self|set|static|struct|subscript|super|switch|Type|typealias|unowned|unsafe|var|weak|while|willSet)\b/, null],
          //double slash comments
          [PR['PR_COMMENT'],              /^\/\/.*?[\n\r]/, null],
          //slash star comments
          [PR['PR_COMMENT'],              /^\/\*[\s\S]*?(?:\*\/|$)/, null]
        ]),
    ['swift']);

//PR['registerLangHandler'](
//    PR['createSimpleLexer'](
//        [
//         ['opn',             /^\(+/, null, '('],
//        ['clo',             /^\)+/, null, ')'],
//       // A line comment that starts with ;
//         [PR['PR_COMMENT'],     /^;[^\r\n]*/, null, ';'],
//         // Whitespace
//         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
//         // A double quoted, possibly multi-line, string.
//         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
//        ],
//        [
//         [PR['PR_KEYWORD'],     /^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/, null],
//         [PR['PR_LITERAL'],
//          /^[+\-]?(?:[0#]x[0-9a-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[ed][+\-]?\d+)?)/i],
//         // A single quote possibly followed by a word that optionally ends with
//         // = ! or ?.
//         [PR['PR_LITERAL'],
//          /^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],
//         // A word that optionally ends with = ! or ?.
//         [PR['PR_PLAIN'],
//          /^-*(?:[a-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],
//         // A printable non-space non-special character
//         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0()\"\\\';]+/]
//        ]),
//    ['cl', 'el', 'lisp', 'lsp', 'scm', 'ss', 'rkt']);*/
<commit_msg>Fixes and improvements for Swift<commit_after>// Copyright (C) 2015 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview
 * Registers a language handler for Swift
 *
 *
 * To use, include prettify.js and this file in your HTML page.
 * Then put your code in an HTML tag like
 *
(my swift code)

 * This file supports the following language extensions:
 *     lang-swift - Swift
 *
 * I used https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AboutTheLanguageReference.html
 * as the basis for this. In particular, I targeted the revision from
 * 2015-04-08. Swift is still evolving, and this was the latest version
 * available at the time. I will keep the code unoptimized to ease changes that come with new Swift standards.
 *
 * @author cerech@google.com
 */

PR['registerLangHandler'](
    PR['createSimpleLexer'](
        [
          //whitespace
          [PR['PR_PLAIN'],                /^[ \n\r\t\v\f\0]+/, null, ' \n\r\t\v\f\0'],
          //string literals
          [PR['PR_STRING'],               /^".*?"/, null, '"']
        ],
        [
          //integer literals
          [PR['PR_LITERAL'],              /^-?(?:(?:0(?:(?:b[01][01_]*)|(?:o[0-7][0-7_]*)|(?:x[\da-fA-F][\da-fA-F_]*)))|(?:\d[\d_]*))/, null],
          //some other literals
          [PR['PR_LITERAL'],              /^(?:true|false|nil)\b/, null],
          //keywords
          [PR['PR_KEYWORD'],              /^\b(?:__COLUMN__|__FILE__|__FUNCTION__|__LINE__|associativity|as|break|case|class|continue|convenience|default|deinit|didSet|do|dynamic|dynamicType|enum|fallthrough|final|for|func|get|import|infix|init|inout|internal|in|is|lazy|left|let|mutating|none|nonmutating|operator|optional|override|postfix|precedence|prefix|private|protocol|Protocol|public|required|return|right|safe|self|set|static|struct|subscript|super|switch|Type|typealias|unowned|unsafe|var|weak|while|willSet)\b/, null],
          //double slash comments
          [PR['PR_COMMENT'],              /^\/\/.*?[\n\r]/, null],
          //slash star comments
          [PR['PR_COMMENT'],              /^\/\*[\s\S]*?(?:\*\/|$)/, null]
        ]),
    ['swift']);

//PR['registerLangHandler'](
//    PR['createSimpleLexer'](
//        [
//         ['opn',             /^\(+/, null, '('],
//        ['clo',             /^\)+/, null, ')'],
//       // A line comment that starts with ;
//         [PR['PR_COMMENT'],     /^;[^\r\n]*/, null, ';'],
//         // Whitespace
//         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
//         // A double quoted, possibly multi-line, string.
//         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
//        ],
//        [
//         [PR['PR_KEYWORD'],     /^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/, null],
//         [PR['PR_LITERAL'],
//          /^[+\-]?(?:[0#]x[0-9a-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[ed][+\-]?\d+)?)/i],
//         // A single quote possibly followed by a word that optionally ends with
//         // = ! or ?.
//         [PR['PR_LITERAL'],
//          /^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],
//         // A word that optionally ends with = ! or ?.
//         [PR['PR_PLAIN'],
//          /^-*(?:[a-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],
//         // A printable non-space non-special character
//         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0()\"\\\';]+/]
//        ]),
//    ['cl', 'el', 'lisp', 'lsp', 'scm', 'ss', 'rkt']);*/
<|endoftext|>


<commit_before>/*global assert*/
function iframeExecute(iframe, done, execute, assertCallback) {
    iframe.contentWindow.done = function () {
        try {
            assertCallback(iframe);
            done();
        } catch (e) {
            done(e);
        }
    }
    // use setTimeout so stack trace doesn't go all the way back to mocha test runner
    iframe.contentWindow.eval('origSetTimeout(' + execute.toString() + ');');
}

function createIframe(done) {
    var iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    iframe.src = './frame.html';
    iframe.onload = function () {
        done();
    };
    document.body.appendChild(iframe);
    return iframe;
}

describe('integration', function () {
    var timeoutStackDepth = 0;
    var eventHandlerStackDepth = 0;

    before(function (done) {
        // Before running any tests, throw/catch a known error
        // inside setTimeout to get a baseline expected stack
        // depth for future errors (this is different in every
        // browser).
        var iframe = createIframe(function () {
            iframe.contentWindow.setTimeout(function () {
                try {
                    iframe.contentWindow.foo();
                } catch (e) {
                    var trace = Raven.TraceKit.computeStackTrace(e);
                    timeoutStackDepth = trace.stack.length;
                }

                var doc = iframe.contentWindow.document;
                var div = doc.createElement('div');
                doc.body.appendChild(div);
                div.addEventListener('click', function () {
                    try {
                        foo();
                    } catch (e) {
                        var trace = Raven.TraceKit.computeStackTrace(e);
                        eventHandlerStackDepth = trace.stack.length;
                    }
                }, false);

                var evt;
                if (doc.createEvent) {
                    evt = doc.createEvent('MouseEvents');
                    evt.initEvent('click', true, false);
                    div.dispatchEvent(evt);
                } else if(doc.createEventObject) {
                    div.fireEvent('onclick');
                }

                document.body.removeChild(iframe);
                done();
            });
        });
    });

    beforeEach(function (done) {
        var iframe = this.iframe = createIframe(done);
    });

    afterEach(function () {
        document.body.removeChild(this.iframe);
    });

    describe('API', function () {
        it('should capture Raven.captureMessage', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    Raven.captureMessage('Hello');
                    done();
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.equal(ravenData.message, 'Hello');
                }
            );
        });

        it('should capture Raven.captureException', function (done) {
            var iframe = this.iframe;
            iframeExecute(iframe, done,
                function () {
                    setTimeout(done);

                    try {
                        foo();
                    } catch (e) {
                        Raven.captureException(e);
                    }
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.isAbove(ravenData.exception.values[0].stacktrace.frames.length, 1);
                }
            );
        });
    });
    describe('native', function () {
        it('should capture exceptions from event listeners', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    setTimeout(done);

                    var div = document.createElement('div');
                    document.body.appendChild(div);
                    div.addEventListener('click', function () {
                        foo();
                    }, false);

                    var evt;
                    if (document.createEvent) {
                        evt = document.createEvent('MouseEvents');
                        evt.initEvent('click', true, false);
                        div.dispatchEvent(evt);
                    } else if(document.createEventObject) {
                        div.fireEvent('onclick');
                    }
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.equal(ravenData.exception.values[0].stacktrace.frames.length, eventHandlerStackDepth + 1);
                }
            );
        });

        it('should transparently remove event listeners from wrapped functions', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
              function () {
                  setTimeout(done);

                  var div = document.createElement('div');
                  document.body.appendChild(div);
                  var fooFn = function () { foo(); };
                  div.addEventListener('click', fooFn, false);
                  div.removeEventListener('click', fooFn);

                  var evt;
                  if (document.createEvent) {
                      evt = document.createEvent('MouseEvents');
                      evt.initEvent('click', true, false);
                      div.dispatchEvent(evt);
                  } else if(document.createEventObject) {
                      div.fireEvent('onclick');
                  }
              },
              function () {
                  var ravenData = iframe.contentWindow.ravenData;
                  assert.equal(ravenData, null); // should never trigger error
              }
            );
        });

        it('should capture exceptions inside setTimeout', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    setTimeout(function () {
                        setTimeout(done);
                        foo();
                    }, 10);
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.equal(ravenData.exception.values[0].stacktrace.frames.length, timeoutStackDepth);
                }
            );
        });

        it('should capture exceptions inside setInterval', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    var exceptionInterval = setInterval(function () {
                        setTimeout(done);
                        clearInterval(exceptionInterval);
                        foo();
                    }, 10);
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.equal(ravenData.exception.values[0].stacktrace.frames.length, timeoutStackDepth);
                }
            );
        });

        it('should capture exceptions inside requestAnimationFrame', function (done) {
            var iframe = this.iframe;
            // needs to be visible or requestAnimationFrame won't ever fire
            iframe.style.display = 'block';

            iframeExecute(iframe, done,
                function () {
                    requestAnimationFrame(function () {
                        setTimeout(done);
                        foo();
                    });
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.equal(ravenData.exception.values[0].stacktrace.frames.length, timeoutStackDepth);
                }
            );
        });

        it('should capture exceptions from XMLHttpRequest event handlers (e.g. onreadystatechange)', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
              function () {
                  setTimeout(done);
                  var xhr = new XMLHttpRequest();
                  xhr.onreadystatechange = function () {
                      foo();
                  }
                  xhr.open('GET', 'example.json');
                  xhr.send();
              },
              function () {
                  var ravenData = iframe.contentWindow.ravenData;
                  console.log(ravenData);
                  // # of frames alter significantly between chrome/firefox & safari
                  assert.isTrue(ravenData.exception.values[0].stacktrace.frames.length >= 4);
              }
            );
        });
    });
});
<commit_msg>Better integration test assertions (assert stack depth > 1)<commit_after>/*global assert*/
function iframeExecute(iframe, done, execute, assertCallback) {
    iframe.contentWindow.done = function () {
        try {
            assertCallback(iframe);
            done();
        } catch (e) {
            done(e);
        }
    }
    // use setTimeout so stack trace doesn't go all the way back to mocha test runner
    iframe.contentWindow.eval('origSetTimeout(' + execute.toString() + ');');
}

function createIframe(done) {
    var iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    iframe.src = './frame.html';
    iframe.onload = function () {
        done();
    };
    document.body.appendChild(iframe);
    return iframe;
}

describe('integration', function () {

    beforeEach(function (done) {
        this.iframe = createIframe(done);
    });

    afterEach(function () {
        document.body.removeChild(this.iframe);
    });

    describe('API', function () {
        it('should capture Raven.captureMessage', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    Raven.captureMessage('Hello');
                    done();
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.equal(ravenData.message, 'Hello');
                }
            );
        });

        it('should capture Raven.captureException', function (done) {
            var iframe = this.iframe;
            iframeExecute(iframe, done,
                function () {
                    setTimeout(done);

                    try {
                        foo();
                    } catch (e) {
                        Raven.captureException(e);
                    }
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.isAbove(ravenData.exception.values[0].stacktrace.frames.length, 1);
                }
            );
        });
    });
    describe('native', function () {
        it('should capture exceptions from event listeners', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    setTimeout(done);

                    var div = document.createElement('div');
                    document.body.appendChild(div);
                    div.addEventListener('click', function () {
                        foo();
                    }, false);

                    var evt;
                    if (document.createEvent) {
                        evt = document.createEvent('MouseEvents');
                        evt.initEvent('click', true, false);
                        div.dispatchEvent(evt);
                    } else if(document.createEventObject) {
                        div.fireEvent('onclick');
                    }
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.isAbove(ravenData.exception.values[0].stacktrace.frames.length, 2);
                }
            );
        });

        it('should transparently remove event listeners from wrapped functions', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
              function () {
                  setTimeout(done);

                  var div = document.createElement('div');
                  document.body.appendChild(div);
                  var fooFn = function () { foo(); };
                  div.addEventListener('click', fooFn, false);
                  div.removeEventListener('click', fooFn);

                  var evt;
                  if (document.createEvent) {
                      evt = document.createEvent('MouseEvents');
                      evt.initEvent('click', true, false);
                      div.dispatchEvent(evt);
                  } else if(document.createEventObject) {
                      div.fireEvent('onclick');
                  }
              },
              function () {
                  var ravenData = iframe.contentWindow.ravenData;
                  assert.equal(ravenData, null); // should never trigger error
              }
            );
        });

        it('should capture exceptions inside setTimeout', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    setTimeout(function () {
                        setTimeout(done);
                        foo();
                    }, 10);
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.isAbove(ravenData.exception.values[0].stacktrace.frames.length, 2);
                }
            );
        });

        it('should capture exceptions inside setInterval', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
                function () {
                    var exceptionInterval = setInterval(function () {
                        setTimeout(done);
                        clearInterval(exceptionInterval);
                        foo();
                    }, 10);
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.isAbove(ravenData.exception.values[0].stacktrace.frames.length, 2);
                }
            );
        });

        it('should capture exceptions inside requestAnimationFrame', function (done) {
            var iframe = this.iframe;
            // needs to be visible or requestAnimationFrame won't ever fire
            iframe.style.display = 'block';

            iframeExecute(iframe, done,
                function () {
                    requestAnimationFrame(function () {
                        setTimeout(done);
                        foo();
                    });
                },
                function () {
                    var ravenData = iframe.contentWindow.ravenData;
                    assert.isAbove(ravenData.exception.values[0].stacktrace.frames.length, 2);
                }
            );
        });

        it('should capture exceptions from XMLHttpRequest event handlers (e.g. onreadystatechange)', function (done) {
            var iframe = this.iframe;

            iframeExecute(iframe, done,
              function () {
                  setTimeout(done);
                  var xhr = new XMLHttpRequest();
                  xhr.onreadystatechange = function () {
                      foo();
                  }
                  xhr.open('GET', 'example.json');
                  xhr.send();
              },
              function () {
                  var ravenData = iframe.contentWindow.ravenData;
                  console.log(ravenData);
                  // # of frames alter significantly between chrome/firefox & safari
                  assert.isAbove(ravenData.exception.values[0].stacktrace.frames.length, 2);
              }
            );
        });
    });
});
<|endoftext|>