<commit_before>import loadScript from 'load-script';
import Promise from 'promise';
import ThreeDSecureStrategy from './strategy';
import { Frame } from '../../../frame';

const debug = require('debug')('recurly:risk:three-d-secure:adyen');

export default class AdyenStrategy extends ThreeDSecureStrategy {
  static libUrl = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/2.2.0/adyen.js';
  static strategyName = 'adyen';

  constructor (...args) {
    super(...args);

    if (!this.shouldLoadAdyenLibrary) return;
    debug('loading Adyen library');
    this.loadAdyenLibrary()
      .catch(cause => this.threeDSecure.error('3ds-vendor-load-error', { vendor: 'Adyen', cause }))
      .then(() => {
        this.adyenCheckout = new window.AdyenCheckout();
        debug('Adyen checkout instance created', this.adyenCheckout);
        this.markReady();
      });
  }

  get shouldLoadAdyenLibrary () {
    return !this.shouldFallback;
  }

  get shouldFingerprint () {
    return !!this.adyenFingerprintToken;
  }

  get shouldChallenge () {
    return !!this.adyenChallengeToken;
  }

  get shouldFallback () {
    return !!this.adyenRedirectParams;
  }

  get adyenFingerprintToken () {
    const { authentication } = this.actionToken.three_d_secure.params;
    return authentication && authentication['threeds2.fingerprintToken'];
  }

  get adyenChallengeToken () {
    const { authentication } = this.actionToken.three_d_secure.params;
    return authentication && authentication['threeds2.challengeToken'];
  }

  get adyenRedirectParams () {
    return this.actionToken.three_d_secure.params.redirect;
  }

  /**
   * Provides the target DOM element for which we will apply
   * fingerprint detection, challenge flows, and results
   *
   * @param {HTMLElement} element
   */
  attach (element) {
    super.attach(element);

    const { shouldFallback, shouldFingerprint, shouldChallenge } = this;

    if (shouldFingerprint) {
      this.whenReady(() => this.fingerprint());
    } else if (shouldChallenge) {
      this.whenReady(() => this.challenge());
    } else if (shouldFallback) {
      this.fallback();
    } else {
      const cause = 'We could not determine an authentication method';
      this.threeDSecure.error('3ds-auth-determination-error', { cause });
    }
  }

  /**
   * Removes DOM elements
   */
  remove () {
    const { frame } = this;
    if (frame) frame.destroy();
    super.remove();
  }

  /**
   * Initiates device fingerprinting through AdyenCheckout
   */
  fingerprint () {
    const { adyenCheckout, adyenFingerprintToken, container } = this;

    debug('Initializing fingerprinting with Adyen token', adyenFingerprintToken);

    const fingerprintService = adyenCheckout.create('threeDS2DeviceFingerprint', {
      fingerprintToken: adyenFingerprintToken,
      onComplete: results => this.emit('done', results),
      onError: cause => this.threeDSecure.error('3ds-auth-error', { cause }),
    });

    fingerprintService.mount(container);
  }

  /**
   * Initiates a challenge through AdyenCheckout
   */
  challenge () {
    const { adyenCheckout, adyenChallengeToken, container } = this;

    debug('Initializing challenge with Adyen token', adyenChallengeToken);

    const challengeService = adyenCheckout.create('threeDS2Challenge', {
      challengeToken: adyenChallengeToken,
      onComplete: results => this.emit('done', results),
      onError: cause => this.threeDSecure.error('3ds-auth-error', { cause }),
      size: '05'
    });

    challengeService.mount(container);
  }

  /**
   * Constructs a 3D Secure 1.0 iframe
   *
   * TODO: Move this into a separate strategy, and have this strategy
   *       instruct ThreeDSecureConcern to employ it instead
   */
  fallback () {
    debug('Initiating 3D Secure 1.0 frame');
    const { adyenRedirectParams, container, threeDSecure } = this;
    const { recurly } = threeDSecure.risk;
    const payload = {
      redirect_url: adyenRedirectParams.url,
      ...adyenRedirectParams.data
    };
    this.frame = recurly.Frame({ type: Frame.TYPES.IFRAME, path: '/three_d_secure/start', payload, container })
      .on('error', cause => threeDSecure.error('3ds-auth-error', { cause }))
      .on('done', results => this.emit('done', results));
  }

  /**
   * Loads Adyen library dependency
   */
  loadAdyenLibrary () {
    return new Promise((resolve, reject) => {
      if (window.AdyenCheckout) return resolve();
      loadScript(AdyenStrategy.libUrl, error => {
        if (error) reject(error);
        else resolve();
      });
    });
  }
}
<commit_msg>update 3ds frame to include default event name<commit_after>import loadScript from 'load-script';
import Promise from 'promise';
import ThreeDSecureStrategy from './strategy';
import { Frame } from '../../../frame';

const debug = require('debug')('recurly:risk:three-d-secure:adyen');

export default class AdyenStrategy extends ThreeDSecureStrategy {
  static libUrl = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/2.2.0/adyen.js';
  static strategyName = 'adyen';

  constructor (...args) {
    super(...args);

    if (!this.shouldLoadAdyenLibrary) return;
    debug('loading Adyen library');
    this.loadAdyenLibrary()
      .catch(cause => this.threeDSecure.error('3ds-vendor-load-error', { vendor: 'Adyen', cause }))
      .then(() => {
        this.adyenCheckout = new window.AdyenCheckout();
        debug('Adyen checkout instance created', this.adyenCheckout);
        this.markReady();
      });
  }

  get shouldLoadAdyenLibrary () {
    return !this.shouldFallback;
  }

  get shouldFingerprint () {
    return !!this.adyenFingerprintToken;
  }

  get shouldChallenge () {
    return !!this.adyenChallengeToken;
  }

  get shouldFallback () {
    return !!this.adyenRedirectParams;
  }

  get adyenFingerprintToken () {
    const { authentication } = this.actionToken.three_d_secure.params;
    return authentication && authentication['threeds2.fingerprintToken'];
  }

  get adyenChallengeToken () {
    const { authentication } = this.actionToken.three_d_secure.params;
    return authentication && authentication['threeds2.challengeToken'];
  }

  get adyenRedirectParams () {
    return this.actionToken.three_d_secure.params.redirect;
  }

  /**
   * Provides the target DOM element for which we will apply
   * fingerprint detection, challenge flows, and results
   *
   * @param {HTMLElement} element
   */
  attach (element) {
    super.attach(element);

    const { shouldFallback, shouldFingerprint, shouldChallenge } = this;

    if (shouldFingerprint) {
      this.whenReady(() => this.fingerprint());
    } else if (shouldChallenge) {
      this.whenReady(() => this.challenge());
    } else if (shouldFallback) {
      this.fallback();
    } else {
      const cause = 'We could not determine an authentication method';
      this.threeDSecure.error('3ds-auth-determination-error', { cause });
    }
  }

  /**
   * Removes DOM elements
   */
  remove () {
    const { frame } = this;
    if (frame) frame.destroy();
    super.remove();
  }

  /**
   * Initiates device fingerprinting through AdyenCheckout
   */
  fingerprint () {
    const { adyenCheckout, adyenFingerprintToken, container } = this;

    debug('Initializing fingerprinting with Adyen token', adyenFingerprintToken);

    const fingerprintService = adyenCheckout.create('threeDS2DeviceFingerprint', {
      fingerprintToken: adyenFingerprintToken,
      onComplete: results => this.emit('done', results),
      onError: cause => this.threeDSecure.error('3ds-auth-error', { cause }),
    });

    fingerprintService.mount(container);
  }

  /**
   * Initiates a challenge through AdyenCheckout
   */
  challenge () {
    const { adyenCheckout, adyenChallengeToken, container } = this;

    debug('Initializing challenge with Adyen token', adyenChallengeToken);

    const challengeService = adyenCheckout.create('threeDS2Challenge', {
      challengeToken: adyenChallengeToken,
      onComplete: results => this.emit('done', results),
      onError: cause => this.threeDSecure.error('3ds-auth-error', { cause }),
      size: '05'
    });

    challengeService.mount(container);
  }

  /**
   * Constructs a 3D Secure 1.0 iframe
   *
   * TODO: Move this into a separate strategy, and have this strategy
   *       instruct ThreeDSecureConcern to employ it instead
   */
  fallback () {
    debug('Initiating 3D Secure 1.0 frame');
    const { adyenRedirectParams, container, threeDSecure } = this;
    const { recurly } = threeDSecure.risk;
    const payload = {
      redirect_url: adyenRedirectParams.url,
      ...adyenRedirectParams.data
    };
    this.frame = recurly.Frame({
        type: Frame.TYPES.IFRAME,
        path: '/three_d_secure/start',
        payload,
        container,
        defaultEventName: 'adyen-3ds-challenge'
      })
      .on('error', cause => threeDSecure.error('3ds-auth-error', { cause }))
      .on('done', results => this.emit('done', results));
  }

  /**
   * Loads Adyen library dependency
   */
  loadAdyenLibrary () {
    return new Promise((resolve, reject) => {
      if (window.AdyenCheckout) return resolve();
      loadScript(AdyenStrategy.libUrl, error => {
        if (error) reject(error);
        else resolve();
      });
    });
  }
}
<|endoftext|>


<commit_before>// The Opal object that is exposed globally
var Opal = this.Opal = {};

// Very root class
function BasicObject(){}

// Core Object class
function Object(){}

// Class' class
function Class(){}

// Modules are just classes that cannot be instantiated
var Module = Class;

// the class of nil
function NilClass(){}

// TopScope is used for inheriting constants from the top scope
var TopScope = function(){};

// Opal just acts as the top scope
TopScope.prototype = Opal;

// To inherit scopes
Opal.alloc  = TopScope;

// This is a useful reference to global object inside ruby files
Opal.global = this;

// Minify common function calls
var __hasOwn = Opal.hasOwnProperty;
var __slice  = Opal.slice = Array.prototype.slice;

// Generates unique id for every ruby object
var unique_id = 0;

// Table holds all class variables
Opal.cvars = {};

// Globals table
Opal.gvars = {};

