<commit_before>'use strict'

/**
 * Dependencies
 * @ignore
 */
const BaseRequest = require('./BaseRequest')

/**
 * TokenRequest
 */
class TokenRequest extends BaseRequest {

  /**
   * Request Handler
   *
   * @param {HTTPRequest} req
   * @param {HTTPResponse} res
   * @param {Provider} provider
   */
  static handle (req, res, provider) {
    let request = new TokenRequest(req, res, provider)

    Promise
      .resolve(request)
      .then(request.validate)
      .then(request.authenticateClient)
      .then(request.verifyAuthorizationCode)
      .then(request.grant)
      .catch(request.internalServerError)
  }

  /**
   * Constructor
   */
  constructor (req, res, provider) {
    super(req, res, provider)
    this.params = TokenRequest.getParams(this)
    this.grantType = TokenRequest.getGrantType(this)
  }

  /**
   * Get Grant Type
   *
   * @param {TokenRequest} request
   * @return {string}
   */
  static getGrantType (request) {
    let {params} = request
    return params.grant_type
  }

  /**
   * Validate Request
   */
  validate (request) {
    let {params,provider} = request

    // MISSING GRANT TYPE
    if (!params.grant_type) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing grant type'
      })
    }

    // UNSUPPORTED GRANT TYPE
    if (!request.supportedGrantType()) {
      return request.badRequest({
        error: 'unsupported_grant_type',
        error_description: 'Unsupported grant type'
      })
    }

    // MISSING AUTHORIZATION CODE
    if (params.grant_type === 'authorization_code' && !params.code) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing authorization code'
      })
    }

    // MISSING REDIRECT URI
    if (params.grant_type === 'authorization_code' && !params.redirect_uri) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing redirect uri'
      })
    }

    // MISSING REFRESH TOKEN
    if (params.grant_type === 'refresh_token' && !params.refresh_token) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing refresh token'
      })
    }

    return Promise.resolve(request)
  }

  /**
   * Supported Grant Type
   */
  supportedGrantType () {
    let {params,provider} = this
    let supportedGrantTypes = provider.supported_grant_types
    let requestedGrantType = params.grant_type

    return supportedGrantTypes.indexOf(requestedGrantType) !== -1
  }

  /**
   * Authenticate Client
   */
  authenticateClient (request) {
    let method
    let {req} = request

    // Use HTTP Basic Authentication Method
    if (req.headers && req.headers.authorization) {
      method = 'clientSecretBasic'
    }

    // Use HTTP Post Authentication Method
    if (req.body && req.body.client_secret) {
      // Fail if multiple authentication methods are attempted
      if (method) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Must use only one authentication method'
        })
      }

      method = 'clientSecretPost'
    }

    // Use Client JWT Authentication Method
    if (req.body && req.body.client_assertion_type) {
      var type = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'

      // Fail if multiple authentication methods are attempted
      if (method) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Must use only one authentication method'
        })
      }

      // Invalid client assertion type
      if (req.body.client_assertion_type !== type) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Invalid client assertion type'
        })
      }

      // Missing client assertion
      if (!req.body.client_assertion) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Missing client assertion'
        })
      }

      method = 'clientSecretJWT'
    }

    // Missing authentication parameters
    if (!method) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Missing client credentials'
      })
    }

    // Apply the appropriate authentication method
    return this[method](request)
  }

  /**
   * Client Secret Basic Authentication
   *
   * @description
   * HTTP Basic Authentication of client using client_id and client_secret as
   * username and password.
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  clientSecretBasic (request) {
    let {req:{headers},provider} = request
    let authorization = headers.authorization.split(' ')
    let scheme = authorization[0]
    let credentials = new Buffer(authorization[1], 'base64')
      .toString('ascii')
      .split(':')
    let [id, secret] = credentials

   // MALFORMED CREDENTIALS
    if (credentials.length !== 2) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Malformed HTTP Basic credentials'
      })
    }

    // INVALID AUTHORIZATION SCHEME
    if (!/^Basic$/i.test(scheme)) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Invalid authorization scheme'
      })
    }

    // MISSING CREDENTIALS
    if (!id || !secret) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Missing client credentials'
      })
    }

    return new Promise((resolve, reject) => {
      provider.getClient(id).then(client => {

        // UNKNOWN CLIENT
        if (!client) {
          return request.unauthorized({
            error: 'unauthorized_client',
            error_description: 'Unknown client identifier'
          })
        }

        // MISMATCHING SECRET
        if (client.client_secret !== secret) {
          return request.unauthorized({
            error: 'unauthorized_client',
            error_description: 'Mismatching client secret'
          })
        }

        resolve(request)
      })
    })
  }

  /**
   * Client Secret Post
   *
   * @description
   * Authentication of client using client_id and client_secret as HTTP POST
   * body parameters.
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  clientSecretPost (request) {
    let {params: {client_id: id, client_secret: secret}, provider} = request

    // MISSING CREDENTIALS
    if (!id || !secret) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Missing client credentials'
      })
    }

    return new Promise((resolve, reject) => {
      provider.getClient(id).then(client => {

        // UNKNOWN CLIENT
        if (!client) {
          return request.unauthorized({
            error: 'unauthorized_client',
            error_description: 'Unknown client identifier'
          })
        }

        // MISMATCHING SECRET
        if (client.client_secret !== secret) {
          return request.unauthorized({
            error: 'unauthorized_client',
            error_description: 'Mismatching client secret'
          })
        }

        resolve(request)
      })
    })
  }

  /**
   * Client Secret JWT Authentication
   *
   * TODO RTFS
   */
  clientSecretJWT (request) {
    let { req: { body: { client_assertion: jwt } }, provider} = request
    let payloadB64u = jwt.split('.')[1]
    let payload = JSON.parse(base64url.decode(payloadB64u))

    if (!payload || !payload.sub) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Cannot extract client id from JWT'
      })
    }

    return new Promise((resolve, reject) => {
      provider.getClient(payload.sub).then(client => {

        if (!client) {
          return request.badRequest({
            error: 'unauthorized_client',
            error_description: 'Unknown client'
          })
        }

        if (!client.client_secret) {
          return request.badRequest({
            error: 'unauthorized_client',
            error_description: 'Missing client secret'
          })
        }

        let token = JWT.decode(jwt, client.client_secret)

        if (!token || token instanceof Error) {
          return request.badRequest({
            error: 'unauthorized_client',
            error_description: 'Invalid client JWT'
          })
        }

        // TODO validate the payload

        resolve(request)
      })
    })
  }

  /**
   * Private Key JWT Authentication
   */
  privateKeyJWT () {}

  /**
   * None Authentication
   */
  none () {}

  /**
   * Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  grant (request) {
    let {grantType} = request

    if (grantType === 'authorization_code') {
      return this.authorizationCodeGrant(request)
    }

    if (grantType === 'refresh_token') {
      return this.refreshTokenGrant(request)
    }

    if (grantType === 'client_credentials') {
      return this.clientCredentialsGrant(request)
    }

    // THIS IS SERIOUS TROUBLE
    // REQUEST VALIDATION SHOULD FILTER OUT
    // UNSUPPORTED GRANT TYPES BEFORE WE ARRIVE
    // HERE.
    throw new Error('Unsupported response type')
  }

  /**
   * Authorization Code Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  authorizationCodeGrant (request) {
    AccessToken.exchange(request).then(this.tokenResponse)
  }

  /**
   * Refresh Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  refreshTokenGrant (request) {
    AccessToken.refresh(request).then(this.tokenResponse)
  }

  /**
   * OAuth 2.0 Client Credentials Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  clientCredentialsGrant (request) {
    let {res, client: { default_max_age: expires } } = request

    AccessToken.issue(request).then(token => {
      let response = {}

      res.set({
        'Cache-Control': 'no-store',
        'Pragma': 'no-cache'
      })

      response.access_token = token
      response.token_type = 'Bearer'
      if (expires) {
        response.expires_in = expires
      }

      res.json(response)
    })
  }

  /**
   * Verify Authorization Code
   */
  verifyAuthorizationCode (request) {
    let {params, client, provider, grantType} = request

    return new Promise((resolve, reject) => {
      if (grantType === 'authorization_code') {
        provider.getAuthorizationCode(params.code).then(authorizationCode => {

          // UNKNOWN AUTHORIZATION CODE
          if (!authorizationCode) {
            return request.badRequest({
              error: 'invalid_grant',
              error_description: 'Authorization not found'
            })
          }

          // AUTHORIZATION CODE HAS BEEN PREVIOUSLY USED
          if (authorizationCode.used === true) {
            return request.badRequest({
              error: 'invalid_grant',
              error_description: 'Authorization code invalid'
            })
          }

          // AUTHORIZATION CODE IS EXPIRED
          if (authorizationCode.isExpired()) {
            return request.badRequest({
              error: 'invalid_grant',
              error_description: 'Authorization code expired'
            })
          }

          // MISMATCHING REDIRECT URI
          if (authorizationCode.redirect_uri !== params.redirect_uri) {
            return request.badRequest({
              error: 'invalid_grant',
              error_description: 'Mismatching redirect uri'
            })
          }

          // MISMATCHING CLIENT ID
          if (authorizationCode.client_id !== client._id) {
            return request.badRequest({
              error: 'invalid_grant',
              error_description: 'Mismatching client id'
            })
          }

          // TODO mismatching user id?

          request.code = authorizationCode

          // UPDATE AUTHORIZATION CODE TO REFLECT THAT IT'S BEEN USED
          authorizationCode.use().then(() => Promise.resolve(request))
        })
      } else {
        resolve(request)
      }
    })
  }
}

/**
 * Export
 */
module.exports = TokenRequest

<commit_msg>wip(TokenRequest): authorization code grant<commit_after>'use strict'

/**
 * Dependencies
 * @ignore
 */
const BaseRequest = require('./BaseRequest')
const AccessToken = require('../AccessToken')
const AuthorizationCode = require('../AuthorizationCode')
const IDToken = require('../IDToken')

/**
 * TokenRequest
 */
class TokenRequest extends BaseRequest {

  /**
   * Request Handler
   *
   * @param {HTTPRequest} req
   * @param {HTTPResponse} res
   * @param {Provider} provider
   */
  static handle (req, res, provider) {
    let request = new TokenRequest(req, res, provider)

    Promise
      .resolve(request)
      .then(request.validate)
      .then(request.authenticateClient)
      .then(request.verifyAuthorizationCode)
      .then(request.grant)
      .catch(request.internalServerError)
  }

  /**
   * Constructor
   */
  constructor (req, res, provider) {
    super(req, res, provider)
    this.params = TokenRequest.getParams(this)
    this.grantType = TokenRequest.getGrantType(this)
  }

  /**
   * Get Grant Type
   *
   * @param {TokenRequest} request
   * @return {string}
   */
  static getGrantType (request) {
    let {params} = request
    return params.grant_type
  }

  /**
   * Validate Request
   */
  validate (request) {
    let {params,provider} = request

    // MISSING GRANT TYPE
    if (!params.grant_type) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing grant type'
      })
    }

    // UNSUPPORTED GRANT TYPE
    if (!request.supportedGrantType()) {
      return request.badRequest({
        error: 'unsupported_grant_type',
        error_description: 'Unsupported grant type'
      })
    }

    // MISSING AUTHORIZATION CODE
    if (params.grant_type === 'authorization_code' && !params.code) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing authorization code'
      })
    }

    // MISSING REDIRECT URI
    if (params.grant_type === 'authorization_code' && !params.redirect_uri) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing redirect uri'
      })
    }

    // MISSING REFRESH TOKEN
    if (params.grant_type === 'refresh_token' && !params.refresh_token) {
      return request.badRequest({
        error: 'invalid_request',
        error_description: 'Missing refresh token'
      })
    }

    return Promise.resolve(request)
  }

  /**
   * Supported Grant Type
   */
  supportedGrantType () {
    let {params,provider} = this
    let supportedGrantTypes = provider.grant_types_supported
    let requestedGrantType = params.grant_type

    return supportedGrantTypes.includes(requestedGrantType)
  }

  /**
   * Authenticate Client
   */
  authenticateClient (request) {
    let method
    let {req} = request

    // Use HTTP Basic Authentication Method
    if (req.headers && req.headers.authorization) {
      method = 'clientSecretBasic'
    }

    // Use HTTP Post Authentication Method
    if (req.body && req.body.client_secret) {
      // Fail if multiple authentication methods are attempted
      if (method) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Must use only one authentication method'
        })
      }

      method = 'clientSecretPost'
    }

    // Use Client JWT Authentication Method
    if (req.body && req.body.client_assertion_type) {
      var type = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'

      // Fail if multiple authentication methods are attempted
      if (method) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Must use only one authentication method'
        })
      }

      // Invalid client assertion type
      if (req.body.client_assertion_type !== type) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Invalid client assertion type'
        })
      }

      // Missing client assertion
      if (!req.body.client_assertion) {
        return request.badRequest({
          error: 'unauthorized_client',
          error_description: 'Missing client assertion'
        })
      }

      method = 'clientSecretJWT'
    }

    // Missing authentication parameters
    if (!method) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Missing client credentials'
      })
    }

    // Apply the appropriate authentication method
    return request[method](request)
  }

  /**
   * Client Secret Basic Authentication
   *
   * @description
   * HTTP Basic Authentication of client using client_id and client_secret as
   * username and password.
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  clientSecretBasic (request) {
    let {req:{headers},provider} = request
    let authorization = headers.authorization.split(' ')
    let scheme = authorization[0]
    let credentials = new Buffer(authorization[1], 'base64')
      .toString('ascii')
      .split(':')
    let [id, secret] = credentials

   // MALFORMED CREDENTIALS
    if (credentials.length !== 2) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Malformed HTTP Basic credentials'
      })
    }

    // INVALID AUTHORIZATION SCHEME
    if (!/^Basic$/i.test(scheme)) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Invalid authorization scheme'
      })
    }

    // MISSING CREDENTIALS
    if (!id || !secret) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Missing client credentials'
      })
    }

    return provider.backend.get('clients', id).then(client => {

      // UNKNOWN CLIENT
      if (!client) {
        return request.unauthorized({
          error: 'unauthorized_client',
          error_description: 'Unknown client identifier'
        })
      }

      // MISMATCHING SECRET
      if (client.client_secret !== secret) {
        return request.unauthorized({
          error: 'unauthorized_client',
          error_description: 'Mismatching client secret'
        })
      }

      request.client = client
      return request
    })
  }

  /**
   * Client Secret Post
   *
   * @description
   * Authentication of client using client_id and client_secret as HTTP POST
   * body parameters.
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  clientSecretPost (request) {
    let {params: {client_id: id, client_secret: secret}, provider} = request

    // MISSING CREDENTIALS
    if (!id || !secret) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Missing client credentials'
      })
    }

    return new Promise((resolve, reject) => {
      provider.getClient(id).then(client => {

        // UNKNOWN CLIENT
        if (!client) {
          return request.unauthorized({
            error: 'unauthorized_client',
            error_description: 'Unknown client identifier'
          })
        }

        // MISMATCHING SECRET
        if (client.client_secret !== secret) {
          return request.unauthorized({
            error: 'unauthorized_client',
            error_description: 'Mismatching client secret'
          })
        }

        resolve(request)
      })
    })
  }

  /**
   * Client Secret JWT Authentication
   *
   * TODO RTFS
   */
  clientSecretJWT (request) {
    let { req: { body: { client_assertion: jwt } }, provider} = request
    let payloadB64u = jwt.split('.')[1]
    let payload = JSON.parse(base64url.decode(payloadB64u))

    if (!payload || !payload.sub) {
      return request.badRequest({
        error: 'unauthorized_client',
        error_description: 'Cannot extract client id from JWT'
      })
    }

    return new Promise((resolve, reject) => {
      provider.getClient(payload.sub).then(client => {

        if (!client) {
          return request.badRequest({
            error: 'unauthorized_client',
            error_description: 'Unknown client'
          })
        }

        if (!client.client_secret) {
          return request.badRequest({
            error: 'unauthorized_client',
            error_description: 'Missing client secret'
          })
        }

        let token = JWT.decode(jwt, client.client_secret)

        if (!token || token instanceof Error) {
          return request.badRequest({
            error: 'unauthorized_client',
            error_description: 'Invalid client JWT'
          })
        }

        // TODO validate the payload

        resolve(request)
      })
    })
  }

  /**
   * Private Key JWT Authentication
   */
  privateKeyJWT () {}

  /**
   * None Authentication
   */
  none () {}

  /**
   * Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  grant (request) {
    let {grantType} = request

    if (grantType === 'authorization_code') {
      return request.authorizationCodeGrant(request)
    }

    if (grantType === 'refresh_token') {
      return request.refreshTokenGrant(request)
    }

    if (grantType === 'client_credentials') {
      return request.clientCredentialsGrant(request)
    }

    // THIS IS SERIOUS TROUBLE
    // REQUEST VALIDATION SHOULD FILTER OUT
    // UNSUPPORTED GRANT TYPES BEFORE WE ARRIVE
    // HERE.
    throw new Error('Unsupported response type')
  }

  /**
   * Authorization Code Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  authorizationCodeGrant (request) {
    Promise.resolve({})
      .then(request.includeAccessToken.bind(request))
      .then(request.includeIDToken.bind(request))
      .then(response => {
        request.res.json(response)
      })
  }

  /**
   * includeAccessToken
   */
  includeAccessToken (response) {
    return AccessToken.issue(this, response)
  }

  /**
   * includeIDToken
   */
  includeIDToken (response) {
    return IDToken.issue(this, response)
  }

  /**
   * Refresh Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  refreshTokenGrant (request) {
    AccessToken.refresh(request).then(this.tokenResponse)
  }

  /**
   * OAuth 2.0 Client Credentials Grant
   *
   * @param {TokenRequest} request
   * @returns {Promise}
   */
  clientCredentialsGrant (request) {
    let {res, client: { default_max_age: expires } } = request

    AccessToken.issue(request).then(token => {
      let response = {}

      res.set({
        'Cache-Control': 'no-store',
        'Pragma': 'no-cache'
      })

      response.access_token = token
      response.token_type = 'Bearer'
      if (expires) {
        response.expires_in = expires
      }

      res.json(response)
    })
  }

  /**
   * Verify Authorization Code
   */
  verifyAuthorizationCode (request) {
    let {params, client, provider, grantType} = request

    if (grantType === 'authorization_code') {
      return provider.backend.get('codes', params.code).then(authorizationCode => {

        // UNKNOWN AUTHORIZATION CODE
        if (!authorizationCode) {
          return request.badRequest({
            error: 'invalid_grant',
            error_description: 'Authorization not found'
          })
        }

        // AUTHORIZATION CODE HAS BEEN PREVIOUSLY USED
        if (authorizationCode.used === true) {
          return request.badRequest({
            error: 'invalid_grant',
            error_description: 'Authorization code invalid'
          })
        }

        // AUTHORIZATION CODE IS EXPIRED
        if (authorizationCode.exp < Math.floor(Date.now() / 1000)) {
          return request.badRequest({
            error: 'invalid_grant',
            error_description: 'Authorization code expired'
          })
        }

        // MISMATCHING REDIRECT URI
        if (authorizationCode.redirect_uri !== params.redirect_uri) {
          return request.badRequest({
            error: 'invalid_grant',
            error_description: 'Mismatching redirect uri'
          })
        }

        // MISMATCHING CLIENT ID
        if (authorizationCode.aud !== client.client_id) {
          return request.badRequest({
            error: 'invalid_grant',
            error_description: 'Mismatching client id'
          })
        }

        // TODO mismatching user id?

        request.code = authorizationCode

        // TODO UPDATE AUTHORIZATION CODE TO REFLECT THAT IT'S BEEN USED
        //authorizationCode.use().then(() => Promise.resolve(request))
        return request
      })
    }

    return request
  }
}

/**
 * Export
 */
module.exports = TokenRequest

<|endoftext|>


<commit_before>this.cutie = this.cutie || {};

(function(module){
	var KeyCodes = {
		"UP": 38,
		"DOWN": 40,
		"LEFT": 37,
		"RIGHT": 39,
		"W": 87,
		"A": 65,
		"S": 83,
		"D": 68,
		"SHIFT": 16,
		"RETURN": 13,
		"CTRL": 17,
		"TAB": 9,
		"Q": 81,
		"E": 69,
		"Z": 90,
		"X": 88,
		"C": 67,
		"V": 86,
		"F": 70,
		"ZERO": 48,
		"ONE": 49,
		"TWO": 50,
		"THREE": 51,
		"FOUR": 52,
		"FIVE": 53,
		"SIX": 54,
		"SEVEN": 55,
		"EIGHT": 56,
		"NINE":57
	};

	module.KeyCodes = KeyCodes;
})(this.cutie);<commit_msg>Got KeyCodes documented.<commit_after>this.cutie = this.cutie || {};