// Runtime method used to either define a new class, or re-open an old
// class. The base may be an object (rather than a class), which is
// always the case when defining classes in the top level as the top
// level is just the 'main' Object instance.
//
// The given ruby code:
//
//     class Foo
//       42
//     end
//
//     class Bar < Foo
//       3.142
//     end
//
// Would be compiled to something like:
//
//     var __klass = Opal.klass;
//
//     __klass(this, null, 'Foo', function() {
//       return 42;
//     });
//
//     __klass(this, __scope.Foo, 'Bar', function() {
//       return 3.142;
//     });
//
// @param [RubyObject] base the scope in which to define the class
// @param [RubyClass] superklass the superklass, may be null
// @param [String] id the name for the class
// @param [Function] body the class body
// @return returns last value from running body
Opal.klass = function(base, superklass, id, constructor) {
  var klass;
  if (base._isObject) {
    base = base._real;
  }

  if (superklass === null) {
    superklass = Object;
  }

  if (__hasOwn.call(base._scope, id)) {
    klass = base._scope[id];
  }
  else {
    if (!superklass._methods) {
      var bridged = superklass;
      superklass  = Object;
      klass       = bridge_class(bridged);
    }
    else {
      klass = boot_class(superklass, constructor);
    }

    klass._name = (base === Object ? id : base._name + '::' + id);

    var const_alloc   = function() {};
    var const_scope   = const_alloc.prototype = new base._scope.alloc();
    klass._scope      = const_scope;
    const_scope.alloc = const_alloc;

    base[id] = base._scope[id] = klass;

    if (superklass.$inherited) {
      superklass.$inherited(klass);
    }
  }

  return klass;
};

// Define new module (or return existing module)
Opal.module = function(base, id, constructor) {
  var klass;
  if (base._isObject) {
    base = base._real;
  }

  if (__hasOwn.call(base._scope, id)) {
    klass = base._scope[id];
  }
  else {
    klass = boot_module(constructor, id);
    klass._name = (base === Object ? id : base._name + '::' + id);

    klass._isModule = true;
    klass.$included_in = [];

    var const_alloc   = function() {};
    var const_scope   = const_alloc.prototype = new base._scope.alloc();
    klass._scope      = const_scope;
    const_scope.alloc = const_alloc;

    base[id] = base._scope[id]    = klass;
  }

  return klass;
}

// Convert a ruby method name into a javascript identifier
var mid_to_jsid = function(mid) {
  return method_names[mid] ||
    ('$' + mid.replace('!', '$b').replace('?', '$p').replace('=', '$e'));
};

// Utility function to raise a "no block given" error
var no_block_given = function() {
  throw new Error('no block given');
};

// An array of all classes inside Opal. Used for donating methods from
// Module and Class.
var classes = Opal.classes = [];

// Boot a base class (makes instances).
var boot_defclass = function(id, constructor, superklass) {
  if (superklass) {
    var ctor           = function() {};
        ctor.prototype = superklass.prototype;

    constructor.prototype = new ctor();
  }

  var prototype = constructor.prototype;

  prototype.constructor = constructor;
  prototype._isObject   = true;
  prototype._klass      = constructor;
  prototype._real       = constructor;

  constructor._included_in  = [];
  constructor._isClass      = true;
  constructor._name         = id;
  constructor._super        = superklass;
  constructor._methods      = [];
  constructor._smethods     = [];
  constructor._isObject     = false;
  constructor._subclasses   = [];

  constructor._donate = __donate;
  constructor._sdonate = __sdonate;

  Opal[id] = constructor;

  classes.push(constructor);

  return constructor;
};

// Create generic class with given superclass.
var boot_class = function(superklass, constructor) {
  var ctor = function() {};
      ctor.prototype = superklass.prototype;

  constructor.prototype = new ctor();
  var prototype = constructor.prototype;

  prototype._klass      = constructor;
  prototype._real       = constructor;
  prototype.constructor = constructor;

  constructor._included_in  = [];
  constructor._isClass      = true;
  constructor._super        = superklass;
  constructor._methods      = [];
  constructor._isObject     = false;
  constructor._klass        = Class;
  constructor._real         = Class;
  constructor._donate       = __donate
  constructor._sdonate      = __sdonate;
  constructor._subclasses   = [];

  constructor.$eqq$ = module_eqq;

  superklass._subclasses.push(constructor);

  var smethods;

  smethods = superklass._smethods.slice();

  constructor._smethods = smethods;
  for (var i = 0, length = smethods.length; i < length; i++) {
    var m = smethods[i];
    constructor[m] = superklass[m];
  }

  classes.push(constructor);

  return constructor;
};

var boot_module = function(constructor, id) {
  var ctor = function() {};
      ctor.prototype = Module.prototype;

  constructor.prototype = new ctor();
  var prototype = constructor.prototype;

  prototype.constructor = constructor;

  constructor._isModule = true;
  constructor._name     = id;
  constructor._methods  = [];
  constructor._smethods = [];
  constructor._klass    = Module;
  constructor._donate   = __donate;
  constructor._sdonate  = function(){};

  classes.push(constructor);

  var smethods = constructor._smethods = Module._methods.slice();
  for (var i = 0, length = smethods.length; i < length; i++) {
    var m = smethods[i];
    constructor[m] = Object[m];
  }

  return constructor;
};

var bridge_class = function(constructor) {
  constructor.prototype._klass = constructor;
  constructor.prototype._real = constructor;

  constructor._included_in  = [];
  constructor._isClass      = true;
  constructor._super        = Object;
  constructor._klass        = Class;
  constructor._methods      = [];
  constructor._smethods     = [];
  constructor._isObject     = false;
  constructor._subclasses   = [];

  constructor._donate = function(){};
  constructor._sdonate = __sdonate;

  constructor.$eqq$ = module_eqq;

  var smethods = constructor._smethods = Module._methods.slice();
  for (var i = 0, length = smethods.length; i < length; i++) {
    var m = smethods[i];
    constructor[m] = Object[m];
  }

  bridgedClasses.push(constructor);
  classes.push(constructor);

  var allocator = function(initializer) {
    var result, kls = this, methods = kls._methods, proto = kls.prototype;

    if (initializer == null) {
      result = new constructor
    }
    else {
      result = new constructor(initializer);
    }

    if (kls === constructor) {
      return result;
    }

    result._klass = kls;
    result._real  = kls;

    for (var i = 0, length = methods.length; i < length; i++) {
      var method = methods[i];
      result[method] = proto[method];
    }

    return result;
  };

  var table = Object.prototype, methods = Object._methods;

  for (var i = 0, length = methods.length; i < length; i++) {
    var m = methods[i];
    constructor.prototype[m] = table[m];
  }

  constructor.$allocate = allocator;

  constructor._smethods.push('$allocate');

  return constructor;
};

// An IClass is a fake class created when a module is included into a
// class or another module. It is a "copy" of the module that is then
// injected into the hierarchy so it appears internally that the iclass
// is the super of the class instead of the old super class. This is
// actually hidden from the ruby side of things, but allows internal
// features such as super() etc to work. All useful properties from the
// module are copied onto this iclass.
//
// @param [RubyClass] klass the klass which is including the module
// @param [RubyModule] module the module which is being included
// @return [RubyIClass] returns newly created iclass
var define_iclass = function(klass, module) {
  var iclass = {
    _proto:     module._proto,
    _super:     klass._super,
    _isIClass:  true,
    _klass:     module,
    _name:      module._name,
    _methods:   module._methods
  };

  klass._super = iclass;

  return iclass;
};

// Initialization
// --------------

boot_defclass('BasicObject', BasicObject);
boot_defclass('Object', Object, BasicObject);
boot_defclass('Class', Class, Object);

Class.prototype = Function.prototype;

BasicObject._klass = Object._klass = Class._klass = Class;

Module._donate = function(defined) {
  // ...
};

// Implementation of Module#===
function module_eqq(object) {
  if (object == null) {
    return false;
  }

  var search = object._klass;

  while (search) {
    if (search === this) {
      return true;
    }

    search = search._super;
  }

  return false;
}

// Donator for all 'normal' classes and modules
function __donate(defined, indirect) {
  var methods = this._methods, included_in = this.$included_in;

  if (!indirect) {
    this._methods = methods.concat(defined);
  }

  if (included_in) {
    for (var i = 0, length = included_in.length; i < length; i++) {
      var includee = included_in[i];
      var dest = includee.prototype;

      for (var j = 0, jj = defined.length; j < jj; j++) {
        var method = defined[j];
        dest[method] = this.prototype[method];
      }

      if (includee.$included_in) {
        includee._donate(defined, true);
      }
    }

  }
}

// Donator for singleton (class) methods
function __sdonate(defined) {
  var smethods = this._smethods, subclasses = this._subclasses;

  this._smethods = smethods.concat(defined);

  for (var i = 0, length = subclasses.length; i < length; i++) {
    var s = subclasses[i];

    for (var j = 0, jj = defined.length; j < jj; j++) {
    }
  }
}

var bridgedClasses = Object.$included_in = [];
BasicObject.$included_in = bridgedClasses;

BasicObject._scope = Object._scope = Opal;
Opal.Module = Opal.Class;
Opal.Kernel = Object;

var class_const_alloc = function(){};
var class_const_scope = new TopScope();
class_const_scope.alloc = class_const_alloc;
Class._scope = class_const_scope;

Object.prototype.toString = function() {
  return this.$to_s();
};

Opal.top = new Object;

Opal.klass(Object, Object, 'NilClass', NilClass)
Opal.nil = new NilClass;
Opal.nil.call = Opal.nil.apply = no_block_given;

Opal.breaker  = new Error('unexpected break');<commit_msg>Remove redundant Opal.classes array of defined classes<commit_after>// The Opal object that is exposed globally
var Opal = this.Opal = {};

// Very root class
function BasicObject(){}

// Core Object class
function Object(){}

// Class' class
function Class(){}

// Modules are just classes that cannot be instantiated
var Module = Class;

// the class of nil
function NilClass(){}

// TopScope is used for inheriting constants from the top scope
var TopScope = function(){};

// Opal just acts as the top scope
TopScope.prototype = Opal;

// To inherit scopes
Opal.alloc  = TopScope;

// This is a useful reference to global object inside ruby files
Opal.global = this;

// Minify common function calls
var __hasOwn = Opal.hasOwnProperty;
var __slice  = Opal.slice = Array.prototype.slice;

// Generates unique id for every ruby object
var unique_id = 0;

// Table holds all class variables
Opal.cvars = {};

// Globals table
Opal.gvars = {};