(function(module){
	/**
	 * Holds a list of ASCII values for commently-accessed keybard key.s.
	 * @namespace cutie.KeyCodes
	 * @type {Object}
	 * @property {Number} UP The up arrow key on the keyboard.
	 * @property {Number} DOWN The down arrow key on the keyboard.
	 * @property {Number} LEFT The left arrow key on the keyboard.
	 * @property {Number} RIGHT The right arrow key on the keyboard.
	 * @property {Number} W The 'w' key on the keyboard.
	 * @property {Number} A The 'a' key on the keyboard.
	 * @property {Number} S The 's' key on the keyboard.
	 * @property {Number} D The 'd' key on the keyboard.
	 * @property {Number} SHIFT The shift key on the keyboard.
	 * @property {Number} RETURN The enter/return key on the keyboard.
	 * @property {Number} CTRL The control key on the keyboard.
	 * @property {Number} TAB The tab key on the keyboard.
	 * @property {Number} Q The 'q' key on the keyboard.
	 * @property {Number} E The 'e' key on the keyboard.
	 * @property {Number} Z The 'z' key on the keyboard.
	 * @property {Number} X The 'x' key on the keyboard.
	 * @property {Number} C The 'c' key on the keyboard.
	 * @property {Number} V The 'v' key on the keyboard.
	 * @property {Number} F The 'f' key on the keyboard.
	 * @property {Number} ZERO The '0' key on the keyboard.
	 * @property {Number} ONE The '1' key on the keyboard.
	 * @property {Number} TWO The '2' key on the keyboard.
	 * @property {Number} THREE The '3' key on the keyboard.
	 * @property {Number} FOUR The '4' key on the keyboard.
	 * @property {Number} FIVE The '5' key on the keyboard.
	 * @property {Number} SIX The '6' key on the keyboard.
	 * @property {Number} SEVEN The '7' key on the keyboard.
	 * @property {Number} EIGHT The '8' key on the keyboard.
	 * @property {Number} NINE The '9' key on the keyboard.
	 */
	var KeyCodes = {

		"UP": 38,
		"DOWN": 40,
		"LEFT": 37,
		"RIGHT": 39,
		"W": 87,
		"A": 65,
		"S": 83,
		"D": 68,
		"SHIFT": 16,
		"RETURN": 13,
		"CTRL": 17,
		"TAB": 9,
		"Q": 81,
		"E": 69,
		"Z": 90,
		"X": 88,
		"C": 67,
		"V": 86,
		"F": 70,
		"ZERO": 48,
		"ONE": 49,
		"TWO": 50,
		"THREE": 51,
		"FOUR": 52,
		"FIVE": 53,
		"SIX": 54,
		"SEVEN": 55,
		"EIGHT": 56,
		"NINE":57
	};

	module.KeyCodes = KeyCodes;
})(this.cutie);<|endoftext|>


<commit_before>INTERVAL = 0;
BLOB_SIZE = 10;
BLOB_DRAW_INTERVAL = 50;
SCALEFACTOR = 1.0;
BACKGROUND_COLOR = "#1D1D1D";

/* Libraries used
jQuery: http://jquery.com/ */
var map = new Image();
map.src = "./img/map.png";
var blobs = [];
var clicked = false;

/* Fit the canvas properly inside the window
1000 * 550 are the "baseline" dimensions */
function doResize()
{
	var canvas = document.getElementById("canvas");
	if (window.innerWidth * 0.55 > window.innerHeight)
	{ // height will be the limiting factor
		canvas.height = window.innerHeight * 0.95;
		canvas.width = canvas.height / 0.55;
	}
	else
	{
		canvas.width = window.innerWidth * 0.95;
		canvas.height = canvas.width * 0.55;
	}
	SCALEFACTOR = canvas.width / 1000;
}

function main()
{
	// Set the background color
	document.body.style.backgroundColor = BACKGROUND_COLOR;

	///// LISTENERS /////
	// Get rid of annoying text select
	canvas.addEventListener("selectstart", function(e)
	{
		e.preventDefault();
		return false;
	}, false);

	// Responsive to resizing
	var resizeTimer;
	$(window).resize(function()
	{
		clearTimeout(resizeTimer);
		resizeTimer = setTimeout(function()
		{
			doResize();
			var ctx = drawCanvas();
			drawBlobs(ctx);
		});
	});

	Parse.initialize("mEmM0UeRE8GX5hYcuI3Z8Yao4bT4Z7wTWyjOImvt", "G5gLmYiSdDo9YNHF56Rrom15e7VJyGYmUYlcu7f9");
	var MapPoint = Parse.Object.extend("MapPoint");

	// Click to choose a location
	canvas.addEventListener("click", function(e)
	{
		// Only let them click once
		if (clicked)
			return;
		clicked = true;
		var x = e.pageX - canvas.offsetLeft;
		var y = e.pageY - canvas.offsetTop;

		var query = new Parse.Query(MapPoint);
		// Sorts the results in descending order by the Created Date field
		query = query.addDescending("createdAt");

		query.first().then(function(object){
			object.set("x", x);
			object.set("y", y);
			console.log(object.get("x") + " " + object.get("y") + " " + object.get("color"));

			object.save(null, {
			  success: function(object) {
			    // Execute any logic that should take place after the object is saved.
			  },
			  error: function(object, error) {
			    // Execute any logic that should take place if the save fails.
			    // error is a Parse.Error with an error code and message.
			    alert("error occurred while saving");
			  }
			});

		});

		getData();
		var ctx = drawCanvas();

		// This gives enough time for the data to return
		setTimeout(function(){
			drawBlobsInterval(ctx, 0);
		}, 1000);

		// console.log(data);
	});
	///// LISTENERS /////

	doResize();
	drawCanvas();
}

/* Get the existing data from wherever */
function getData()
{
	/* PARSE */
	Parse.initialize("mEmM0UeRE8GX5hYcuI3Z8Yao4bT4Z7wTWyjOImvt", "G5gLmYiSdDo9YNHF56Rrom15e7VJyGYmUYlcu7f9");
	var MapPoint = Parse.Object.extend("MapPoint");
	var query = new Parse.Query(MapPoint);
	query.each(function(object){
  		// console.log(object.get("x") + " " + object.get("y") + " " + object.get("color"));
  		blobs.push(new Blob(object.get("x"), object.get("y"), object.get("color")));
  	});
}

/* Draws the map onto the canvas */
function drawCanvas()
{
	var canvas = document.getElementById("canvas");
	// console.log("drawCanvas called. width: " + canvas.width + " height: " + canvas.height);

	var ctx = canvas.getContext("2d");
	ctx.fillStyle = BACKGROUND_COLOR;
	ctx.fillRect(0, 0, canvas.width, canvas.height);
	// ctx.strokeStyle = "rgb(0,0,0)";
	// ctx.strokeRect(0, 0, canvas.width, canvas.height);
	ctx.drawImage(map, 0, 0, canvas.width, canvas.height);

	return ctx;
}

/* Draws the blobs immediately, no delay */
function drawBlobs(ctx)
{
	for (var i in blobs)
	{
		blobs[i].draw(ctx);
	}
}

/* Draws the blobs one by one */
function drawBlobsInterval(ctx, i)
{
	setTimeout(function(){
		blobs[i].draw(ctx);
		i++;
		if (i < blobs.length)
			drawBlobsInterval(ctx, i);
	}, BLOB_DRAW_INTERVAL);
}

//// BLOB ////

function Blob(x, y, color)
{
	// console.log("created new blob");
	this.x = parseInt(x);
	this.y = parseInt(y);
	this.color = color;
}

/* Not really a blob anymore but I'm still calling it a blob. */
Blob.prototype.draw = function(ctx)
{
	// console.log("draw a blob: " + this.color);
	ctx.fillStyle = this.color;
	ctx.strokeStyle = "#FFFFFF";

	var path = new Path2D();
	path.arc(this.x * SCALEFACTOR, this.y * SCALEFACTOR, (BLOB_SIZE - 4) * SCALEFACTOR,
		0, Math.PI * 2);
	ctx.fill(path);
	ctx.stroke(path);

	var path = new Path2D();
	path.arc(this.x * SCALEFACTOR, this.y * SCALEFACTOR, (BLOB_SIZE - 1) * SCALEFACTOR,
		0.3 * Math.PI, 0.7 * Math.PI);
	path.lineTo((this.x - BLOB_SIZE - 1) * SCALEFACTOR, (this.y + BLOB_SIZE + 3) * SCALEFACTOR);
	path.lineTo((this.x + BLOB_SIZE + 1) * SCALEFACTOR, (this.y + BLOB_SIZE + 3) * SCALEFACTOR);
	path.closePath();
	ctx.fill(path);
	ctx.stroke(path);
}<commit_msg>Fix scaling for input<commit_after>INTERVAL = 0;
BLOB_SIZE = 10;
BLOB_DRAW_INTERVAL = 50;
SCALEFACTOR = 1.0;
BACKGROUND_COLOR = "#1D1D1D";

/* Libraries used
jQuery: http://jquery.com/ */
var map = new Image();
map.src = "./img/map.png";
var blobs = [];
var clicked = false;

/* Fit the canvas properly inside the window
1000 * 550 are the "baseline" dimensions */
function doResize()
{
	var canvas = document.getElementById("canvas");
	if (window.innerWidth * 0.55 > window.innerHeight)
	{ // height will be the limiting factor
		canvas.height = window.innerHeight * 0.95;
		canvas.width = canvas.height / 0.55;
	}
	else
	{
		canvas.width = window.innerWidth * 0.95;
		canvas.height = canvas.width * 0.55;
	}
	SCALEFACTOR = canvas.width / 1000;
}

function main()
{
	// Set the background color
	document.body.style.backgroundColor = BACKGROUND_COLOR;

	///// LISTENERS /////
	// Get rid of annoying text select
	canvas.addEventListener("selectstart", function(e)
	{
		e.preventDefault();
		return false;
	}, false);

	// Responsive to resizing
	var resizeTimer;
	$(window).resize(function()
	{
		clearTimeout(resizeTimer);
		resizeTimer = setTimeout(function()
		{
			doResize();
			var ctx = drawCanvas();
			drawBlobs(ctx);
		});
	});

	Parse.initialize("mEmM0UeRE8GX5hYcuI3Z8Yao4bT4Z7wTWyjOImvt", "G5gLmYiSdDo9YNHF56Rrom15e7VJyGYmUYlcu7f9");
	var MapPoint = Parse.Object.extend("MapPoint");

	// Click to choose a location
	canvas.addEventListener("click", function(e)
	{
		// Only let them click once
		if (clicked)
			return;
		clicked = true;
		var x = e.pageX - canvas.offsetLeft;
		var y = e.pageY - canvas.offsetTop;
		x = x / canvas.width * 1000;
		y = y / canvas.height * 550;

		var query = new Parse.Query(MapPoint);
		// Sorts the results in descending order by the Created Date field
		query = query.addDescending("createdAt");

		query.first().then(function(object){
			object.set("x", x);
			object.set("y", y);
			console.log(object.get("x") + " " + object.get("y") + " " + object.get("color"));

			object.save(null, {
			  success: function(object) {
			    // Execute any logic that should take place after the object is saved.
			  },
			  error: function(object, error) {
			    // Execute any logic that should take place if the save fails.
			    // error is a Parse.Error with an error code and message.
			    alert("error occurred while saving");
			  }
			});

		});

		getData();
		var ctx = drawCanvas();

		// This gives enough time for the data to return
		setTimeout(function(){
			drawBlobsInterval(ctx, 0);
		}, 1000);

		// console.log(data);
	});
	///// LISTENERS /////

	doResize();
	drawCanvas();
}

/* Get the existing data from wherever */
function getData()
{
	/* PARSE */
	Parse.initialize("mEmM0UeRE8GX5hYcuI3Z8Yao4bT4Z7wTWyjOImvt", "G5gLmYiSdDo9YNHF56Rrom15e7VJyGYmUYlcu7f9");
	var MapPoint = Parse.Object.extend("MapPoint");
	var query = new Parse.Query(MapPoint);
	query.each(function(object){
  		// console.log(object.get("x") + " " + object.get("y") + " " + object.get("color"));
  		blobs.push(new Blob(object.get("x"), object.get("y"), object.get("color")));
  	});
}

/* Draws the map onto the canvas */
function drawCanvas()
{
	var canvas = document.getElementById("canvas");
	// console.log("drawCanvas called. width: " + canvas.width + " height: " + canvas.height);

	var ctx = canvas.getContext("2d");
	ctx.fillStyle = BACKGROUND_COLOR;
	ctx.fillRect(0, 0, canvas.width, canvas.height);
	// ctx.strokeStyle = "rgb(0,0,0)";
	// ctx.strokeRect(0, 0, canvas.width, canvas.height);
	ctx.drawImage(map, 0, 0, canvas.width, canvas.height);

	return ctx;
}

/* Draws the blobs immediately, no delay */
function drawBlobs(ctx)
{
	for (var i in blobs)
	{
		blobs[i].draw(ctx);
	}
}

/* Draws the blobs one by one */
function drawBlobsInterval(ctx, i)
{
	setTimeout(function(){
		blobs[i].draw(ctx);
		i++;
		if (i < blobs.length)
			drawBlobsInterval(ctx, i);
	}, BLOB_DRAW_INTERVAL);
}

//// BLOB ////

function Blob(x, y, color)
{
	// console.log("created new blob");
	this.x = parseInt(x);
	this.y = parseInt(y);
	this.color = color;
}

/* Not really a blob anymore but I'm still calling it a blob. */
Blob.prototype.draw = function(ctx)
{
	// console.log("draw a blob: " + this.color);
	ctx.fillStyle = this.color;
	ctx.strokeStyle = "#FFFFFF";

	var path = new Path2D();
	path.arc(this.x * SCALEFACTOR, this.y * SCALEFACTOR, (BLOB_SIZE - 4) * SCALEFACTOR,
		0, Math.PI * 2);
	ctx.fill(path);
	ctx.stroke(path);

	var path = new Path2D();
	path.arc(this.x * SCALEFACTOR, this.y * SCALEFACTOR, (BLOB_SIZE - 1) * SCALEFACTOR,
		0.3 * Math.PI, 0.7 * Math.PI);
	path.lineTo((this.x - BLOB_SIZE - 1) * SCALEFACTOR, (this.y + BLOB_SIZE + 3) * SCALEFACTOR);
	path.lineTo((this.x + BLOB_SIZE + 1) * SCALEFACTOR, (this.y + BLOB_SIZE + 3) * SCALEFACTOR);
	path.closePath();
	ctx.fill(path);
	ctx.stroke(path);
}<|endoftext|>


<commit_before><commit_msg>revert<commit_after><|endoftext|>


<commit_before><commit_msg>Update books model (not to use unique titles)<commit_after><|endoftext|>


<commit_before><commit_msg>deal w/ duplicate keys<commit_after><|endoftext|>


<commit_before>load("util.js");

var io = {
	print: function(s) {
		return print(s);
	},
	quit: function() {
		return quit();
	},
};

var connector = {
	selector: java.nio.channels.Selector.open(),
	read_buf: java.nio.ByteBuffer.allocate(1024),

	/* Register/unregister descriptors and operations with the selector.
	   These assume that only one ops of each type is registered per
	   descriptor; for example, you can't register two read events, because
	   when one is unregistered it will unregister the other. */
	register: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		var current_ops = 0;
		if (key)
			current_ops = key.interestOps();
		return sd.register(this.selector, current_ops | ops);
	},
	unregister: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		var current_ops = 0;
		if (key)
			current_ops = key.interestOps();
		return sd.register(this.selector, current_ops & ~ops);
	},

	bytebuffer_to_string: function(bb) {
		return String(new java.lang.String(java.util.Arrays.copyOf(bb.array(), bb.position()), "ISO-8859-1"));
	},
	string_to_bytebuffer: function(s) {
		return java.nio.ByteBuffer.wrap(new java.lang.String(s).getBytes("ISO-8859-1"));
	},

	/* Stringify/serialize a socket descriptor. */
	s_sd: function(sd) {
		var s = sd.socket();
		return s["class"] + "\0" + s.getInetAddress().getHostAddress() + "\0" + s.getPort();
	},

	wait_for_event: function() {
		var n;
		do {
			n = this.selector.select();
		} while (n == 0);
		var key = this.selector.selectedKeys().iterator().next();
		var channel = key.channel();
		this.selector.selectedKeys().remove(key);
		var ev = {};
		ev.sd = channel;
		if ((key.readyOps() & java.nio.channels.SelectionKey.OP_ACCEPT)
			== java.nio.channels.SelectionKey.OP_ACCEPT) {
			ev.type = "accept";
			var c = channel.socket().accept();
			ev.address = c.getInetAddress().getHostAddress();
			ev.port = c.getPort();
			ev.client = c.channel;
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_CONNECT)
			== java.nio.channels.SelectionKey.OP_CONNECT) {
			if (channel.isConnectionPending())
				channel.finishConnect();
			ev.type = "connect";
			ev.address = channel.socket().getInetAddress().getHostAddress();
			ev.port = channel.socket().getPort();
			this.unregister(channel, java.nio.channels.SelectionKey.OP_CONNECT);
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_READ)
			== java.nio.channels.SelectionKey.OP_READ) {
			ev.type = "recv";
			this.read_buf.clear();
			var n = channel.read(this.read_buf);
			if (n == -1)
				ev.data = undefined;
			else
				ev.data = this.bytebuffer_to_string(this.read_buf);
			this.unregister(channel, java.nio.channels.SelectionKey.OP_READ);
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_WRITE)
			== java.nio.channels.SelectionKey.OP_WRITE) {
			ev.type = "send";
			this.unregister(channel, java.nio.channels.SelectionKey.OP_WRITE);
		} else {
			io.print("Unknown selection key op.");
			io.quit();
		}
		return ev;
	},
	listen: function(address, port) {
		var sd = java.nio.channels.ServerSocketChannel.open();
		sd.configureBlocking(false);
		sd.socket().bind(java.net.InetSocketAddress(port));
		this.register(sd, java.nio.channels.SelectionKey.OP_ACCEPT);
		return sd;
	},
	connect: function(address, port) {
		var sd = java.nio.channels.SocketChannel.open();
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_CONNECT);
		sd.connect(java.net.InetSocketAddress(address, port));
		return sd;
	},
	recv: function(sd) {
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_READ);
		return sd;
	},
	send: function(sd, data) {
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_WRITE);
		sd.write(this.string_to_bytebuffer(data));
		return sd;
	},
	close: function(sd) {
		sd.close();
		sd.keyFor(this.selector).cancel();
	},
};

accept_pending = [];
connect_pending = [];
recv_pending = [];
send_pending = [];

function add_pending(pending_list, id, data) {
	pending_list.push({ id: id, data: data });
}

function get_pending(pending_list, id, keep) {
	for (var i = 0; i < pending_list.length; i++) {
		if (pending_list[i].id == id) {
			var pending = pending_list[i];
			if (!keep)
				pending_list.splice(i, 1)[0];
			return pending.data;
		}
	}
}