// Runtime method used to either define a new class, or re-open an old
// class. The base may be an object (rather than a class), which is
// always the case when defining classes in the top level as the top
// level is just the 'main' Object instance.
//
// The given ruby code:
//
//     class Foo
//       42
//     end
//
//     class Bar < Foo
//       3.142
//     end
//
// Would be compiled to something like:
//
//     var __klass = Opal.klass;
//
//     __klass(this, null, 'Foo', function() {
//       return 42;
//     });
//
//     __klass(this, __scope.Foo, 'Bar', function() {
//       return 3.142;
//     });
//
// @param [RubyObject] base the scope in which to define the class
// @param [RubyClass] superklass the superklass, may be null
// @param [String] id the name for the class
// @param [Function] body the class body
// @return returns last value from running body
Opal.klass = function(base, superklass, id, constructor) {
  var klass;
  if (base._isObject) {
    base = base._real;
  }

  if (superklass === null) {
    superklass = Object;
  }

  if (__hasOwn.call(base._scope, id)) {
    klass = base._scope[id];
  }
  else {
    if (!superklass._methods) {
      var bridged = superklass;
      superklass  = Object;
      klass       = bridge_class(bridged);
    }
    else {
      klass = boot_class(superklass, constructor);
    }

    klass._name = (base === Object ? id : base._name + '::' + id);

    var const_alloc   = function() {};
    var const_scope   = const_alloc.prototype = new base._scope.alloc();
    klass._scope      = const_scope;
    const_scope.alloc = const_alloc;

    base[id] = base._scope[id] = klass;

    if (superklass.$inherited) {
      superklass.$inherited(klass);
    }
  }

  return klass;
};

// Define new module (or return existing module)
Opal.module = function(base, id, constructor) {
  var klass;
  if (base._isObject) {
    base = base._real;
  }

  if (__hasOwn.call(base._scope, id)) {
    klass = base._scope[id];
  }
  else {
    klass = boot_module(constructor, id);
    klass._name = (base === Object ? id : base._name + '::' + id);

    klass._isModule = true;
    klass.$included_in = [];

    var const_alloc   = function() {};
    var const_scope   = const_alloc.prototype = new base._scope.alloc();
    klass._scope      = const_scope;
    const_scope.alloc = const_alloc;

    base[id] = base._scope[id]    = klass;
  }

  return klass;
}

// Convert a ruby method name into a javascript identifier
var mid_to_jsid = function(mid) {
  return method_names[mid] ||
    ('$' + mid.replace('!', '$b').replace('?', '$p').replace('=', '$e'));
};

// Utility function to raise a "no block given" error
var no_block_given = function() {
  throw new Error('no block given');
};

// Boot a base class (makes instances).
var boot_defclass = function(id, constructor, superklass) {
  if (superklass) {
    var ctor           = function() {};
        ctor.prototype = superklass.prototype;

    constructor.prototype = new ctor();
  }

  var prototype = constructor.prototype;

  prototype.constructor = constructor;
  prototype._isObject   = true;
  prototype._klass      = constructor;
  prototype._real       = constructor;

  constructor._included_in  = [];
  constructor._isClass      = true;
  constructor._name         = id;
  constructor._super        = superklass;
  constructor._methods      = [];
  constructor._smethods     = [];
  constructor._isObject     = false;
  constructor._subclasses   = [];

  constructor._donate = __donate;
  constructor._sdonate = __sdonate;

  Opal[id] = constructor;

  return constructor;
};

// Create generic class with given superclass.
var boot_class = function(superklass, constructor) {
  var ctor = function() {};
      ctor.prototype = superklass.prototype;

  constructor.prototype = new ctor();
  var prototype = constructor.prototype;

  prototype._klass      = constructor;
  prototype._real       = constructor;
  prototype.constructor = constructor;

  constructor._included_in  = [];
  constructor._isClass      = true;
  constructor._super        = superklass;
  constructor._methods      = [];
  constructor._isObject     = false;
  constructor._klass        = Class;
  constructor._real         = Class;
  constructor._donate       = __donate
  constructor._sdonate      = __sdonate;
  constructor._subclasses   = [];

  constructor.$eqq$ = module_eqq;

  superklass._subclasses.push(constructor);

  var smethods;

  smethods = superklass._smethods.slice();

  constructor._smethods = smethods;
  for (var i = 0, length = smethods.length; i < length; i++) {
    var m = smethods[i];
    constructor[m] = superklass[m];
  }

  return constructor;
};

var boot_module = function(constructor, id) {
  var ctor = function() {};
      ctor.prototype = Module.prototype;

  constructor.prototype = new ctor();
  var prototype = constructor.prototype;

  prototype.constructor = constructor;

  constructor._isModule = true;
  constructor._name     = id;
  constructor._methods  = [];
  constructor._smethods = [];
  constructor._klass    = Module;
  constructor._donate   = __donate;
  constructor._sdonate  = function(){};

  var smethods = constructor._smethods = Module._methods.slice();
  for (var i = 0, length = smethods.length; i < length; i++) {
    var m = smethods[i];
    constructor[m] = Object[m];
  }

  return constructor;
};

var bridge_class = function(constructor) {
  constructor.prototype._klass = constructor;
  constructor.prototype._real = constructor;

  constructor._included_in  = [];
  constructor._isClass      = true;
  constructor._super        = Object;
  constructor._klass        = Class;
  constructor._methods      = [];
  constructor._smethods     = [];
  constructor._isObject     = false;
  constructor._subclasses   = [];

  constructor._donate = function(){};
  constructor._sdonate = __sdonate;

  constructor.$eqq$ = module_eqq;

  var smethods = constructor._smethods = Module._methods.slice();
  for (var i = 0, length = smethods.length; i < length; i++) {
    var m = smethods[i];
    constructor[m] = Object[m];
  }

  bridged_classes.push(constructor);

  var allocator = function(initializer) {
    var result, kls = this, methods = kls._methods, proto = kls.prototype;

    if (initializer == null) {
      result = new constructor
    }
    else {
      result = new constructor(initializer);
    }

    if (kls === constructor) {
      return result;
    }

    result._klass = kls;
    result._real  = kls;

    for (var i = 0, length = methods.length; i < length; i++) {
      var method = methods[i];
      result[method] = proto[method];
    }

    return result;
  };

  var table = Object.prototype, methods = Object._methods;

  for (var i = 0, length = methods.length; i < length; i++) {
    var m = methods[i];
    constructor.prototype[m] = table[m];
  }

  constructor.$allocate = allocator;

  constructor._smethods.push('$allocate');

  return constructor;
};

// An IClass is a fake class created when a module is included into a
// class or another module. It is a "copy" of the module that is then
// injected into the hierarchy so it appears internally that the iclass
// is the super of the class instead of the old super class. This is
// actually hidden from the ruby side of things, but allows internal
// features such as super() etc to work. All useful properties from the
// module are copied onto this iclass.
//
// @param [RubyClass] klass the klass which is including the module
// @param [RubyModule] module the module which is being included
// @return [RubyIClass] returns newly created iclass
var define_iclass = function(klass, module) {
  var iclass = {
    _proto:     module._proto,
    _super:     klass._super,
    _isIClass:  true,
    _klass:     module,
    _name:      module._name,
    _methods:   module._methods
  };

  klass._super = iclass;

  return iclass;
};

// Initialization
// --------------

boot_defclass('BasicObject', BasicObject);
boot_defclass('Object', Object, BasicObject);
boot_defclass('Class', Class, Object);

Class.prototype = Function.prototype;

BasicObject._klass = Object._klass = Class._klass = Class;

Module._donate = function(defined) {
  // ...
};

// Implementation of Module#===
function module_eqq(object) {
  if (object == null) {
    return false;
  }

  var search = object._klass;

  while (search) {
    if (search === this) {
      return true;
    }

    search = search._super;
  }

  return false;
}

// Donator for all 'normal' classes and modules
function __donate(defined, indirect) {
  var methods = this._methods, included_in = this.$included_in;

  if (!indirect) {
    this._methods = methods.concat(defined);
  }

  if (included_in) {
    for (var i = 0, length = included_in.length; i < length; i++) {
      var includee = included_in[i];
      var dest = includee.prototype;

      for (var j = 0, jj = defined.length; j < jj; j++) {
        var method = defined[j];
        dest[method] = this.prototype[method];
      }

      if (includee.$included_in) {
        includee._donate(defined, true);
      }
    }

  }
}

// Donator for singleton (class) methods
function __sdonate(defined) {
  var smethods = this._smethods, subclasses = this._subclasses;

  this._smethods = smethods.concat(defined);

  for (var i = 0, length = subclasses.length; i < length; i++) {
    var s = subclasses[i];

    for (var j = 0, jj = defined.length; j < jj; j++) {
    }
  }
}

var bridged_classes = Object.$included_in = [];
BasicObject.$included_in = bridged_classes;

BasicObject._scope = Object._scope = Opal;
Opal.Module = Opal.Class;
Opal.Kernel = Object;

var class_const_alloc = function(){};
var class_const_scope = new TopScope();
class_const_scope.alloc = class_const_alloc;
Class._scope = class_const_scope;

Object.prototype.toString = function() {
  return this.$to_s();
};

Opal.top = new Object;

Opal.klass(Object, Object, 'NilClass', NilClass)
Opal.nil = new NilClass;
Opal.nil.call = Opal.nil.apply = no_block_given;

Opal.breaker  = new Error('unexpected break');<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var exec = require('child_process').exec;

function writeToFile(path, rawImageBuffer, done) {
  var imageBuffer = new Buffer(rawImageBuffer, 'base64');
  fs.writeFile(path, imageBuffer, done);
}

function compareAndSaveDiffOnMismatch(image1Buffer,
                                      image2Path,
                                      taskPath,
                                      done) {
  // in our use case, iamge1Buffer will always be a buffer of the temp image we
  // created
  var tempFileName = 'temp' + Math.random() + '.png';

  writeToFile(tempFileName, image1Buffer, function(err) {
    try {
      _checkIfDifferent(tempFileName, image2Path, function(err, areSame) {
        if (!areSame) {
          var diffPath = taskPath + '/diff.png';
          _saveDiffImage(tempFileName, image2Path, diffPath, function(err) {
            fs.unlinkSync(tempFileName);
            done(err, areSame);
          });
        } else {
          fs.unlinkSync(tempFileName);
          done(err, areSame);
        }
      });
    } catch (err) {
      fs.unlinkSync(tempFileName);
      done(err);
    }
  });
}

function _checkIfDifferent(image1Path, image2Path, done) {
  exec(
    'gm compare -metric mse "' + image1Path + '" "' + image2Path + '"',
    function (err, stdout) {
      if (err) return done(err);

      // the output is an ascii table, with the last row like this:
      // Total: 0.0000607584        0.0
      //           ^ what we want
      var match = /Total: (\d+\.?\d*)/m.exec(stdout);
      if (!match) return done('Unable to compare images: %s', stdout);

      var equality = parseFloat(match[1]);
      done(err, equality === 0);
    }
  );
}