function listen(address, port, callback, userdata) {
	var sd = connector.listen(address, port);
	add_pending(accept_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function connect(address, port, callback, userdata) {
	var sd = connector.connect(address, port);
	add_pending(connect_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function recv(sd, callback, userdata) {
	var sd = connector.recv(sd);
	add_pending(recv_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function send(sd, data, callback, userdata) {
	var sd = connector.send(sd, data);
	add_pending(send_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function close(sd) {
	while (get_pending(accept_pending, sd))
		;
	while (get_pending(connect_pending, sd))
		;
	while (get_pending(recv_pending, sd))
		;
	while (get_pending(send_pending, sd))
		;
	connector.close(sd);
};

function event_loop() {
	while (true) {
		var ev = connector.wait_for_event();
		io.print("ev: " + repr(ev));
		var pending;
		switch (ev.type) {
		case "accept":
			/* accept events are persistent; don't remove pending
			   except on error. */
			pending = this.get_pending(this.accept_pending, ev.sd, true);
			args = [ev.sd, ev.address, ev.port, ev.client, pending.userdata];
			break;
		case "connect":
			pending = this.get_pending(this.connect_pending, ev.sd);
			args = [ev.sd, ev.address, ev.port, pending.userdata];
			break;
		case "recv":
			pending = this.get_pending(this.recv_pending, ev.sd);
			args = [ev.sd, ev.data, pending.userdata];
			break;
		case "send":
			pending = this.get_pending(this.send_pending, ev.sd);
			args = [ev.sd, pending.userdata];
			break;
		default:
			io.print("Unknown event type \"" + ev.type + "\".");
			io.quit();
		}
		if (pending.callback)
			pending.callback.apply(null, args);
	}
}

io.print("jscat starting.")

var LOCAL_ADDRESS = "0.0.0.0";
var LOCAL_PORT = 9998;

var DIRECTORY_ADDRESS = "localhost";
var DIRECTORY_PORT = 9999;

var peers = {};

function accept_handler(sd, address, port, client, userdata) {
	io.print("Connection from " + address + ":" + port + ".");
	/* Pass the client as userdata. */
	connect(DIRECTORY_ADDRESS, DIRECTORY_PORT, connect_handler, client);
}

function connect_handler(sd, address, port, userdata) {
	io.print("Connection to " + address + ":" + port + ".");
	peers[connector.s_sd(sd)] = userdata;
	peers[connector.s_sd(userdata)] = sd;
	/* Queue initial read events. */
	recv(sd, recv_handler, userdata);
	recv(userdata, recv_handler, sd);
}

function recv_handler(sd, data, userdata) {
	if (data == undefined) {
		close(sd);
		var peer = peers[connector.s_sd(sd)];
		if (peer) {
			connector.close(peer);
			delete peers[connector.s_sd(sd)];
			delete peers[connector.s_sd(peer)];
		}
	} else {
		send(userdata, data);
		recv(sd, recv_handler, userdata);
	}
}

listen(LOCAL_ADDRESS, LOCAL_PORT, accept_handler);

event_loop();
<commit_msg>Add an event queue. Factor out op handlers.<commit_after>load("util.js");

var io = {
	print: function(s) {
		return print(s);
	},
	quit: function() {
		return quit();
	},
};

var connector = {
	selector: java.nio.channels.Selector.open(),
	read_buf: java.nio.ByteBuffer.allocate(1024),
	events: [],

	/* Register/unregister descriptors and operations with the selector.
	   These assume that only one ops of each type is registered per
	   descriptor; for example, you can't register two read events, because
	   when one is unregistered it will unregister the other. */
	register: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		var current_ops = 0;
		if (key)
			current_ops = key.interestOps();
		return sd.register(this.selector, current_ops | ops);
	},
	unregister: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		var current_ops = 0;
		if (key)
			current_ops = key.interestOps();
		return sd.register(this.selector, current_ops & ~ops);
	},

	bytebuffer_to_string: function(bb) {
		return String(new java.lang.String(java.util.Arrays.copyOf(bb.array(), bb.position()), "ISO-8859-1"));
	},
	string_to_bytebuffer: function(s) {
		return java.nio.ByteBuffer.wrap(new java.lang.String(s).getBytes("ISO-8859-1"));
	},

	/* Stringify/serialize a socket descriptor. */
	s_sd: function(sd) {
		var s = sd.socket();
		return s["class"] + "\0" + s.getInetAddress().getHostAddress() + "\0" + s.getPort();
	},

	op_accept: function(channel) {
		var c = channel.socket().accept();
		this.events.push({
			type: "accept",
			sd: channel,
			address: c.getInetAddress().getHostAddress(),
			port: c.getPort(),
			client: c.channel,
		});
		/* For accept only, do not unregister the selection key. */
	},
	op_connect: function(channel) {
		if (channel.isConnectionPending())
			channel.finishConnect();
		this.events.push({
			type: "connect",
			sd: channel,
			address: channel.socket().getInetAddress().getHostAddress(),
			port: channel.socket().getPort(),
		});
		this.unregister(channel, java.nio.channels.SelectionKey.OP_CONNECT);
	},
	op_read: function(channel) {
		this.read_buf.clear();
		var n = channel.read(this.read_buf);
		var data;
		if (n == -1)
			data = undefined;
		else
			data = this.bytebuffer_to_string(this.read_buf);
		this.events.push({
			type: "recv",
			sd: channel,
			data: data,
		});
		this.unregister(channel, java.nio.channels.SelectionKey.OP_READ);
	},
	op_write: function(channel) {
		this.events.push({
			type: "send",
			sd: channel,
		});
		this.unregister(channel, java.nio.channels.SelectionKey.OP_WRITE);
	},

	wait_for_event: function() {
		while (true) {
			if (this.events.length > 0)
				return this.events.shift();

			var n;
			do {
				n = this.selector.select();
			} while (n == 0);
			var key = this.selector.selectedKeys().iterator().next();
			var channel = key.channel();
			this.selector.selectedKeys().remove(key);
			if ((key.readyOps() & java.nio.channels.SelectionKey.OP_ACCEPT)
				== java.nio.channels.SelectionKey.OP_ACCEPT) {
				this.op_accept(channel);
			} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_CONNECT)
				== java.nio.channels.SelectionKey.OP_CONNECT) {
				this.op_connect(channel);
			} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_READ)
				== java.nio.channels.SelectionKey.OP_READ) {
				this.op_read(channel);
			} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_WRITE)
				== java.nio.channels.SelectionKey.OP_WRITE) {
				this.op_write(channel);
			} else {
				throw new Error("Unknown selection key op.");
			}
		}
	},
	listen: function(address, port) {
		var sd = java.nio.channels.ServerSocketChannel.open();
		sd.configureBlocking(false);
		sd.socket().bind(java.net.InetSocketAddress(port));
		this.register(sd, java.nio.channels.SelectionKey.OP_ACCEPT);
		return sd;
	},
	connect: function(address, port) {
		var sd = java.nio.channels.SocketChannel.open();
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_CONNECT);
		sd.connect(java.net.InetSocketAddress(address, port));
		return sd;
	},
	recv: function(sd) {
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_READ);
		return sd;
	},
	send: function(sd, data) {
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_WRITE);
		sd.write(this.string_to_bytebuffer(data));
		return sd;
	},
	close: function(sd) {
		sd.close();
		sd.keyFor(this.selector).cancel();
	},
};

accept_pending = [];
connect_pending = [];
recv_pending = [];
send_pending = [];

function add_pending(pending_list, id, data) {
	pending_list.push({ id: id, data: data });
}

function get_pending(pending_list, id, keep) {
	for (var i = 0; i < pending_list.length; i++) {
		if (pending_list[i].id == id) {
			var pending = pending_list[i];
			if (!keep)
				pending_list.splice(i, 1)[0];
			return pending.data;
		}
	}
}

function listen(address, port, callback, userdata) {
	var sd = connector.listen(address, port);
	add_pending(accept_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function connect(address, port, callback, userdata) {
	var sd = connector.connect(address, port);
	add_pending(connect_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function recv(sd, callback, userdata) {
	var sd = connector.recv(sd);
	add_pending(recv_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function send(sd, data, callback, userdata) {
	var sd = connector.send(sd, data);
	add_pending(send_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function close(sd) {
	while (get_pending(accept_pending, sd))
		;
	while (get_pending(connect_pending, sd))
		;
	while (get_pending(recv_pending, sd))
		;
	while (get_pending(send_pending, sd))
		;
	connector.close(sd);
};

function event_loop() {
	while (true) {
		var ev = connector.wait_for_event();
		io.print("ev: " + repr(ev));
		var pending;
		switch (ev.type) {
		case "accept":
			/* accept events are persistent; don't remove pending
			   except on error. */
			pending = this.get_pending(this.accept_pending, ev.sd, true);
			args = [ev.sd, ev.address, ev.port, ev.client, pending.userdata];
			break;
		case "connect":
			pending = this.get_pending(this.connect_pending, ev.sd);
			args = [ev.sd, ev.address, ev.port, pending.userdata];
			break;
		case "recv":
			pending = this.get_pending(this.recv_pending, ev.sd);
			args = [ev.sd, ev.data, pending.userdata];
			break;
		case "send":
			pending = this.get_pending(this.send_pending, ev.sd);
			args = [ev.sd, pending.userdata];
			break;
		default:
			io.print("Unknown event type \"" + ev.type + "\".");
			io.quit();
		}
		if (pending.callback)
			pending.callback.apply(null, args);
	}
}

io.print("jscat starting.")

var LOCAL_ADDRESS = "0.0.0.0";
var LOCAL_PORT = 9998;

var DIRECTORY_ADDRESS = "localhost";
var DIRECTORY_PORT = 9999;

var peers = {};

function accept_handler(sd, address, port, client, userdata) {
	io.print("Connection from " + address + ":" + port + ".");
	/* Pass the client as userdata. */
	connect(DIRECTORY_ADDRESS, DIRECTORY_PORT, connect_handler, client);
}

function connect_handler(sd, address, port, userdata) {
	io.print("Connection to " + address + ":" + port + ".");
	peers[connector.s_sd(sd)] = userdata;
	peers[connector.s_sd(userdata)] = sd;
	/* Queue initial read events. */
	recv(sd, recv_handler, userdata);
	recv(userdata, recv_handler, sd);
}

function recv_handler(sd, data, userdata) {
	if (data == undefined) {
		close(sd);
		var peer = peers[connector.s_sd(sd)];
		if (peer) {
			connector.close(peer);
			delete peers[connector.s_sd(sd)];
			delete peers[connector.s_sd(peer)];
		}
	} else {
		send(userdata, data);
		recv(sd, recv_handler, userdata);
	}
}

listen(LOCAL_ADDRESS, LOCAL_PORT, accept_handler);

event_loop();
<|endoftext|>


<commit_before>var tilt = 0;

var Teacher = "Taylor Hudson ";

var ClubPresident = "Zach Gray";

var ClubVP = "Ayush Agarwal";

var Secretary = "Deep Desai";

var Historian = "Ryan Noeske";

var Secretary = "Ryan King";

var advisor= "Nathan Wander";

var AntiDeep = "Chris Delagarza";

var HighSchool = "Allen High School";

var ASCII = function(){
/*return"                ___          __   __         __       ___  ___  __      __   __     ___       __   ___"+"\n"+
				" /\  |    |    |__  |\ |    /  ` /  \  |\/| |__) |  |  |  |__  |__)    /__` /  ` | |__  |\ | /  ` |__"+"\n"+
				"/--\ |___ |___ |___ | \|    \__, \__/  |  | |    \__/  |  |___ |  \    .__/ \__, | |___ | \| \__, |___"+"\n"
*/
return " $$$$$$\\  $$\\ $$\\                            $$$$$$\\                                           $$$$$$\\            $$\\ " + "\n" +
	   "$$  __$$\\ $$ |$$ |                          $$  __$$\\                                         $$  __$$\\           \\__|" + "\n" +
	   "$$ /  $$ |$$ |$$ | $$$$$$\\  $$$$$$$\\        $$ /  \\__| $$$$$$\\  $$$$$$\\$$$$\\   $$$$$$\\        $$ /  \\__| $$$$$$$\\ $$\\ " + "\n" +
	   "$$$$$$$$ |$$ |$$ |$$  __$$\\ $$  __$$\\       $$ |      $$  __$$\\ $$  _$$  _$$\\ $$  __$$\\       \\$$$$$$\\  $$  _____|$$ |" + "\n" +
	   "$$  __$$ |$$ |$$ |$$$$$$$$ |$$ |  $$ |      $$ |      $$ /  $$ |$$ / $$ / $$ |$$ /  $$ |       \\____$$\\ $$ /      $$ |" + "\n" +
	   "$$ |  $$ |$$ |$$ |$$   ____|$$ |  $$ |      $$ |  $$\\ $$ |  $$ |$$ | $$ | $$ |$$ |  $$ |      $$\\   $$ |$$ |      $$ |" + "\n" +
	   "$$ |  $$ |$$ |$$ |\\$$$$$$$\\ $$ |  $$ |      \\$$$$$$  |\\$$$$$$  |$$ | $$ | $$ |$$$$$$$  |      \\$$$$$$  |\\$$$$$$$\\ $$ |" + "\n" +
	   "\\__|  \\__|\\__|\\__| \\_______|\\__|  \\__|       \\______/  \\______/ \\__| \\__| \\__|$$  ____/        \\______/  \\_______|\\__|" + "\n" +
	   "                                                                              $$ |                                    " + "\n" +
	   "                                                                              $$ |                                    " + "\n" +
	   "                                                                              \\__|                                    " + "\n" ;

};

var linkify = function(text, url) {
	return "" + text + "";
};

var specialify = function(text) {
	return "" + text + "";
};

var data = {
	hello: "Welcome to Allen Computer Science, where we " + specialify("promote Computer Science, development and innovation") + "\n\tin the Allen community by providing " + specialify("an place to soar") + " for those interested in furthering their \n\tpursuit of the field and attending " + specialify("competitions") + " ranging from " + specialify("hackathons") + " to " + specialify("algorithm contests") + ". \n\tComputer Science club meets every Wednesday from 3:35 to 5, and works on multifaceted projects, \n\tranging from app to web to even game development.",
	help: [ {
		name: specialify("hello"),
		description: "Our mission statement"
	}, {
		name: specialify("team"),
		description: "Our board and members"
	}, {
		name: specialify("competitions"),
		description: "Info about upcoming competitions and hackathons"
	}, {
		name: specialify("links"),
		description: "Displays links to permission slips, resources, and more"
	},{
		name: specialify("showcase"),
		description: "HS students\' cool projects"
	},{
		name: specialify("contact"),
		description: "Get in touch for outreach and info on projects"
	}, {
		name: specialify("twitter"),
		description: "Follow us " + linkify("@Allen_CompSci", "https://twitter.com/allen_compsci")
	},
	{
		name: specialify("help"),
		description: "Displays all commands"
	}],
	contact:
	[
	{
		name:"Contact Taylor Hudson.",
	},{
		name:"Contact Computer Science Club."
	}],
	team:
	[{
		name: specialify("Taylor") + " Hudson",
		position: "Club Sponsor"
	},
	{
		name: specialify("Zach") + " Gray",
		position: "President"
	},
	{
		name: specialify("Ayush") + " Agarwal",
		position: "Vice President"
	},
	{
		name: specialify("Deep") + " Desai",
		position: "Secretary"
	},{
		name: specialify("Ryan") + " Noeske",
		position: "Historian"
	},{
		name: specialify("Ryan") + " King",
		position: "Treasurer"
	},{
		name: specialify("Chris") + " Delegarza",
		position: "AntiDeep"
	},{
		name: specialify("Nathan") + " Wander",
		position: "Advisor"
	},
	],
	competitions: "Competition schedule coming soon!",
	links: [
		{
			name : linkify("CS Classes' Github", "https://github.com/AllenCompSci"),
			description: "Github for all CS classes, where projects and assignments are hosted."
		},
		{
			name : linkify("CompSci Club Github", "https://github.com/orgs/allen-computer-science/dashboard"),
			description: "Github for CompSci Club, where project and ideas are hosted."
		},
		{
			name : linkify("Allen High School", "http://www.allenisd.org/allenhs"),
		},
		{
			name : linkify("Taylor Hudson", "https://www.allenisd.org/Domain/3279"),
		}
		],
	showcase: [{
		name: linkify("Cool Projects we've made.","http://github.com/AllenCompSci"),
		authors: "Look at projects which highschool students have made!"
	}],
	invalid: "That's not a valid command! Type help for a list of commands."
};

var describify = function(obj) {
	var output = "";

	properties = [];
	for (var property in obj) {
		if (obj.hasOwnProperty(property)) {
			properties.push(obj[property]);
		}
	}

	output += properties.join(" | ");
	return output;
};

var listify = function(list) {
	var output = "";

	for (var i = 0; i < list.length; i++) {
		output += "\t• ";

		var described = describify(list[i]);
		output += described;

		output += "\n";
	}

	return output;
};

var format = function(field) {
	var unformatted = data[field];

	if (typeof unformatted == 'string') {
		return "\n\t" + unformatted + "\n\n";
	}

	return "\n" + listify(unformatted) + "\n";
};

var lambdify = function(format_string) {
	return function() { return format(format_string) }
}

var options = {
	include: ["score"],
	shouldSort: true,
	threshold: 0.3,
	location: 0,
	distance: 100,
	maxPatternLength: 32,
	keys: ['command']
};

var search = function(list, searchitem) {
	options.distance = (searchitem.length<=2? 0 : 100)
	return new Fuse(list, options).search(searchitem)
}

$(function() {
	var intro = ASCII() +"\n"+ "Welcome to the Computer Science department at " + "Allen High School" +"!\nType 'hello' below to learn what we're all about! \nTry '?' for more.\n\n";
	var jqconsole = $('#console').jqconsole(intro, 'C:\\Users\\Eagles> ');
	var cout = function(input){
		jqconsole.Write("     "+input.replace(/\n/g,'\n     ')+'\n', 'jqconsole-output', false);
	}
	function process(input) {
		var parsed = input.split(" ");
		var commands = [
			[["help", "?", "ls"], lambdify('help')],
			[["hello", "mission", "description", "why"], lambdify('hello')],
			[["team", "execs", "executives", "officers"], lambdify('team')],
			[["competitions", "hackathons", "events"], lambdify('competitions')],
			[["links", "forms", "info"], lambdify('links')],
			[["projects", "showcase"], lambdify('showcase')],
			[["contact"], lambdify('contact')],
			[["soar"], lambdify('soar')],
			[["clear", "cls"], function() { jqconsole.Clear(); return '\r'; }],
			[["fb", "facebook"], function() {
				window.location.href = "https://www.facebook.com/groups/";
				return '\r';
			}],
			[["tilt"], function() {
				tilt += 7;
				$(document.documentElement).addClass('rotate_please');
				document.documentElement.setAttribute('style', 'transform: rotate(' + String(tilt) + 'deg);');
				return "\n\n";
			}],
			[["qt"], function() {
				tilt += 70;
				$(document.documentElement).addClass('qt_please');
				document.documentElement.setAttribute('style', 'transform: rotate(' + String(tilt) + 'deg);');
				return "\n\n";
			}],
			[["untilt"], function() {
				tilt = 0;
				$(document.documentElement).removeClass('rotate_please');
				$(document.documentElement).removeClass('qt_please');
				document.documentElement.setAttribute('style', 'transform: rotate(' + String(tilt) + 'deg);');
				return "\n\n";
			}],
			[["js", "javascript", "code"], function() {}], //since this is processed directly, there is no need for a function here
		];
		var response = null;
		commands.forEach(function(key, index, commands) {
			key[0].forEach(function(term, tindex) {
				if (term === parsed[0]) {
					response = key[1]();
				}
			});
		});
		if (response) {
			return response;
		} else {
			var commands_list = [];
			commands.forEach(function(key, index, commands) {
				key[0].forEach(function(term, tindex) {
					if (term !== "qt") {
						commands_list.push({
							'command': term,
							'callback': key[1]
						});
					}
				})
			});
			var results = search(commands_list, parsed[0]);
			if (results.length > 0) {
				response = '\nThat command doesn\'t exist. Did you mean ';
				results.forEach(function(result, index) {
					if (index === results.length - 1 && results.length == 2) {
						response = response.substring(0, response.length - 2);
						response += ' or ' + specialify(result['item']['command']) + ', ';
					} else if (index === results.length - 1 && results.length > 1) {
						response = response.substring(0, response.length - 2);
						response += ', or ' + specialify(result['item']['command']) + ', ';
					} else {
						response += specialify(result['item']['command']) + ', ';
					}
				});
				response = response.substring(0, response.length - 2);
				response += '?\n\n';
				return response;
			} else {
				return '\nThat command doesn\'t exist. Here is a list of commands you can use:\n' + format('help');
			}
		}
	};
	var jsmode = false;
	var blockQuery = false;
	var block = "";
	var processJs = function(input){
		if(input.match(/exit/) || input.match(/process.exit\(/)){
			jsmode = false;
			jqconsole.SetPromptLabel("C:\Users\Eagles> ");
			jqconsole.Write('\n');
			startPrompt();
			return;
		}
		if(!blockQuery){
			block = "";
		}
		block+=input;
		var leftParens = (block.match(/\{/g)? block.match(/\{/g).length: 0);
		var rightParens = (block.match(/\}/g)? block.match(/\}/g).length: 0);
		if(leftParens > rightParens){
			blockQuery = true;
			startPrompt();
			return;
		}else{
			blockQuery = false;
		}
		var result;
		try{
			result = eval('eval')(block); //indirect call so it's global
		}catch(err){
			result = err;
		}
		result = String(result);
		cout(result);
	}
	var processQuery = function(input) {
		if(jsmode){
			processJs(input);
			startPrompt();
			return;
		}
		if (input) {
			if(input == "javascript" || input == "js" || input == "code" || input == "node"){
				jsmode = true;
				jqconsole.SetPromptLabel("   > ");
				jqconsole.Write('\n');
				startPrompt();
				return;
			}
			jqconsole.Write(process(input),'jqconsole-output',false);
		} else {
			jqconsole.Write('\n Here is a list of commands:\n' + format('help'), 'jqconsole-output', false);
		}
		startPrompt();
	}
	var startPrompt = function() {
		jqconsole.Prompt(true, processQuery);
	};

	startPrompt();
});
<commit_msg>Added some minor visual effects<commit_after>var tilt = 0;

var Teacher = "Taylor Hudson ";

var ClubPresident = "Zach Gray";

var ClubVP = "Ayush Agarwal";

var Secretary = "Deep Desai";

var Historian = "Ryan Noeske";

var Secretary = "Ryan King";

var advisor= "Nathan Wander";

var AntiDeep = "Chris Delagarza";

var HighSchool = "Allen High School";

var ASCII = function(){
/*return"                ___          __   __         __       ___  ___  __      __   __     ___       __   ___"+"\n"+
				" /\  |    |    |__  |\ |    /  ` /  \  |\/| |__) |  |  |  |__  |__)    /__` /  ` | |__  |\ | /  ` |__"+"\n"+
				"/--\ |___ |___ |___ | \|    \__, \__/  |  | |    \__/  |  |___ |  \    .__/ \__, | |___ | \| \__, |___"+"\n"
*/
return "    :::      :::         :::         ::::::::::  ::::    :::        ::::::::    ::::::::   ::::    ::::   :::::::::         ::::::::    ::::::::   :::::::::::
  :+: :+:    :+:         :+:         :+:         :+:+:   :+:       :+:    :+:  :+:    :+:  +:+:+: :+:+:+  :+:    :+:       :+:    :+:  :+:    :+:      :+:
 +:+   +:+   +:+         +:+         +:+         :+:+:+  +:+       +:+         +:+    +:+  +:+ +:+:+ +:+  +:+    +:+       +:+         +:+             +:+
+#++:++#++:  +#+         +#+         +#++:++#    +#+ +:+ +#+       +#+         +#+    +:+  +#+  +:+  +#+  +#++:++#+        +#++:++#++  +#+             +#+
+#+     +#+  +#+         +#+         +#+         +#+  +#+#+#       +#+         +#+    +#+  +#+       +#+  +#+                     +#+  +#+             +#+
#+#     #+#  #+#         #+#         #+#         #+#   #+#+#       #+#    #+#  #+#    #+#  #+#       #+#  #+#              #+#    #+#  #+#    #+#      #+#
###     ###  ##########  ##########  ##########  ###    ####        ########    ########   ###       ###  ###               ########    ########   ###########"+"\n"+ "\n" ;

};

var linkify = function(text, url) {
	return "" + text + "";
};

var specialify = function(text) {
	return "" + text + "";
};

var data = {
	hello: "Welcome to Allen Computer Science, where we " + specialify("promote Computer Science, development and innovation") + "\n\tin the Allen community by providing " + specialify("an place to soar") + " for those interested in furthering their \n\tpursuit of the field and attending " + specialify("competitions") + " ranging from " + specialify("hackathons") + " to " + specialify("algorithm contests") + ". \n\tComputer Science club meets every Wednesday from 3:35 to 5, and works on multifaceted projects, \n\tranging from app to web to even game development.",
	help: [ {
		name: specialify("hello"),
		description: "Our mission statement"
	}, {
		name: specialify("team"),
		description: "Our board and members"
	}, {
		name: specialify("competitions"),
		description: "Info about upcoming competitions and hackathons"
	}, {
		name: specialify("links"),
		description: "Displays links to permission slips, resources, and more"
	},{
		name: specialify("showcase"),
		description: "HS students\' cool projects"
	},{
		name: specialify("contact"),
		description: "Get in touch for outreach and info on projects"
	}, {
		name: specialify("twitter"),
		description: "Follow us " + linkify("@Allen_CompSci", "https://twitter.com/allen_compsci")
	},
	{
		name: specialify("help"),
		description: "Displays all commands"
	}],
	contact:
	[
	{
		name:"Contact Taylor Hudson.",
	},{
		name:"Contact Computer Science Club."
	}],
	team:
	[{
		name: specialify("Taylor") + " Hudson",
		position: "Club Sponsor"
	},
	{
		name: specialify("Zach") + " Gray",
		position: "President"
	},
	{
		name: specialify("Ayush") + " Agarwal",
		position: "Vice President"
	},
	{
		name: specialify("Deep") + " Desai",
		position: "Secretary"
	},{
		name: specialify("Ryan") + " Noeske",
		position: "Historian"
	},{
		name: specialify("Ryan") + " King",
		position: "Treasurer"
	},{
		name: specialify("Chris") + " Delegarza",
		position: "AntiDeep"
	},{
		name: specialify("Nathan") + " Wander",
		position: "Advisor"
	},
	],
	competitions: "Competition schedule coming soon!",
	links: [
		{
			name : linkify("CS Classes' Github", "https://github.com/AllenCompSci"),
			description: "Github for all CS classes, where projects and assignments are hosted."
		},
		{
			name : linkify("CompSci Club Github", "https://github.com/orgs/allen-computer-science/dashboard"),
			description: "Github for CompSci Club, where project and ideas are hosted."
		},
		{
			name : linkify("Allen High School", "http://www.allenisd.org/allenhs"),
		},
		{
			name : linkify("Taylor Hudson", "https://www.allenisd.org/Domain/3279"),
		}
		],
	showcase: [{
		name: linkify("Cool Projects we've made.","http://github.com/AllenCompSci"),
		authors: "Look at projects which highschool students have made!"
	}],
	invalid: "That's not a valid command! Type help for a list of commands."
};

var describify = function(obj) {
	var output = "";

	properties = [];
	for (var property in obj) {
		if (obj.hasOwnProperty(property)) {
			properties.push(obj[property]);
		}
	}

	output += properties.join(" | ");
	return output;
};

var listify = function(list) {
	var output = "";

	for (var i = 0; i < list.length; i++) {
		output += "\t• ";

		var described = describify(list[i]);
		output += described;

		output += "\n";
	}

	return output;
};

var format = function(field) {
	var unformatted = data[field];

	if (typeof unformatted == 'string') {
		return "\n\t" + unformatted + "\n\n";
	}

	return "\n" + listify(unformatted) + "\n";
};

var lambdify = function(format_string) {
	return function() { return format(format_string) }
}

var options = {
	include: ["score"],
	shouldSort: true,
	threshold: 0.3,
	location: 0,
	distance: 100,
	maxPatternLength: 32,
	keys: ['command']
};

var search = function(list, searchitem) {
	options.distance = (searchitem.length<=2? 0 : 100)
	return new Fuse(list, options).search(searchitem)
}

$(function() {
	var intro = ASCII() +"\n"+ "Welcome to the Computer Science department at " + "Allen High School" +"!\nType 'hello' below to learn what we're all about! \nTry '?' for more.\n\n";
	var jqconsole = $('#console').jqconsole(intro, 'C:\\Users\\Eagles> ');
	var cout = function(input){
		jqconsole.Write("     "+input.replace(/\n/g,'\n     ')+'\n', 'jqconsole-output', false);
	}
	function process(input) {
		var parsed = input.split(" ");
		var commands = [
			[["help", "?", "ls"], lambdify('help')],
			[["hello", "mission", "description", "why"], lambdify('hello')],
			[["team", "execs", "executives", "officers"], lambdify('team')],
			[["competitions", "hackathons", "events"], lambdify('competitions')],
			[["links", "forms", "info"], lambdify('links')],
			[["projects", "showcase"], lambdify('showcase')],
			[["contact"], lambdify('contact')],
			[["soar"], lambdify('soar')],
			[["clear", "cls"], function() { jqconsole.Clear(); return '\r'; }],
			[["fb", "facebook"], function() {
				window.location.href = "https://www.facebook.com/groups/";
				return '\r';
			}],
			[["tilt"], function() {
				tilt += 7;
				$(document.documentElement).addClass('rotate_please');
				document.documentElement.setAttribute('style', 'transform: rotate(' + String(tilt) + 'deg);');
				return "\n\n";
			}],
			[["qt"], function() {
				tilt += 70;
				$(document.documentElement).addClass('qt_please');
				document.documentElement.setAttribute('style', 'transform: rotate(' + String(tilt) + 'deg);');
				return "\n\n";
			}],
			[["untilt"], function() {
				tilt = 0;
				$(document.documentElement).removeClass('rotate_please');
				$(document.documentElement).removeClass('qt_please');
				document.documentElement.setAttribute('style', 'transform: rotate(' + String(tilt) + 'deg);');
				return "\n\n";
			}],
			[["js", "javascript", "code"], function() {}], //since this is processed directly, there is no need for a function here
		];
		var response = null;
		commands.forEach(function(key, index, commands) {
			key[0].forEach(function(term, tindex) {
				if (term === parsed[0]) {
					response = key[1]();
				}
			});
		});
		if (response) {
			return response;
		} else {
			var commands_list = [];
			commands.forEach(function(key, index, commands) {
				key[0].forEach(function(term, tindex) {
					if (term !== "qt") {
						commands_list.push({
							'command': term,
							'callback': key[1]
						});
					}
				})
			});
			var results = search(commands_list, parsed[0]);
			if (results.length > 0) {
				response = '\nThat command doesn\'t exist. Did you mean ';
				results.forEach(function(result, index) {
					if (index === results.length - 1 && results.length == 2) {
						response = response.substring(0, response.length - 2);
						response += ' or ' + specialify(result['item']['command']) + ', ';
					} else if (index === results.length - 1 && results.length > 1) {
						response = response.substring(0, response.length - 2);
						response += ', or ' + specialify(result['item']['command']) + ', ';
					} else {
						response += specialify(result['item']['command']) + ', ';
					}
				});
				response = response.substring(0, response.length - 2);
				response += '?\n\n';
				return response;
			} else {
				return '\nThat command doesn\'t exist. Here is a list of commands you can use:\n' + format('help');
			}
		}
	};
	var jsmode = false;
	var blockQuery = false;
	var block = "";
	var processJs = function(input){
		if(input.match(/exit/) || input.match(/process.exit\(/)){
			jsmode = false;
			jqconsole.SetPromptLabel("C:\Users\Eagles> ");
			jqconsole.Write('\n');
			startPrompt();
			return;
		}
		if(!blockQuery){
			block = "";
		}
		block+=input;
		var leftParens = (block.match(/\{/g)? block.match(/\{/g).length: 0);
		var rightParens = (block.match(/\}/g)? block.match(/\}/g).length: 0);
		if(leftParens > rightParens){
			blockQuery = true;
			startPrompt();
			return;
		}else{
			blockQuery = false;
		}
		var result;
		try{
			result = eval('eval')(block); //indirect call so it's global
		}catch(err){
			result = err;
		}
		result = String(result);
		cout(result);
	}
	var processQuery = function(input) {
		if(jsmode){
			processJs(input);
			startPrompt();
			return;
		}
		if (input) {
			if(input == "javascript" || input == "js" || input == "code" || input == "node"){
				jsmode = true;
				jqconsole.SetPromptLabel("   > ");
				jqconsole.Write('\n');
				startPrompt();
				return;
			}
			jqconsole.Write(process(input),'jqconsole-output',false);
		} else {
			jqconsole.Write('\n Here is a list of commands:\n' + format('help'), 'jqconsole-output', false);
		}
		startPrompt();
	}
	var startPrompt = function() {
		jqconsole.Prompt(true, processQuery);
	};

	startPrompt();
});
<|endoftext|>


<commit_before>var BoxPool = require("../../box-pool");

var groupsToCollide = [];

module.exports = function(ecs, game) {

  game.entities.registerSearch("boxColliderSearch", ["position", "size", "boxCollider"]);

  game.entities.onRemoveComponent("collisions", function(entity, component, collisions) {
    for (var i = 0; i < collisions.entities.length; i++) {
      var otherCollisions = game.entities.getComponent(collisions.entities[i], "boxCollider");
      var idx = otherCollisions.entities.indexOf(entity);
      if (idx !== -1) {
        otherCollisions.entities.splice(idx, 1);
      }
    }
  });

  var boxPoolNames = [ "unnamed" ];
  var boxPools = {
    unnamed: new BoxPool()
  };

  function handleCollision(a, b) {
    handleCollision2(game, a, b);
    handleCollision2(game, b, a);
  }

  ecs.add(function boxGroupCollider() {
    var ids = game.entities.find("boxColliderSearch");

    for (var i = 0; i < boxPoolNames.length; i++) {
      boxPools[boxPoolNames[i]].reset();
    }

    for (i = 0; i < ids.length; i++) {
      var entity = ids[i];
      var collisions = game.entities.getComponent(entity, "boxCollider");
      collisions.entities.length = 0;
      var position = game.entities.getComponent(entity, "position");
      var size = game.entities.getComponent(entity, "size");

      var name = collisions.group || "unnamed";
      if (!boxPools[name]) {
        boxPoolNames.push(name);
        boxPools[name] = new BoxPool();
      }
      boxPools[name].add(entity, position, size);
    }
    for (i = 0; i < groupsToCollide.length; i++) {
      var a = boxPools[groupsToCollide[i][0]];
      var b = boxPools[groupsToCollide[i][1]];
      if (a && b) {
        a.collideOther(b, handleCollision);
      }
    }
    boxPools["unnamed"].collideSelf(handleCollision);
    for (i = 0; i < ids.length; i++) {
      updateLastCollisions(game, ids[i]);
    }
  });
};

module.exports.collideGroups = function(a, b) {
  groupsToCollide.push([a, b]);
};

function updateLastCollisions(game, entity) {
  var collisions = game.entities.getComponent(entity, "boxCollider");

  if (collisions.onExit) {
    var currentCollisions = {};
    for (var j = 0; j < collisions.entities.length; j++) {
      currentCollisions[collisions.entities[j]] = true;
    }
    for (var k = 0; k < collisions.last.length; k++) {
      if (!currentCollisions[collisions.last[k]]) {
        var onExit = game.require(collisions.onExit);
        onExit(entity, collisions.last[k], game);
      }
    }
  }

  if (collisions.last) {
    collisions.last.length = 0;
  } else {
    collisions.last = [];
  }
  for (var i = 0; i < collisions.entities.length; i++) {
    collisions.last.push(collisions.entities[i]);
  }
}

function handleCollision2(game, entity, other) {
  var collisions = game.entities.getComponent(entity, "boxCollider");
  collisions.entities.push(other);
  if (collisions.onEnter && collisions.last.indexOf(other) === -1) {
    var onEnter = game.require(collisions.onEnter);
    onEnter(entity, other, game);
  }
  if (collisions.script) {
    var script = game.require(collisions.script);
    script(entity, other, game);
  }
}
<commit_msg>Specify which groups *NOT* to collide<commit_after>var BoxPool = require("../../box-pool");

module.exports = function(ecs, game) {

  game.entities.registerSearch("boxColliderSearch", ["position", "size", "boxCollider"]);

  game.entities.onRemoveComponent("collisions", function(entity, component, collisions) {
    for (var i = 0; i < collisions.entities.length; i++) {
      var otherCollisions = game.entities.getComponent(collisions.entities[i], "boxCollider");
      var idx = otherCollisions.entities.indexOf(entity);
      if (idx !== -1) {
        otherCollisions.entities.splice(idx, 1);
      }
    }
  });

  var boxPoolNames = [ "unnamed" ];
  var boxPools = {
    unnamed: new BoxPool()
  };

  function handleCollision(a, b) {
    handleCollision2(game, a, b);
    handleCollision2(game, b, a);
  }

  ecs.add(function boxGroupCollider() {
    var ids = game.entities.find("boxColliderSearch");

    for (var i = 0; i < boxPoolNames.length; i++) {
      boxPools[boxPoolNames[i]].reset();
    }

    for (i = 0; i < ids.length; i++) {
      var entity = ids[i];
      var collisions = game.entities.getComponent(entity, "boxCollider");
      collisions.entities.length = 0;
      var position = game.entities.getComponent(entity, "position");
      var size = game.entities.getComponent(entity, "size");

      var name = collisions.group || "unnamed";
      if (!boxPools[name]) {
        boxPoolNames.push(name);
        boxPools[name] = new BoxPool();
      }
      boxPools[name].add(entity, position, size);
    }
    for (i = 0; i < boxPoolNames.length; i++) {
      for (var j = i + 1; j < boxPoolNames.length; j++) {
        var aName = boxPoolNames[i];
        var bName = boxPoolNames[j];
        if (areGroupsExcluded(game, aName, bName)) {
          continue;
        }

        var a = boxPools[aName];
        var b = boxPools[bName];
        if (a && b) {
          a.collideOther(b, handleCollision);
        }
      }
    }
    boxPools["unnamed"].collideSelf(handleCollision);
    for (i = 0; i < ids.length; i++) {
      updateLastCollisions(game, ids[i]);
    }
  });
};

function areGroupsExcluded(game, a, b) {
  var config = game.sceneConfig["box-group-collider"];
  if (!config) {
    return false;
  }
  var skip = config.skip;
  if (!skip) {
    return false;
  }
  for (var i = 0; i < skip.length; i++) {
    if (
      (skip[i][0] === a && skip[i][1] === b) ||
      (skip[i][0] === b && skip[i][1] === a)
    ) {
      return true;
    }
  }
  return false;
}

function updateLastCollisions(game, entity) {
  var collisions = game.entities.getComponent(entity, "boxCollider");

  if (collisions.onExit) {
    var currentCollisions = {};
    for (var j = 0; j < collisions.entities.length; j++) {
      currentCollisions[collisions.entities[j]] = true;
    }
    for (var k = 0; k < collisions.last.length; k++) {
      if (!currentCollisions[collisions.last[k]]) {
        var onExit = game.require(collisions.onExit);
        onExit(entity, collisions.last[k], game);
      }
    }
  }

  if (collisions.last) {
    collisions.last.length = 0;
  } else {
    collisions.last = [];
  }
  for (var i = 0; i < collisions.entities.length; i++) {
    collisions.last.push(collisions.entities[i]);
  }
}

function handleCollision2(game, entity, other) {
  var collisions = game.entities.getComponent(entity, "boxCollider");
  collisions.entities.push(other);
  if (collisions.onEnter && collisions.last.indexOf(other) === -1) {
    var onEnter = game.require(collisions.onEnter);
    onEnter(entity, other, game);
  }
  if (collisions.script) {
    var script = game.require(collisions.script);
    script(entity, other, game);
  }
}
<|endoftext|>


<commit_before>var urlTools = require('../util/urlTools'),
    errors = require('../errors');

module.exports = function () {
    return function replaceRequireJsWithAlmond(assetGraph) {
        var replacedAssets = [],
            removedAlmonds = [],
            query = assetGraph.query,

            // Start out with checking if requirejs is being used as a script loader.
            // Almond should not replace requirejs if any require/define statement depende on an external url or uses a js experession
            externalDependencies = assetGraph.findRelations({
                type: query.or('JavaScriptAmdRequire', 'JavaScriptAmdDefine'),
                to: {
                    url: query.not(/^file:/)
                }
            }, true),
            almondRelations = assetGraph.findRelations({
                type: 'HtmlRequireJsAlmondReplacement'
            });

        if (!almondRelations.length) {
            return;
        }

        if (externalDependencies.length) {
            assetGraph.emit('warn', new errors.SyntaxError({
                message: 'Could not replace require.js with almond.js since it is used for external script loading.',
                transform: 'replaceRequireJsWithAlmond'
            }));
        } else {
            almondRelations.forEach(function (almondRelation) {
                var document = almondRelation.from.parseTree.documentElement,
                    almondScriptElements = document.querySelectorAll('[data-almond]');

                Array.prototype.forEach.call(almondScriptElements, function (el) {
                    assetGraph.findAssets({
                        type: 'JavaScript',
                        url: urlTools.resolveUrl(almondRelation.from.url, el.src)
                    }).forEach(function (requireJsAsset) {
                        // TODO: Check AST to see if we actually have the correct content

                        if (replacedAssets.indexOf(requireJsAsset.url) === -1) {
                            var replacement = new assetGraph.JavaScript({
                                    text: almondRelation.to.text
                                });

                            requireJsAsset.replaceWith(replacement);

                            replacedAssets.push(replacement.url);
                        }
                    });
                });
            });
        }

        almondRelations.forEach(function (almondRelation) {
            var almond = almondRelation.to;

            if (removedAlmonds.indexOf(almond.url) === -1) {
                removedAlmonds.push(almond.url);
                assetGraph.removeAsset(almond, true);
            }
        });
    };
};
<commit_msg>Simplify graph traversal to find requirejs scripts to replace<commit_after>var urlTools = require('../util/urlTools'),
    errors = require('../errors');

module.exports = function () {
    return function replaceRequireJsWithAlmond(assetGraph) {
        var replacedAssets = [],
            removedAlmonds = [],
            query = assetGraph.query,

            // Start out with checking if requirejs is being used as a script loader.
            // Almond should not replace requirejs if any require/define statement depende on an external url or uses a js experession
            externalDependencies = assetGraph.findRelations({
                type: query.or('JavaScriptAmdRequire', 'JavaScriptAmdDefine'),
                to: {
                    url: query.not(/^file:/)
                }
            }, true),
            almondRelations = assetGraph.findRelations({
                type: 'HtmlRequireJsAlmondReplacement'
            });

        if (!almondRelations.length) {
            return;
        }

        if (externalDependencies.length) {
            assetGraph.emit('warn', new errors.SyntaxError({
                message: 'Could not replace require.js with almond.js since it is used for external script loading.',
                transform: 'replaceRequireJsWithAlmond'
            }));
        } else {
            almondRelations.forEach(function (almondRelation) {
                assetGraph.findRelations({
                    type: 'HtmlScript',
                    node: function (node) {
                        return node === almondRelation.node;
                    }
                }, true).forEach(function (scriptRelation) {
                    if (replacedAssets.indexOf(scriptRelation.to.url) === -1) {
                        var replacement = new assetGraph.JavaScript({
                                text: almondRelation.to.text
                            });

                        scriptRelation.to.replaceWith(replacement);

                        replacedAssets.push(replacement.url);
                    }
                });
            });
        }

        almondRelations.forEach(function (almondRelation) {
            var almond = almondRelation.to;

            if (removedAlmonds.indexOf(almond.url) === -1) {
                removedAlmonds.push(almond.url);
                assetGraph.removeAsset(almond, true);
            }
        });
    };
};
<|endoftext|>