function _saveDiffImage(image1Path, image2Path, diffPath, done) {
  exec(
    'gm compare -file "' + diffPath + '" "' + image1Path +
    '" "' + image2Path + '"',
    done
  );
}

function removeDanglingImages(taskPath, index, done) {
  // a new recording might take less screenshots than the previous
  var imagePath = taskPath + '/' + index + '.png';
  if (!fs.existsSync(imagePath)) return done();

  fs.unlink(imagePath, function(err) {
    if (err) return done(err);
    removeDanglingImages(taskPath, index + 1, done);
  });
}

module.exports = {
  writeToFile: writeToFile,
  compareAndSaveDiffOnMismatch: compareAndSaveDiffOnMismatch,
  removeDanglingImages: removeDanglingImages
};
<commit_msg>drop graphicsmagick dep<commit_after>'use strict';

var fs = require('fs');
var exec = require('child_process').exec;
var PNGDiff = require('png-diff');

function writeToFile(path, rawImageBuffer, done) {
  var imageBuffer = new Buffer(rawImageBuffer, 'base64');
  fs.writeFile(path, imageBuffer, done);
}

function compareAndSaveDiffOnMismatch(image1Buffer,
                                      image2Path,
                                      taskPath,
                                      done) {
  // in our use case, iamge1Buffer will always be a buffer of the temp image we
  // created
  var tempFileName = 'temp' + Math.random() + '.png';

  writeToFile(tempFileName, image1Buffer, function(err) {
    PNGDiff.measureDiff(tempFileName, image2Path, function(err, diffMetric) {
      if (err) {
        fs.unlinkSync(tempFileName);
        return done(err);
      }

      var areSame = diffMetric === 0;
      if (!areSame) {
        var diffPath = taskPath + '/diff.png';
        PNGDiff.outputDiff(tempFileName, image2Path, diffPath, function(err) {
          done(err, areSame);
        });
      } else {
        done(err, areSame);
      }
      fs.unlinkSync(tempFileName);
    });
  });
}

function removeDanglingImages(taskPath, index, done) {
  // a new recording might take less screenshots than the previous
  var imagePath = taskPath + '/' + index + '.png';
  if (!fs.existsSync(imagePath)) return done();

  fs.unlink(imagePath, function(err) {
    if (err) return done(err);

    removeDanglingImages(taskPath, index + 1, done);
  });
}

module.exports = {
  writeToFile: writeToFile,
  compareAndSaveDiffOnMismatch: compareAndSaveDiffOnMismatch,
  removeDanglingImages: removeDanglingImages
};
<|endoftext|>


<commit_before>
/**
 * @file
 * Main JS.
 *
 * Created by: Topsitemakers
 * http://www.topsitemakers.com/
 */
$(document).ready(function(){

  //

});
<commit_msg>adding sample log and jquerynoc to main.js<commit_after>
/**
 * @file
 * Main JS.
 *
 * Created by: Topsitemakers
 * http://www.topsitemakers.com/
 */

jQuery.noConflict();
jQuery(document).ready(function($) {

  console.log('main.js loaded');

});
<|endoftext|>


<commit_before>/**
 * CreditsPopup.js
 *
 * Show game credits.
 *
 */

MemoryMatch.CreditsPopup = {
    parentDisplayObject: null,
    groupDisplayObject: null,
    buttonHelperInstances: null,
    buttonInstances: null,
    backgroundWidth: 0,
    backgroundHeight: 0,
    backgroundCover: null,
    marginTop: 0,
    marginLeft: 0,
    centerX: 0,
    marginX: 0,
    lineHeight: 0,
    isEnabled: false,
    title: null,
    closeButton: true,
    stateCompleteCallback: null,
    primaryColorFilter: null,
    secondaryColorFilter: null,
    primaryColorValue: null,
    secondaryColorValue: null,

    setup: function (displayObject, stateCompleteCallback) {
        this.parentDisplayObject = displayObject;
        this.buttonHelperInstances = [];
        this.buttonInstances = [];
        this.stateCompleteCallback = stateCompleteCallback;
    },

    buildScreen: function (autoStart) {
        if (this.groupDisplayObject !== null) {
            return;
        }
        // layout the screen
        this.groupDisplayObject = new createjs.Container();
        this.setColorFilters();
        this.showBackgroundImage(this.parentDisplayObject.canvas);
        this.marginTop = this.backgroundHeight * 0.05;
        this.marginLeft = this.backgroundWidth * 0.09;
        this.centerX = this.backgroundWidth * 0.5;
        this.marginX = 12 * MemoryMatch.stageScaleFactor;
        this.setupTitleText();
        this.setupCopyrightText();
        this.showCredits();
        this.setupButtons();
        this.parentDisplayObject.addChild(this.groupDisplayObject);
        this.groupDisplayObject.setTransform(this.parentDisplayObject.canvas.width * 0.5, this.parentDisplayObject.canvas.height * 0.5, 1, 1, 0, 0, 0, this.backgroundWidth * 0.5, this.backgroundHeight * 0.5);
        if (autoStart === null) {
            autoStart = false;
        }
        if (autoStart) {
            this.start();
        }
    },

    start: function () {
        // No animation for Credits
        this.isEnabled = true;
    },

    closeStartAnimation: function () {
        var duration = 0.1, // seconds of animation
            animator = MemoryMatch.AnimationHandler.addToAnimationQueue(this.groupDisplayObject, 0, duration * 1000, false, null, this.closeShrink.bind(this));

        animator.endYScale = animator.endXScale = 1.08;
        animator.vYScale = animator.vXScale = animator.endXScale / (duration * MemoryMatch.fps);
    },

    closeShrink: function () {
        var duration = 0.3, // seconds of animation
            animator = MemoryMatch.AnimationHandler.addToAnimationQueue(this.groupDisplayObject, 0, duration * 1000, false, null, this.closeComplete.bind(this));

        animator.endYScale = animator.endXScale = 0;
        animator.vYScale = animator.vXScale = (-1 * this.groupDisplayObject.scaleX) / (duration * MemoryMatch.fps);
    },

    closeComplete: function () {
        this.killScreen();
    },

    closePopup: function (closeEventType) {
        // begin animation and send notification we're done here
        this.isEnabled = false;
        if (this.stateCompleteCallback !== null) {
            this.stateCompleteCallback("close");
        }
        this.closeStartAnimation();
    },

    onClickClose: function (event) {
        if (this.isEnabled) {
            this.closePopup("close");
        }
    },

    onClickBackground: function (event) {
        // this just eats the click so anything under the popup is not activated
    },

    showBackgroundImage: function (canvas) {
        // This method will scale the background image to fit the current stage if it is too big.
        var popupImageAsset = assetLoader.getResult("popup-bg"),
            bgImage = new createjs.Bitmap(popupImageAsset),
            xScale,
            yScale,
            backgroundCover;

        if (popupImageAsset.width > canvas.width) {
            xScale = canvas.width / popupImageAsset.width;
        } else {
            xScale = 1;
        }
        if (popupImageAsset.height > canvas.height) {
            yScale = canvas.height / popupImageAsset.height;
        } else {
            yScale = 1;
        }
        bgImage.alpha = 1;
        bgImage.scaleX = xScale;
        bgImage.scaleY = yScale;

        backgroundCover = new createjs.Shape();
        backgroundCover.graphics.beginFill("#CCCCCC").drawRect(0, 0, canvas.width, canvas.height);
        backgroundCover.alpha = 0.1;
        backgroundCover.addEventListener("click", this.onClickBackground);
        this.backgroundCover = backgroundCover;
        this.parentDisplayObject.addChild(backgroundCover);
        this.groupDisplayObject.addChild(bgImage);
        this.backgroundWidth = popupImageAsset.width * xScale;
        this.backgroundHeight = popupImageAsset.height * yScale;
        if (this.primaryColorFilter != null) {
            bgImage.filters = [this.primaryColorFilter];
            bgImage.cache(0, 0, this.backgroundWidth, this.backgroundHeight);
        }
    },

    setupTitleText: function () {
        var titleTextField;

        titleTextField = new createjs.Text("Credits", MemoryMatch.getScaledFontSize(72) + " " + MemoryMatch.GameSetup.guiBoldFontName, MemoryMatch.GameSetup.guiFontColor);
        titleTextField.textAlign = "center";
        titleTextField.x = this.backgroundWidth * 0.5;
        titleTextField.y = this.marginTop;
        titleTextField.lineWidth = this.backgroundWidth - (this.marginLeft * 2);
        titleTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(titleTextField);
    },

    showCredits: function () {
        var titleTextField,
            text = 'This game was made by JumpyDot using the EaselJS HTML5 framework.';

        titleTextField = new createjs.Text(text, MemoryMatch.getScaledFontSize(52) + " " + MemoryMatch.GameSetup.guiMediumFontName, MemoryMatch.GameSetup.guiFontColor);
        titleTextField.textAlign = "left";
        titleTextField.x = this.marginLeft;
        titleTextField.y = this.backgroundHeight * 0.24;
        titleTextField.lineWidth = this.backgroundWidth - (this.marginLeft * 2);
        titleTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(titleTextField);

        text = 'Julia Deter-Keren: Game Design & Art Direction\n\nJohn Foster:     Programming & Audio\n\nDan Hart:  Game Design & Product Management\n\nRobert Prescott:     Quality Assurance';
        titleTextField = new createjs.Text(text, MemoryMatch.getScaledFontSize(56) + " " + MemoryMatch.GameSetup.guiMediumFontName, MemoryMatch.GameSetup.guiFontColor);
        titleTextField.textAlign = "center";
        titleTextField.x = this.backgroundWidth * 0.5;
        titleTextField.y = this.backgroundHeight * 0.4;
        titleTextField.lineWidth = this.backgroundWidth - (this.marginLeft * 2);
        titleTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(titleTextField);

        // Show the JumpyDot logo
        var spriteData = new createjs.SpriteSheet(MemoryMatch.GameSetup.guiSpritesheet2Frames);
        var iconSprite = new createjs.Sprite(spriteData, "JumpyDotLogo");
        iconSprite.setTransform(this.backgroundWidth * 0.15, this.backgroundHeight * 0.70);
        iconSprite.framerate = 1;
        this.groupDisplayObject.addChild(iconSprite);

        // Show the HTML5 icon
        iconSprite = new createjs.Sprite(spriteData, "html5-logo");
        iconSprite.setTransform(this.backgroundWidth * 0.80, this.backgroundHeight * 0.73);
        iconSprite.framerate = 1;
        this.groupDisplayObject.addChild(iconSprite);
    },

    setupCopyrightText: function () {
        var info = 'Copyright 2014 JumpyDot. All rights reserved.',
            infoTextField = new createjs.Text(info, MemoryMatch.getScaledFontSize(36) + " " + MemoryMatch.GameSetup.guiMediumFontName, MemoryMatch.GameSetup.guiInfoColor);

        infoTextField.textAlign = "center";
        infoTextField.x = this.backgroundWidth * 0.5;
        infoTextField.y = this.backgroundHeight * 0.88;
        infoTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(infoTextField);
    },

    setupButtons: function () {
        var spriteFrame,
            spriteData = new createjs.SpriteSheet(MemoryMatch.GameSetup.guiSpritesheet1Frames),
            buttonScale = 1.0,
            gameButton,
            newButtonInstance,
            buttonSize;

        // Close button always shows in its own special place
        gameButton = MemoryMatch.GUIButton({name: "close", tag: 1, disabled: false, callback: this.onClickClose.bind(this), baseUp: "closeButtonUp", baseOver: "closeButtonDown", baseDown: "closeButtonDown"});
        buttonSize = gameButton.getSize();
        gameButton.setTransform(this.backgroundWidth * 0.94 - buttonSize.width, this.backgroundHeight * 0.05, buttonScale, buttonScale);
        this.groupDisplayObject.addChild(gameButton);
        this.buttonInstances.push(gameButton);
    },

    isShowing: function () {
        return this.groupDisplayObject !== null && this.groupDisplayObject.visible;
    },

    setColorFilters: function () {
        var primaryColor,
            secondaryColor;

        this.primaryColorValue = MemoryMatch.GameSetup.levels[MemoryMatch.gameLevel - 1].primaryColor;
        this.secondaryColorValue = MemoryMatch.GameSetup.levels[MemoryMatch.gameLevel - 1].primaryColor;
        if (this.primaryColorValue != null) {
            primaryColor = MemoryMatch.htmlColorStringToColorArray(this.primaryColorValue);
            this.primaryColorFilter = new createjs.ColorFilter(0, 0, 0, 1, primaryColor[0], primaryColor[1], primaryColor[2], 0);
        } else {
            this.primaryColorFilter = null;
        }
        if (this.secondaryColorValue != null) {
            secondaryColor = MemoryMatch.htmlColorStringToColorArray(this.secondaryColorValue);
            this.secondaryColorFilter = new createjs.ColorFilter(0, 0, 0, 1, secondaryColor[0], secondaryColor[1], secondaryColor[2], 0);
        } else {
            this.secondaryColorFilter = null;
        }
    },

    killScreen: function () {
        // remove all display objects and object references:
        var i;

        this.primaryColorFilter = null;
        this.secondaryColorFilter = null;
        if (this.buttonInstances !== null) {
            for (i = 0; i < this.buttonInstances.length; i ++) {
                this.buttonInstances[i].removeAllEventListeners();
            }
            this.buttonInstances = null;
        }
        this.buttonHelperInstances = null;
        this.parentDisplayObject.removeChild(this.groupDisplayObject);
        this.parentDisplayObject.removeChild(this.backgroundCover);
        this.backgroundCover = null;
        this.parentDisplayObject = null;
        this.groupDisplayObject = null;
    }
};
<commit_msg>change credits layout<commit_after>/**
 * CreditsPopup.js
 *
 * Show game credits.
 *
 */

MemoryMatch.CreditsPopup = {
    parentDisplayObject: null,
    groupDisplayObject: null,
    buttonHelperInstances: null,
    buttonInstances: null,
    backgroundWidth: 0,
    backgroundHeight: 0,
    backgroundCover: null,
    marginTop: 0,
    marginLeft: 0,
    centerX: 0,
    marginX: 0,
    lineHeight: 0,
    isEnabled: false,
    title: null,
    closeButton: true,
    stateCompleteCallback: null,
    primaryColorFilter: null,
    secondaryColorFilter: null,
    primaryColorValue: null,
    secondaryColorValue: null,

    setup: function (displayObject, stateCompleteCallback) {
        this.parentDisplayObject = displayObject;
        this.buttonHelperInstances = [];
        this.buttonInstances = [];
        this.stateCompleteCallback = stateCompleteCallback;
    },

    buildScreen: function (autoStart) {
        if (this.groupDisplayObject !== null) {
            return;
        }
        // layout the screen
        this.groupDisplayObject = new createjs.Container();
        this.setColorFilters();
        this.showBackgroundImage(this.parentDisplayObject.canvas);
        this.marginTop = this.backgroundHeight * 0.05;
        this.marginLeft = this.backgroundWidth * 0.09;
        this.centerX = this.backgroundWidth * 0.5;
        this.marginX = 12 * MemoryMatch.stageScaleFactor;
        this.setupTitleText();
        this.setupCopyrightText();
        this.showCredits();
        this.setupButtons();
        this.parentDisplayObject.addChild(this.groupDisplayObject);
        this.groupDisplayObject.setTransform(this.parentDisplayObject.canvas.width * 0.5, this.parentDisplayObject.canvas.height * 0.5, 1, 1, 0, 0, 0, this.backgroundWidth * 0.5, this.backgroundHeight * 0.5);
        if (autoStart === null) {
            autoStart = false;
        }
        if (autoStart) {
            this.start();
        }
    },

    start: function () {
        // No animation for Credits
        this.isEnabled = true;
    },

    closeStartAnimation: function () {
        var duration = 0.1, // seconds of animation
            animator = MemoryMatch.AnimationHandler.addToAnimationQueue(this.groupDisplayObject, 0, duration * 1000, false, null, this.closeShrink.bind(this));

        animator.endYScale = animator.endXScale = 1.08;
        animator.vYScale = animator.vXScale = animator.endXScale / (duration * MemoryMatch.fps);
    },

    closeShrink: function () {
        var duration = 0.3, // seconds of animation
            animator = MemoryMatch.AnimationHandler.addToAnimationQueue(this.groupDisplayObject, 0, duration * 1000, false, null, this.closeComplete.bind(this));

        animator.endYScale = animator.endXScale = 0;
        animator.vYScale = animator.vXScale = (-1 * this.groupDisplayObject.scaleX) / (duration * MemoryMatch.fps);
    },

    closeComplete: function () {
        this.killScreen();
    },

    closePopup: function (closeEventType) {
        // begin animation and send notification we're done here
        this.isEnabled = false;
        if (this.stateCompleteCallback !== null) {
            this.stateCompleteCallback("close");
        }
        this.closeStartAnimation();
    },

    onClickClose: function (event) {
        if (this.isEnabled) {
            this.closePopup("close");
        }
    },

    onClickBackground: function (event) {
        // this just eats the click so anything under the popup is not activated
    },

    showBackgroundImage: function (canvas) {
        // This method will scale the background image to fit the current stage if it is too big.
        var popupImageAsset = assetLoader.getResult("popup-bg"),
            bgImage = new createjs.Bitmap(popupImageAsset),
            xScale,
            yScale,
            backgroundCover;

        if (popupImageAsset.width > canvas.width) {
            xScale = canvas.width / popupImageAsset.width;
        } else {
            xScale = 1;
        }
        if (popupImageAsset.height > canvas.height) {
            yScale = canvas.height / popupImageAsset.height;
        } else {
            yScale = 1;
        }
        bgImage.alpha = 1;
        bgImage.scaleX = xScale;
        bgImage.scaleY = yScale;

        backgroundCover = new createjs.Shape();
        backgroundCover.graphics.beginFill("#CCCCCC").drawRect(0, 0, canvas.width, canvas.height);
        backgroundCover.alpha = 0.1;
        backgroundCover.addEventListener("click", this.onClickBackground);
        this.backgroundCover = backgroundCover;
        this.parentDisplayObject.addChild(backgroundCover);
        this.groupDisplayObject.addChild(bgImage);
        this.backgroundWidth = popupImageAsset.width * xScale;
        this.backgroundHeight = popupImageAsset.height * yScale;
        if (this.primaryColorFilter != null) {
            bgImage.filters = [this.primaryColorFilter];
            bgImage.cache(0, 0, this.backgroundWidth, this.backgroundHeight);
        }
    },

    setupTitleText: function () {
        var titleTextField;

        titleTextField = new createjs.Text("Credits", MemoryMatch.getScaledFontSize(72) + " " + MemoryMatch.GameSetup.guiBoldFontName, MemoryMatch.GameSetup.guiFontColor);
        titleTextField.textAlign = "center";
        titleTextField.x = this.backgroundWidth * 0.5;
        titleTextField.y = this.marginTop;
        titleTextField.lineWidth = this.backgroundWidth - (this.marginLeft * 2);
        titleTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(titleTextField);
    },

    showCredits: function () {
        var titleTextField,
            text1 = 'This game was made by JumpyDot using the EaselJS HTML5 framework.',
            text2 = 'Julia Deter-Keren: Game Design & Art Direction\n\nJohn Foster:     Programming & Audio\n\nDan Hart:  Game Design & Product Management\n\nRobert Prescott:     Quality Assurance';

        titleTextField = new createjs.Text(text1, MemoryMatch.getScaledFontSize(52) + " " + MemoryMatch.GameSetup.guiMediumFontName, MemoryMatch.GameSetup.guiFontColor);
        titleTextField.textAlign = "left";
        titleTextField.x = this.marginLeft;
        titleTextField.y = this.backgroundHeight * 0.2;
        titleTextField.lineWidth = this.backgroundWidth - (this.marginLeft * 2);
        titleTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(titleTextField);

        titleTextField = new createjs.Text(text2, MemoryMatch.getScaledFontSize(56) + " " + MemoryMatch.GameSetup.guiMediumFontName, MemoryMatch.GameSetup.guiFontColor);
        titleTextField.textAlign = "center";
        titleTextField.x = this.backgroundWidth * 0.5;
        titleTextField.y = this.backgroundHeight * 0.3;
        titleTextField.lineWidth = this.backgroundWidth - (this.marginLeft * 2);
        titleTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(titleTextField);

        // Show the JumpyDot logo
        var spriteData = new createjs.SpriteSheet(MemoryMatch.GameSetup.guiSpritesheet2Frames);
        var iconSprite = new createjs.Sprite(spriteData, "JumpyDotLogo");
        iconSprite.setTransform(this.backgroundWidth * 0.15, this.backgroundHeight * 0.70);
        iconSprite.framerate = 1;
        this.groupDisplayObject.addChild(iconSprite);

        // Show the HTML5 icon
        iconSprite = new createjs.Sprite(spriteData, "html5-logo");
        iconSprite.setTransform(this.backgroundWidth * 0.80, this.backgroundHeight * 0.73);
        iconSprite.framerate = 1;
        this.groupDisplayObject.addChild(iconSprite);
    },

    setupCopyrightText: function () {
        var info = 'Copyright 2014 JumpyDot. All rights reserved.',
            infoTextField = new createjs.Text(info, MemoryMatch.getScaledFontSize(36) + " " + MemoryMatch.GameSetup.guiMediumFontName, MemoryMatch.GameSetup.guiInfoColor);

        infoTextField.textAlign = "center";
        infoTextField.x = this.backgroundWidth * 0.5;
        infoTextField.y = this.backgroundHeight * 0.88;
        infoTextField.maxWidth = this.backgroundWidth - (this.marginLeft * 2);
        this.groupDisplayObject.addChild(infoTextField);
    },

    setupButtons: function () {
        var spriteFrame,
            spriteData = new createjs.SpriteSheet(MemoryMatch.GameSetup.guiSpritesheet1Frames),
            buttonScale = 1.0,
            gameButton,
            newButtonInstance,
            buttonSize;

        // Close button always shows in its own special place
        gameButton = MemoryMatch.GUIButton({name: "close", tag: 1, disabled: false, callback: this.onClickClose.bind(this), baseUp: "closeButtonUp", baseOver: "closeButtonDown", baseDown: "closeButtonDown"});
        buttonSize = gameButton.getSize();
        gameButton.setTransform(this.backgroundWidth * 0.94 - buttonSize.width, this.backgroundHeight * 0.05, buttonScale, buttonScale);
        this.groupDisplayObject.addChild(gameButton);
        this.buttonInstances.push(gameButton);
    },

    isShowing: function () {
        return this.groupDisplayObject !== null && this.groupDisplayObject.visible;
    },

    setColorFilters: function () {
        var primaryColor,
            secondaryColor;

        this.primaryColorValue = MemoryMatch.GameSetup.levels[MemoryMatch.gameLevel - 1].primaryColor;
        this.secondaryColorValue = MemoryMatch.GameSetup.levels[MemoryMatch.gameLevel - 1].primaryColor;
        if (this.primaryColorValue != null) {
            primaryColor = MemoryMatch.htmlColorStringToColorArray(this.primaryColorValue);
            this.primaryColorFilter = new createjs.ColorFilter(0, 0, 0, 1, primaryColor[0], primaryColor[1], primaryColor[2], 0);
        } else {
            this.primaryColorFilter = null;
        }
        if (this.secondaryColorValue != null) {
            secondaryColor = MemoryMatch.htmlColorStringToColorArray(this.secondaryColorValue);
            this.secondaryColorFilter = new createjs.ColorFilter(0, 0, 0, 1, secondaryColor[0], secondaryColor[1], secondaryColor[2], 0);
        } else {
            this.secondaryColorFilter = null;
        }
    },

    killScreen: function () {
        // remove all display objects and object references:
        var i;

        this.primaryColorFilter = null;
        this.secondaryColorFilter = null;
        if (this.buttonInstances !== null) {
            for (i = 0; i < this.buttonInstances.length; i ++) {
                this.buttonInstances[i].removeAllEventListeners();
            }
            this.buttonInstances = null;
        }
        this.buttonHelperInstances = null;
        this.parentDisplayObject.removeChild(this.groupDisplayObject);
        this.parentDisplayObject.removeChild(this.backgroundCover);
        this.backgroundCover = null;
        this.parentDisplayObject = null;
        this.groupDisplayObject = null;
    }
};
<|endoftext|>


<commit_before>window.onload = function onWindowLoaded () {
    enchant();

    var game = new Game(640, 960);
    game.fps = 60;
    var logger = new jam.Logger({console: console});
    var app = new jam.Application({game: game, logger: logger});
    var topLevel = new jam.Level({
        name: 'top',
        preload: function (context) {
            context.app.log(context.game);
            context.app.log("Preloading topLevel...");
            context.game.preload('img/mikoto.png');
            context.game.preload('img/top_background.png');
            context.game.preload('img/top_list_button.png');
            context.game.preload('img/mikoto.png');
        },
        load: function (context, params) {
            var game = context.game;
            var app = context.app;

            app.log("params=", params, "context=", context);

            var scene = (function () {
                var background = new Sprite();
                background.image = game.assets['img/top_background.png'];
                background.width = game.width;
                background.height = game.height;

                var listButton = new Sprite();
                listButton.image = game.assets['img/top_list_button.png'];
                listButton.width = 637
                listButton.height = 346;
                listButton.y = 500;

                listButton.tl
                    .hide()
                    .and()
                    .scaleTo(0, 0)
                    .fadeIn(50, enchant.Easing.BOUNCE_EASEOUT)
                    .and()
                    .scaleTo(1, 50, enchant.Easing.BOUNCE_EASEOUT);

                listButton.addEventListener('touchstart', function () {
                    app.log(window);

                    background.tl
                        .fadeOut(50)
                        .then(function () {
                            app.loadLevel('selectStage', {foo:"bar"});
                        });
                });
                listButton.addEventListener('touchend', function () {
                });

                var scene = new Scene();
                scene.addChild(background);
                scene.addChild(listButton);

                return scene;
            })();

            var frameCount = 0;
            this.onEnterFrame = function () {
                frameCount ++;

                if (frameCount % 100 == 0) {
                    context.app.log(frameCount + " frames has passed until now.");
                }
            };
            game.addEventListener('enterframe', this.onEnterFrame);

            return { scene: scene };
        },
        unload: function (context) {
            var game = context.game;
            game.removeEventListener('enterframe', this.onEnterFrame);
            this.onEnterFrame = null;
        }
    });

    var levelTwo = new jam.Level({
        name: "two",
        load: function (context, params) {
            var scene = new Scene();

            var label = new Label("Level 2: params=" + params);
            label.x = 32;
            label.y = 32;

            var ball = new Sprite(50, 50);
            var surface = new Surface(50, 50);
            surface.context.beginPath();
            surface.context.arc(25, 25, 25, 0, Math.PI*2, true);
            surface.context.fill();
            ball.image = surface;

            scene.addChild(label);
            scene.addChild(ball);
            return { scene: scene };
        },
        unload: function (context, params) {
        }
    });

    var template = new jam.Level({
        name: "template",
        preload: function (context) {
            // context.game.preload('img/mikoto.png');
        },
        load: function (context, params) {
            // var scene = new Scene();
            // return { scene: scene };
        },
        unload: function (context) {

        }
    });

    // ステージ選択
    var selectStage = new jam.Level({
        name: "selectStage",
        preload: function (context) {
            // context.game.preload('img/mikoto.png');
            context.game.preload('img/stage_0.jpg');
        },
        load: function (context, params) {
            var app = context.app;
            var game = context.game;

            var scene = new Scene();

            scene.backgroundColor = "#eeeeee";

            var w = game.width / 2;
            var h = game.height / Math.ceil(window.assets.stages.length / 2);

            var colors = ["#56ADFB", "#19436F", "#15141D"];

            window.assets.stages.forEach(function (stage, i) {
                var components = stage.name.replace("）", "").split("（");
                var charaName = components[0];
                var categoryName = components[1];

                var group = new Group();
                group.width = w;
                group.height = h;
                group.x = w * (i % 2);
                group.y = h * Math.floor(i / 2);

                var charaLabel = new Label(charaName);
                charaLabel.font = "bold 70px serif";
                charaLabel.color = "#ffffff";
                charaLabel.opacity = 0.6;
                charaLabel.touchEnabled = true;

                var categoryLabel = new Label(categoryName);
                categoryLabel.font = "30px sans-serif";
                categoryLabel.color = "#ffffff";
                categoryLabel.opacity = 0.3;
                categoryLabel.y = 80;
                categoryLabel.touchEnabled = true;

                var background = new Sprite();
                background.width = w;
                background.height = h;
                background.opacity = 0.8;
                background.touchEnabled = true;
                background.backgroundColor = colors[(i % colors.length)];
                background.image = game.assets['img/stage_0.jpg']

                var touchArea = new Sprite();
                touchArea.width = w;
                touchArea.height = h;
                touchArea.opacity = 0.8;
                touchArea.touchEnabled = true;
                touchArea.backgroundColor = colors[(i % colors.length)];

                group.addChild(background);
                group.addChild(touchArea);
                group.addChild(charaLabel);
                group.addChild(categoryLabel);

                group.addEventListener('touchstart', function (e) {
                    touchArea.backgroundColor = scene.backgroundColor;
                });

                group.addEventListener('touchend', function (e) {
                    touchArea.backgroundColor = colors[(i % colors.length)];
                    var stage = window.assets.stages[i];
                    app.loadLevel('playStage', { stage: stage })
                });

                scene.addChild(group);
            });

            return { scene: scene };
        },
        unload: function (context) {

        }
    });

    // クイズ画面
    var playStage = new jam.Level({
        name: "playStage",
        preload: function (context) {
            context.app.log(context.game);
            context.app.log('Preloading level...');
        },
        load: function (context, params) {
            var game = context.game;
            var app = context.app;

            app.log("params=", params, "context=", context);

            var scene = (function () {
                // ダミークイズデータ
                var dummies = [
                    {
                        "text": "先輩に呼ばれたときの返事で適切なのは？",
                        "choices": ['はい', 'え？', 'うん', 'なに？'],
                        "correct_choice": 'はい',
                        "correct_choice_index": 0
                    },
                    {
                        "text": "任された仕事が終わった時、正しいのは？",
                        "choices": [
                            '終わっても報告しない',
                            'さっさと次の仕事に取り組む',
                            'すぐに報告する',
                            '同僚に自慢する'
                        ],
                        "correct_choice": 'すぐに報告する',
                        "correct_choice_index": 2
                    },
                ];
                var num = 10;
                var scene = new Scene();
                var pos_list = [
                    [ 15, 720 ],
                    [ 325, 720 ],
                    [ 15, 840 ],
                    [ 325, 840 ]
                ];
                var current = {
                    quiz: null,
                    index: null,
                };

                // Entity
                var l_quiz;
                var spr_character;
                var btn_choice = {
                    list: [],
                    size: [280, 110],
                    font: '32px/48px serif',
                };
                var stage_quizzes = params.stage.quizzes;
                var quizzes;

                // クイズデータを無作為に作成
                var choiceQuizzes = function (quizzes, num) {
                    if (quizzes.length < num) {
                        return quizzes;
                    }
                    var c_quizzes = [];
                    var history = [];
                    var cnt = quizzes.length;
                    var rnd;

                    for (i = 0; i < num; ) {
                        rnd = Math.random() * cnt | 0;

                        if (history.indexOf(rnd) > -1) {
                            continue;
                        }

                        c_quizzes.push(quizzes[rnd]);
                        history.push(rnd);
                        i++;
                    }

                    return c_quizzes;
                };

                // クイズの読み込み
                var loadQuiz = function(quiz) {
                    l_quiz.text = quiz.text;
                    quiz.choices.forEach(function(choice, i) {
                        btn_choice.list[i].text = choice;
                    });
                };
                // 画面の初期化
                var initLevel = function() {
                    // 背景色指定
                    scene.backgroundColor = '#CCCCCC';

                    // Entity生成
                    l_quiz = new Label();
                    l_quiz.backgroundColor = '#FFFFFF';
                    l_quiz.width = 420;
                    l_quiz.height = 155;
                    l_quiz.font = '32px serif';
                    l_quiz.moveTo(18, 505);

                    spr_character = new Entity();
                    spr_character.width = 420;
                    spr_character.height = 420;
                    spr_character.backgroundColor = 'blue';
                    spr_character.moveTo(18, 70);

                    btn_kobi = new Button('こび', 'light');
                    btn_kobi.width = 150;
                    btn_kobi.height = 150;
                    btn_kobi.moveTo(455, 505);

                    for ( i = 0; i < 4; i++ ) {
                        var btn = new Button('select'+i, 'light');

                        btn.index = i;
                        btn.font = btn_choice.font;
                        btn.width = btn_choice.size[0];
                        btn.height = btn_choice.size[1];
                        btn.ontouchend = function(evt) {
                            judgeChoice(evt.target.index);
                        }

                        btn.moveTo(pos_list[i][0], pos_list[i][1]);
                        btn_choice.list.push(btn);
                    }

                    // 画面への追加
                    scene.addChild(l_quiz);
                    scene.addChild(spr_character);
                    scene.addChild(btn_kobi);
                    btn_choice.list.forEach(function (btn) {
                        scene.addChild(btn);
                    });

                    quizzes = choiceQuizzes(stage_quizzes, num);
                    loadQuiz(quizzes[pointer]);
                };

                // 選択を判定
                var judgeChoice = function(index) {
                    app.log('choiced: ' + index);
                    app.log(' text: ' + quizzes[pointer].text);
                    app.log(' answer: ' + quizzes[pointer].correct_choice);
                    showJudgeResult(quizzes[pointer].correct_choice_index == index);
                };

                // 結果を表示
                var showJudgeResult = function(is_correct) {
                    var judge = is_correct ? '正解' : '不正解';
                    app.log(judge);

                    fetchNext();
                };

                // 次を取得
                var fetchNext = function() {
                    pointer++;
                    app.log(pointer);
                    app.log(quizzes.length);

                    // 次はあるか
                    if (pointer < quizzes.length) {
                        loadQuiz(quizzes[pointer]);
                        return ;
                    }

                    app.loadLevel('selectStage', {});
                };

                // ポインタの初期化
                var pointer = 0;
                // ふぁいあー
                initLevel();
                return scene;
            })();

            return { scene: scene };
        },
        unload: function (context) {
        }
    });

    var playRoulette = new jam.Level({
        name: "playRoulette",
        preload: function (context) {
            context.game.preload('img/roulette.png');
            context.game.preload('img/stage_roulette.png');
        },
        load: function (context, params) {
            var game = context.game;
            var app = context.app;
            var stage = params.stage;

            var scene = new Scene();

            var rotationForce = 5 + Math.random() * 2;
            var unitTime = 10;
            var rotationTime = unitTime * rotationForce;

            var background = new Sprite();
            background.image = game.assets['img/stage_roulette.png'];
            background.width = game.width;
            background.height = game.height;

            var roulette = new Sprite();
            roulette.image = game.assets['img/roulette.png']
            roulette.width = 300;
            roulette.height = 300;
            roulette.scaleX = 1.5;
            roulette.scaleY = 1.5;
            roulette.x = 170;
            roulette.y = 300;

            roulette.addEventListener('touchend', function () {
                roulette.tl.rotateBy(360 * rotationForce, rotationTime);
                roulette.tl.then(function () {
                    var earnedLifePoints = Math.floor(Math.random() * 1.9999 + 1);

                    var scoreBackground = new Sprite();
                    scoreBackground.backgroundColor = "#666666";
                    scoreBackground.opacity = 0.8;
                    scoreBackground.width = game.width;
                    scoreBackground.height = game.height;

                    var scoreX = 100;
                    var scoreY = 500;
                    var scoreColor = '#66ee66';

                    var scoreDisplay = new Label("+ " + earnedLifePoints);
                    scoreDisplay.font = 'bold 150px sans'
                    scoreDisplay.color = scoreColor;
                    scoreDisplay.x = scoreX;
                    scoreDisplay.y = scoreY;

                    var scoreSuffix = new Label("コビ");
                    scoreSuffix.font = 'bold 50px sans';
                    scoreSuffix.color = scoreColor;
                    scoreSuffix.x = scoreX + 250;
                    scoreSuffix.y = scoreY + 90;

                    var group = new Group();
                    group.addChild(scoreBackground);
                    group.addChild(scoreDisplay);
                    group.addChild(scoreSuffix);

                    scene.addChild(group);

                    roulette.tl.delay(100);
                    roulette.tl.then(function () {
                        app.loadLevel('playStage', { stage: stage });
                    });
                });
            });

            this.enterFrame = function () {
                ticks ++;
                if (ticks % 100 == 0) {
                    console.log(ticks);
                }
            }

            var ticks = 0;
            game.addEventListener('enterframe', this.enterFrame);

            scene.addChild(background);
            scene.addChild(roulette);

            return { scene: scene };
        },
        unload: function (context) {
            context.game.removeEventListener('enterframe', this.enterFrame);
        }
    });

    app.registerLevel(topLevel);
    app.registerLevel(levelTwo);
    app.registerLevel(selectStage);
    app.registerLevel(playStage);
    app.registerLevel(playRoulette);

    app.loadLevel('top', { stage: window.assets.stages[0] });
};
<commit_msg>Add flickering light effects when buttons are pressed. Also fades out the current level on transition.<commit_after>window.onload = function onWindowLoaded () {
    enchant();

    var game = new Game(640, 960);
    game.fps = 60;
    var logger = new jam.Logger({console: console});
    var app = new jam.Application({game: game, logger: logger});
    var topLevel = new jam.Level({
        name: 'top',
        preload: function (context) {
            context.app.log(context.game);
            context.app.log("Preloading topLevel...");
            context.game.preload('img/mikoto.png');
            context.game.preload('img/top_background.png');
            context.game.preload('img/top_list_button.png');
            context.game.preload('img/mikoto.png');
        },
        load: function (context, params) {
            var game = context.game;
            var app = context.app;

            app.log("params=", params, "context=", context);

            var scene = (function () {
                var background = new Sprite();
                background.image = game.assets['img/top_background.png'];
                background.width = game.width;
                background.height = game.height;

                var listButton = new Sprite();
                listButton.image = game.assets['img/top_list_button.png'];
                listButton.width = 637
                listButton.height = 346;
                listButton.y = 500;

                listButton.tl
                    .hide()
                    .and()
                    .scaleTo(0, 0)
                    .fadeIn(50, enchant.Easing.BOUNCE_EASEOUT)
                    .and()
                    .scaleTo(1, 50, enchant.Easing.BOUNCE_EASEOUT);

                listButton.addEventListener('touchstart', function () {
                    app.log(window);

                    listButton.tl
                        .fadeOut(5)
                        .fadeIn(5)
                        .fadeOut(5)
                        .fadeIn(5)
                        .fadeOut(5)
                        .fadeIn(5);

                    background.tl
                        .fadeOut(50)
                        .then(function () {
                            app.loadLevel('selectStage', {foo:"bar"});
                        });
                });
                listButton.addEventListener('touchend', function () {
                });

                var scene = new Scene();
                scene.addChild(background);
                scene.addChild(listButton);

                return scene;
            })();

            var frameCount = 0;
            this.onEnterFrame = function () {
                frameCount ++;

                if (frameCount % 100 == 0) {
                    context.app.log(frameCount + " frames has passed until now.");
                }
            };
            game.addEventListener('enterframe', this.onEnterFrame);

            return { scene: scene };
        },
        unload: function (context) {
            var game = context.game;
            game.removeEventListener('enterframe', this.onEnterFrame);
            this.onEnterFrame = null;
        }
    });

    var levelTwo = new jam.Level({
        name: "two",
        load: function (context, params) {
            var scene = new Scene();

            var label = new Label("Level 2: params=" + params);
            label.x = 32;
            label.y = 32;

            var ball = new Sprite(50, 50);
            var surface = new Surface(50, 50);
            surface.context.beginPath();
            surface.context.arc(25, 25, 25, 0, Math.PI*2, true);
            surface.context.fill();
            ball.image = surface;

            scene.addChild(label);
            scene.addChild(ball);
            return { scene: scene };
        },
        unload: function (context, params) {
        }
    });

    var template = new jam.Level({
        name: "template",
        preload: function (context) {
            // context.game.preload('img/mikoto.png');
        },
        load: function (context, params) {
            // var scene = new Scene();
            // return { scene: scene };
        },
        unload: function (context) {

        }
    });

    // ステージ選択
    var selectStage = new jam.Level({
        name: "selectStage",
        preload: function (context) {
            // context.game.preload('img/mikoto.png');
            context.game.preload('img/stage_0.jpg');
        },
        load: function (context, params) {
            var app = context.app;
            var game = context.game;

            var scene = new Scene();

            var overlay = new Sprite();
            overlay.backgroundColor = '#eeeeee';
            overlay.width = game.width;
            overlay.height = game.height;
            overlay.opacity = 0;
            overlay.touchEnabled = false;

            scene.backgroundColor = "#eeeeee";

            var w = game.width / 2;
            var h = game.height / Math.ceil(window.assets.stages.length / 2);

            var colors = ["#56ADFB", "#19436F", "#15141D"];

            window.assets.stages.forEach(function (stage, i) {
                var components = stage.name.replace("）", "").split("（");
                var charaName = components[0];
                var categoryName = components[1];

                var group = new Group();
                group.width = w;
                group.height = h;
                group.x = w * (i % 2);
                group.y = h * Math.floor(i / 2);

                var charaLabel = new Label(charaName);
                charaLabel.font = "bold 70px serif";
                charaLabel.color = "#ffffff";
                charaLabel.opacity = 0.6;
                charaLabel.touchEnabled = true;

                var categoryLabel = new Label(categoryName);
                categoryLabel.font = "30px sans-serif";
                categoryLabel.color = "#ffffff";
                categoryLabel.opacity = 0.3;
                categoryLabel.y = 80;
                categoryLabel.touchEnabled = true;

                var touchAreaBackgroundColor = colors[(i % colors.length)];

                var background = new Sprite();
                background.width = w;
                background.height = h;
                background.opacity = 0.8;
                background.touchEnabled = true;
                background.backgroundColor = touchAreaBackgroundColor;
                background.image = game.assets['img/stage_0.jpg']

                var touchArea = new Sprite();
                touchArea.width = w;
                touchArea.height = h;
                touchArea.opacity = 0.8;
                touchArea.touchEnabled = true;
                touchArea.backgroundColor = touchAreaBackgroundColor;

                group.addChild(background);
                group.addChild(touchArea);
                group.addChild(charaLabel);
                group.addChild(categoryLabel);

                group.addEventListener('touchstart', function (e) {
                    function flashOn () {
                        touchArea.backgroundColor = scene.backgroundColor;
                    }
                    function flashOff () {
                        touchArea.backgroundColor = touchAreaBackgroundColor;
                    }
                    group.tl
                        .delay(5).then(flashOn).delay(5).then(flashOff)
                        .delay(5).then(flashOn).delay(5).then(flashOff)
                        .delay(5).then(flashOn).delay(5).then(flashOff)
                        .then(function () {
                            overlay.tl
                                .tween({ opacity: 1, time: 30 }, enchant.Easing.EXPO_EASEOUT)
                                .then(function () {
                                    touchArea.backgroundColor = colors[(i % colors.length)];
                                    var stage = window.assets.stages[i];
                                    app.loadLevel('playStage', { stage: stage })

                                });
                        });
                });

                group.addEventListener('touchend', function (e) {
                });

                scene.addChild(group);
                scene.addChild(overlay);
            });

            return { scene: scene };
        },
        unload: function (context) {

        }
    });

    // クイズ画面
    var playStage = new jam.Level({
        name: "playStage",
        preload: function (context) {
            context.app.log(context.game);
            context.app.log('Preloading level...');
        },
        load: function (context, params) {
            var game = context.game;
            var app = context.app;

            app.log("params=", params, "context=", context);

            var scene = (function () {
                // ダミークイズデータ
                var dummies = [
                    {
                        "text": "先輩に呼ばれたときの返事で適切なのは？",
                        "choices": ['はい', 'え？', 'うん', 'なに？'],
                        "correct_choice": 'はい',
                        "correct_choice_index": 0
                    },
                    {
                        "text": "任された仕事が終わった時、正しいのは？",
                        "choices": [
                            '終わっても報告しない',
                            'さっさと次の仕事に取り組む',
                            'すぐに報告する',
                            '同僚に自慢する'
                        ],
                        "correct_choice": 'すぐに報告する',
                        "correct_choice_index": 2
                    },
                ];
                var num = 10;
                var scene = new Scene();
                var pos_list = [
                    [ 15, 720 ],
                    [ 325, 720 ],
                    [ 15, 840 ],
                    [ 325, 840 ]
                ];
                var current = {
                    quiz: null,
                    index: null,
                };

                // Entity
                var l_quiz;
                var spr_character;
                var btn_choice = {
                    list: [],
                    size: [280, 110],
                    font: '32px/48px serif',
                };
                var stage_quizzes = params.stage.quizzes;
                var quizzes;

                // クイズデータを無作為に作成
                var choiceQuizzes = function (quizzes, num) {
                    if (quizzes.length < num) {
                        return quizzes;
                    }
                    var c_quizzes = [];
                    var history = [];
                    var cnt = quizzes.length;
                    var rnd;

                    for (i = 0; i < num; ) {
                        rnd = Math.random() * cnt | 0;

                        if (history.indexOf(rnd) > -1) {
                            continue;
                        }

                        c_quizzes.push(quizzes[rnd]);
                        history.push(rnd);
                        i++;
                    }

                    return c_quizzes;
                };

                // クイズの読み込み
                var loadQuiz = function(quiz) {
                    l_quiz.text = quiz.text;
                    quiz.choices.forEach(function(choice, i) {
                        btn_choice.list[i].text = choice;
                    });
                };
                // 画面の初期化
                var initLevel = function() {
                    // 背景色指定
                    scene.backgroundColor = '#CCCCCC';

                    // Entity生成
                    l_quiz = new Label();
                    l_quiz.backgroundColor = '#FFFFFF';
                    l_quiz.width = 420;
                    l_quiz.height = 155;
                    l_quiz.font = '32px serif';
                    l_quiz.moveTo(18, 505);

                    spr_character = new Entity();
                    spr_character.width = 420;
                    spr_character.height = 420;
                    spr_character.backgroundColor = 'blue';
                    spr_character.moveTo(18, 70);

                    btn_kobi = new Button('こび', 'light');
                    btn_kobi.width = 150;
                    btn_kobi.height = 150;
                    btn_kobi.moveTo(455, 505);

                    for ( i = 0; i < 4; i++ ) {
                        var btn = new Button('select'+i, 'light');

                        btn.index = i;
                        btn.font = btn_choice.font;
                        btn.width = btn_choice.size[0];
                        btn.height = btn_choice.size[1];
                        btn.ontouchend = function(evt) {
                            judgeChoice(evt.target.index);
                        }

                        btn.moveTo(pos_list[i][0], pos_list[i][1]);
                        btn_choice.list.push(btn);
                    }

                    // 画面への追加
                    scene.addChild(l_quiz);
                    scene.addChild(spr_character);
                    scene.addChild(btn_kobi);
                    btn_choice.list.forEach(function (btn) {
                        scene.addChild(btn);
                    });

                    quizzes = choiceQuizzes(stage_quizzes, num);
                    loadQuiz(quizzes[pointer]);
                };

                // 選択を判定
                var judgeChoice = function(index) {
                    app.log('choiced: ' + index);
                    app.log(' text: ' + quizzes[pointer].text);
                    app.log(' answer: ' + quizzes[pointer].correct_choice);
                    showJudgeResult(quizzes[pointer].correct_choice_index == index);
                };

                // 結果を表示
                var showJudgeResult = function(is_correct) {
                    var judge = is_correct ? '正解' : '不正解';
                    app.log(judge);

                    fetchNext();
                };

                // 次を取得
                var fetchNext = function() {
                    pointer++;
                    app.log(pointer);
                    app.log(quizzes.length);

                    // 次はあるか
                    if (pointer < quizzes.length) {
                        loadQuiz(quizzes[pointer]);
                        return ;
                    }

                    app.loadLevel('selectStage', {});
                };

                // ポインタの初期化
                var pointer = 0;
                // ふぁいあー
                initLevel();
                return scene;
            })();

            return { scene: scene };
        },
        unload: function (context) {
        }
    });

    var playRoulette = new jam.Level({
        name: "playRoulette",
        preload: function (context) {
            context.game.preload('img/roulette.png');
            context.game.preload('img/stage_roulette.png');
        },
        load: function (context, params) {
            var game = context.game;
            var app = context.app;
            var stage = params.stage;

            var scene = new Scene();

            var rotationForce = 5 + Math.random() * 2;
            var unitTime = 10;
            var rotationTime = unitTime * rotationForce;

            var background = new Sprite();
            background.image = game.assets['img/stage_roulette.png'];
            background.width = game.width;
            background.height = game.height;

            var roulette = new Sprite();
            roulette.image = game.assets['img/roulette.png']
            roulette.width = 300;
            roulette.height = 300;
            roulette.scaleX = 1.5;
            roulette.scaleY = 1.5;
            roulette.x = 170;
            roulette.y = 300;

            roulette.addEventListener('touchend', function () {
                roulette.tl.rotateBy(360 * rotationForce, rotationTime);
                roulette.tl.then(function () {
                    var earnedLifePoints = Math.floor(Math.random() * 1.9999 + 1);

                    var scoreBackground = new Sprite();
                    scoreBackground.backgroundColor = "#666666";
                    scoreBackground.opacity = 0.8;
                    scoreBackground.width = game.width;
                    scoreBackground.height = game.height;

                    var scoreX = 100;
                    var scoreY = 500;
                    var scoreColor = '#66ee66';

                    var scoreDisplay = new Label("+ " + earnedLifePoints);
                    scoreDisplay.font = 'bold 150px sans'
                    scoreDisplay.color = scoreColor;
                    scoreDisplay.x = scoreX;
                    scoreDisplay.y = scoreY;

                    var scoreSuffix = new Label("コビ");
                    scoreSuffix.font = 'bold 50px sans';
                    scoreSuffix.color = scoreColor;
                    scoreSuffix.x = scoreX + 250;
                    scoreSuffix.y = scoreY + 90;

                    var group = new Group();
                    group.addChild(scoreBackground);
                    group.addChild(scoreDisplay);
                    group.addChild(scoreSuffix);

                    scene.addChild(group);

                    roulette.tl.delay(100);
                    roulette.tl.then(function () {
                        app.loadLevel('playStage', { stage: stage });
                    });
                });
            });

            this.enterFrame = function () {
                ticks ++;
                if (ticks % 100 == 0) {
                    console.log(ticks);
                }
            }

            var ticks = 0;
            game.addEventListener('enterframe', this.enterFrame);

            scene.addChild(background);
            scene.addChild(roulette);

            return { scene: scene };
        },
        unload: function (context) {
            context.game.removeEventListener('enterframe', this.enterFrame);
        }
    });

    app.registerLevel(topLevel);
    app.registerLevel(levelTwo);
    app.registerLevel(selectStage);
    app.registerLevel(playStage);
    app.registerLevel(playRoulette);

    app.loadLevel('top', { stage: window.assets.stages[0] });
};
<|endoftext|>