<commit_before>var GLSL = {};

/** @param {Polynomial} p
 *  @return {Array<string>} */
GLSL.glslCoefficients = function(p) {
    var cs = [],
        cs_, i;
    if (p.isConstant())
        return [GLSL.glslComplex(p.constant())];
    else if (p.isUnivariate()) {
        cs_ = p.coefficientList_();
        for (i = 0; i < cs_.length; i++)
            cs[i] = GLSL.glslComplex(cs_[i]);
    } else if (p.isBivariate()) {
        var vars = p.variableList();
        var vx = vars[0],
            vy = vars[1];
        cs_ = p.coefficientList(vy);
        for (i = 0; i < cs_.length; i++)
            cs[i] = GLSL.glslHorner(vx, GLSL.glslCoefficients(cs_[i]));
    }
    return cs;
};

/** @param {Complex} z
 *  @return {string} */
GLSL.glslComplex = function(z) {
    return "vec2 (" + z.re + "," + z.im + ")";
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslF = function(p, vx, vy) {
    function pad(cs) {
        var n = GLSL.N - cs.length + 1;
        var zero = GLSL.glslComplex(Complex.zero());
        for (var i = 0; i < n; i++)
            cs.push(zero);
        return cs;
    }
    var cs = pad(GLSL.glslCoefficients(p).reverse());
    var lines = ["void f (in vec2 " + vx + ", out vec2 cs[N+1])", "{"];
    for (var i = 0; i < GLSL.N; i++)
        lines.push("cs[" + i + "] = " + cs[i] + ";");
    lines.push("}");
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslFx = function(p, vx, vy) {
    var cs = p.diff(vx).coefficientList(vy);
    var cs_ = [];
    for (var i = 0; i < cs.length; i++)
        cs_[i] = GLSL.glslHorner(vx, GLSL.glslCoefficients(cs[i]));
    var lines = ["vec2 fx (in vec2 " + vx + ", in vec2 " + vy + ")", "{",
        "    return " + GLSL.glslHorner(vy, cs_) + ";", "}"
    ];
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslFy = function(p, vx, vy) {
    var cs = p.diff(vy).coefficientList(vx);
    var cs_ = [];
    for (var i = 0; i < cs.length; i++)
        cs_[i] = GLSL.glslHorner(vy, GLSL.glslCoefficients(cs[i]));
    var lines = ["vec2 fy (in vec2 " + vx + ", in vec2 " + vy + ")", "{",
        "    return " + GLSL.glslHorner(vx, cs_) + ";", "}"
    ];
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vy
 *  @return {string} */
GLSL.glslHeader = function(p, vx, vy) {
    var lines = ["precision highp float;", "const int N = " + GLSL.N + ";",
        "const int sheets = " + p.degree(vy) + ";", "",
        "/* complex multiplication */", "vec2 cm (in vec2 a, in vec2 b)", "{",
        "    return vec2 (a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);", "}"
    ];
    return lines.join("\n");
};

/** @param {string} v
 *  @param {Array<string>} cs
 *  @return {string} */
GLSL.glslHorner = function(v, cs) {
    var str = cs[0];
    if (str === "vec2(1.0,0.0)")
        str = v;
    else if (str === "vec2(-1.0,0.0)")
        str = "-" + v;
    for (var i = 1; i < cs.length; i++) {
        str = "cm(" + v + "," + str + ")";
        if (cs[i] !== "vec2(0.0,0.0)")
            str += "+" + cs[i];
    }
    return str;
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslM = function(p, vx, vy) {
    var i, j;
    var cs = p.coefficientList(vy);
    for (i = 0; i < cs.length; i++) {
        var terms = cs[i].terms;
        for (j = 0; j < terms.length; j++) {
            var term = terms[j];
            terms[j] = new Term(Complex.real(term.coefficient.abs()),
                term.monomial);
        }
        cs[i] = new Polynomial(terms);
    }
    var a0a0 = cs[0].leading(vx);
    var an = p.leading(vx);
    var leadRoots = Polynomial.roots(an.coefficientList_());
    var lines = ["float M (in vec2 " + vx + ", in float rho)", "{",
        "    vec2 r = vec2 (length (" + vx + ") + rho, 0.0);",
        "    float a[" + cs.length + "];",
        "    a[0] = length (" + GLSL.glslComplex(a0a0.constant()) + ");"
    ];
    for (i = 0; i < leadRoots.length; i++)
        lines.push("    a[0] *= distance (" + vx + ", " +
            GLSL.glslComplex(leadRoots[i]) + ") - rho;");
    for (i = 1; i < cs.length; i++)
    // FIXME: 'r' must not conflict with variables of polynomial p
        lines.push("    a[" + i + "] = length (" + GLSL.glslHorner('r',
        GLSL.glslCoefficients(cs[i])) + ");");
    lines = lines.concat(["    float m = a[1] / a[0];",
        "    for (int j = 2; j < " + cs.length + "; j++) {",
        "        m = max (m, pow (a[j] / a[0], 1.0 / float (j)));", "    }",
        "    return 2.0 * m;", "}"
    ]);
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslRho = function(p, vx, vy) {
    var an = p.leading(vy),
        disc = p.discriminant(vy),
        leadRoots = Polynomial.roots(an.coefficientList_()),
        discRoots = Polynomial.roots(disc.coefficientList_()),
        i, critical = [];
    for (i = 0; i < leadRoots.length; i++)
        if (isFinite(leadRoots[i].abs()))
            critical.push(leadRoots[i]);
    for (i = 0; i < discRoots.length; i++)
        if (isFinite(discRoots[i].abs()))
            critical.push(discRoots[i]);
    var lines = ["float rho (in vec2 " + vx + ") {",
        "    float d = 100.0;"
    ];
    for (i = 0; i < critical.length; i++)
        lines.push("    d = min (d, distance (" + vx + ", " +
            GLSL.glslComplex(critical[i]) + "));");
    lines = lines.concat(["    return 0.999 * d;", "}"]);
    return lines.join("\n");
};

GLSL.N = 8;

/** @param {Polynomial} p
 *  @return {string} */
GLSL.polynomialShaderSource = function(p) {
    var vars = p.variableList();
    var vx = vars.length < 2 ? "x" : vars[0];
    var vy = vars.length === 0 ? "y" : vars[vars.length - 1];
    var sources = [
        GLSL.glslHeader(p, vx, vy),
        GLSL.glslF(p, vx, vy),
        GLSL.glslFx(p, vx, vy),
        GLSL.glslFy(p, vx, vy),
        GLSL.glslRho(p, vx, vy),
        GLSL.glslM(p, vx, vy)
    ];
    return sources.join("\n\n");
};
<commit_msg>Minor changes<commit_after>var GLSL = {};

/** @param {Polynomial} p
 *  @return {Array<string>} */
GLSL.glslCoefficients = function(p) {
    var cs = [],
        cs_, i;
    if (p.isConstant())
        return [GLSL.glslComplex(p.constant())];
    else if (p.isUnivariate()) {
        cs_ = p.coefficientList_();
        for (i = 0; i < cs_.length; i++)
            cs[i] = GLSL.glslComplex(cs_[i]);
    } else if (p.isBivariate()) {
        var vars = p.variableList();
        var vx = vars[0],
            vy = vars[1];
        cs_ = p.coefficientList(vy);
        for (i = 0; i < cs_.length; i++)
            cs[i] = GLSL.glslHorner(vx, GLSL.glslCoefficients(cs_[i]));
    }
    return cs;
};

/** @param {Complex} z
 *  @return {string} */
GLSL.glslComplex = function(z) {
    return "vec2 (" + z.re + "," + z.im + ")";
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslF = function(p, vx, vy) {
    function pad(cs) {
        var n = GLSL.N - cs.length + 1;
        var zero = GLSL.glslComplex(Complex.zero());
        for (var i = 0; i < n; i++)
            cs.push(zero);
        return cs;
    }
    var cs = pad(GLSL.glslCoefficients(p).reverse());
    var lines = ["void f (in vec2 " + vx + ", out vec2 cs[N+1])", "{"];
    for (var i = 0; i < GLSL.N; i++)
        lines.push("cs[" + i + "] = " + cs[i] + ";");
    lines.push("}");
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslFx = function(p, vx, vy) {
    var cs = p.diff(vx).coefficientList(vy);
    var cs_ = [];
    for (var i = 0; i < cs.length; i++)
        cs_[i] = GLSL.glslHorner(vx, GLSL.glslCoefficients(cs[i]));
    var lines = ["vec2 fx (in vec2 " + vx + ", in vec2 " + vy + ")", "{",
        "    return " + GLSL.glslHorner(vy, cs_) + ";", "}"
    ];
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslFy = function(p, vx, vy) {
    var cs = p.diff(vy).coefficientList(vx);
    var cs_ = [];
    for (var i = 0; i < cs.length; i++)
        cs_[i] = GLSL.glslHorner(vy, GLSL.glslCoefficients(cs[i]));
    var lines = ["vec2 fy (in vec2 " + vx + ", in vec2 " + vy + ")", "{",
        "    return " + GLSL.glslHorner(vx, cs_) + ";", "}"
    ];
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vy
 *  @return {string} */
GLSL.glslHeader = function(p, vx, vy) {
    var lines = ["#ifdef GL_FRAGMENT_PRECISION_HIGH", "precision highp float;",
        "#else", "precision mediump float;", "#endif",
        "const int N = " + GLSL.N + ";",
        "const int sheets = " + p.degree(vy) + ";", "",
        "/* complex multiplication */", "vec2 cm (in vec2 a, in vec2 b)", "{",
        "    return vec2 (a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);", "}"
    ];
    return lines.join("\n");
};

/** @param {string} v
 *  @param {Array<string>} cs
 *  @return {string} */
GLSL.glslHorner = function(v, cs) {
    var str = cs[0];
    if (str === "vec2(1.0,0.0)")
        str = v;
    else if (str === "vec2(-1.0,0.0)")
        str = "-" + v;
    for (var i = 1; i < cs.length; i++) {
        str = "cm(" + v + "," + str + ")";
        if (cs[i] !== "vec2(0.0,0.0)")
            str += "+" + cs[i];
    }
    return str;
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslM = function(p, vx, vy) {
    var i, j;
    var cs = p.coefficientList(vy);
    for (i = 0; i < cs.length; i++) {
        var terms = cs[i].terms;
        for (j = 0; j < terms.length; j++) {
            var term = terms[j];
            terms[j] = new Term(Complex.real(term.coefficient.abs()),
                term.monomial);
        }
        cs[i] = new Polynomial(terms);
    }
    var a0a0 = cs[0].leading(vx);
    var an = p.leading(vx);
    var leadRoots = Polynomial.roots(an.coefficientList_());
    var lines = ["float M (in vec2 " + vx + ", in float rho)", "{",
        "    vec2 r = vec2 (length (" + vx + ") + rho, 0.0);",
        "    float a[" + cs.length + "];",
        "    a[0] = length (" + GLSL.glslComplex(a0a0.constant()) + ");"
    ];
    for (i = 0; i < leadRoots.length; i++)
        lines.push("    a[0] *= distance (" + vx + ", " +
            GLSL.glslComplex(leadRoots[i]) + ") - rho;");
    for (i = 1; i < cs.length; i++)
    // FIXME: 'r' must not conflict with variables of polynomial p
        lines.push("    a[" + i + "] = length (" + GLSL.glslHorner('r',
        GLSL.glslCoefficients(cs[i])) + ");");
    lines = lines.concat(["    float m = a[1] / a[0];",
        "    for (int j = 2; j < " + cs.length + "; j++) {",
        "        m = max (m, pow (a[j] / a[0], 1.0 / float (j)));", "    }",
        "    return 2.0 * m;", "}"
    ]);
    return lines.join("\n");
};

/** @param {Polynomial} p
 *  @param {string} vx
 *  @param {string} vy
 *  @return {string} */
GLSL.glslRho = function(p, vx, vy) {
    var an = p.leading(vy),
        disc = p.discriminant(vy),
        leadRoots = Polynomial.roots(an.coefficientList_()),
        discRoots = Polynomial.roots(disc.coefficientList_()),
        i, critical = [];
    for (i = 0; i < leadRoots.length; i++)
        if (isFinite(leadRoots[i].abs()))
            critical.push(leadRoots[i]);
    for (i = 0; i < discRoots.length; i++)
        if (isFinite(discRoots[i].abs()))
            critical.push(discRoots[i]);
    var lines = ["float rho (in vec2 " + vx + ") {",
        "    float d = 100.0;"
    ];
    for (i = 0; i < critical.length; i++)
        lines.push("    d = min (d, distance (" + vx + ", " +
            GLSL.glslComplex(critical[i]) + "));");
    lines = lines.concat(["    return 0.999 * d;", "}"]);
    return lines.join("\n");
};

GLSL.N = 8;

/** @param {Polynomial} p
 *  @return {string} */
GLSL.polynomialShaderSource = function(p) {
    var vars = p.variableList();
    var vx = vars.length < 2 ? "x" : vars[0];
    var vy = vars.length === 0 ? "y" : vars[vars.length - 1];
    var sources = [
        GLSL.glslHeader(p, vx, vy),
        GLSL.glslF(p, vx, vy),
        GLSL.glslFx(p, vx, vy),
        GLSL.glslFy(p, vx, vy),
        GLSL.glslRho(p, vx, vy),
        GLSL.glslM(p, vx, vy)
    ];
    return sources.join("\n\n");
};
<|endoftext|>


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

import {Constants} from './constants.js';
import {PostMessageService} from './post_message_service.js';

/**
 * Supported interactions between iframe and merchant page.
 *
 * @enum {number}
 */
// Next Id: 10
const PostMessageEventType = {
  IS_READY_TO_PAY: 6,
  LOG_BUTTON_CLICK: 5,
  LOG_IS_READY_TO_PAY_API: 0,
  LOG_LOAD_PAYMENT_DATA_API: 1,
  LOG_RENDER_BUTTON: 2,
  LOG_INITIALIZE_PAYMENTS_CLIENT: 9,
  LOG_PAY_FRAME_REQUESTED: 15,
  LOG_PAY_FRAME_LOADED: 16,
  LOG_PAY_FRAME_LOADED_WITH_ALL_JS: 17,
  LOG_INLINE_PAYMENT_WIDGET_INITIALIZE: 4,
  LOG_INLINE_PAYMENT_WIDGET_SUBMIT: 3,
  LOG_INLINE_PAYMENT_WIDGET_DISPLAYED: 7,
  LOG_INLINE_PAYMENT_WIDGET_HIDDEN: 8,
};

/**
 * Types of buy flow activity modes.
 *
 * @enum {number}
 */
const BuyFlowActivityMode = {
  UNKNOWN_MODE: 0,
  IFRAME: 1,
  POPUP: 2,
  REDIRECT: 3,
  ANDROID_NATIVE: 4,
  PAYMENT_HANDLER: 5,
};

/**
 * Types of buy flow activity modes.
 *
 * @enum {number}
 */
const PublicErrorCode = {
  UNKNOWN_ERROR_TYPE: 0,
  INTERNAL_ERROR: 1,
  DEVELOPER_ERROR: 2,
  BUYER_ACCOUNT_ERROR: 3,
  MERCHANT_ACCOUNT_ERROR: 4,
  UNSUPPORTED_API_VERSION: 5,
  BUYER_CANCEL: 6,
};

/**
 * Iframe used for logging and prefetching.
 *
 * @type {?Element}
 */
let iframe = null;

/** @type {?PostMessageService} */
let postMessageService = null;

/** @type {?string} */
let environment = null;

/** @type {?string} */
let googleTransactionId = null;

/** @type {number} */
let originTimeMs = Date.now();

/** @type {?BuyFlowActivityMode} */
let buyFlowActivityMode = null;

/** @type {boolean} */
let iframeLoaded = false;

/** @type {!Array<!Object>} */
let buffer = [];

class PayFrameHelper {
  /**
   * Creates a hidden iframe for logging and appends it to the top level
   * document.
   */
  static load() {
    if (iframe) {
      return;
    }
    const initOptions =
        /** @type {!PaymentOptions} */ (window['gpayInitParams']) || {};
    environment = initOptions.environment || Constants.Environment.PRODUCTION;
    iframe = document.createElement('iframe');
    // Pass in origin because document.referrer inside iframe is empty in
    // certain cases
    // Can be replaced by iframe.src=... in non Google context.
    iframe.src = PayFrameHelper.getIframeUrl_(
            window.location.origin,
            initOptions.merchantInfo && initOptions.merchantInfo.merchantId);
    iframe.height = '0';
    iframe.width = '0';
    iframe.style.display = 'none';
    iframe.style.visibility = 'hidden';
    iframe.onload = function() {
      PayFrameHelper.iframeLoaded();
    };
    // If the body is already loaded, just append the iframe. Otherwise, we wait
    // until the DOM has loaded to append the iframe, otherwise document.body is
    // null.
    if (document.body) {
      PayFrameHelper.initialize_();
    } else {
      document.addEventListener(
          'DOMContentLoaded', () => PayFrameHelper.initialize_());
    }
  }

  /**
   * Appends the iframe to the DOM and updates the post message service.
   * @private
   */
  static initialize_() {
    document.body.appendChild(iframe);
    postMessageService = new PostMessageService(iframe.contentWindow);
  }

  /**
   * Sends a message to the iframe and wait for a response.
   * Uses the responseHandler specified only if the responseType is a match.
   *
   * @param {!Object} data
   * @param {!PostMessageEventType} eventType
   * @param {string} responseType
   * @param {function(!Event)} responseHandler
   */
  static sendAndWaitForResponse(
      data, eventType, responseType, responseHandler) {
    function callback(event) {
      if (event.data[responseType]) {
        responseHandler(event);
        // We only want to process the response from the payframe once.
        // so stop listening to the event once processed.
        PayFrameHelper.removeMessageEventListener_(callback);
      }
    }

    PayFrameHelper.addMessageEventListener_(callback);

    const postMessageData = Object.assign({'eventType': eventType}, data);
    PayFrameHelper.postMessage(postMessageData);
  }

  /**
   * Add an event listener for listening to messages received.
   *
   * @param {function(!Event)} callback
   * @private
   */
  static addMessageEventListener_(callback) {
    window.addEventListener('message', callback);
  }

  /**
   * Remove the event listener for listening to messages.
   *
   * @param {function(!Event)} callback
   * @private
   */
  static removeMessageEventListener_(callback) {
    window.removeEventListener('message', callback);
  }

  /**
   * Posts a message to the iframe with the given data.
   *
   * @param {!Object} data
   */
  static postMessage(data) {
    if (!iframeLoaded) {
      buffer.push(data);
      return;
    }
    const postMessageData = Object.assign(
        {
          'buyFlowActivityMode': buyFlowActivityMode,
          'googleTransactionId': googleTransactionId,
          'originTimeMs': originTimeMs,
        },
        data);
    postMessageService.postMessage(
        postMessageData, PayFrameHelper.getIframeOrigin_());
  }

  /**
   * Sets the activity mode.
   *
   * @param {!BuyFlowActivityMode} mode
   */
  static setBuyFlowActivityMode(mode) {
    buyFlowActivityMode = mode;
  }

  /**
   * Sets the google transaction id.
   *
   * @param {string} txnId
   */
  static setGoogleTransactionId(txnId) {
    googleTransactionId = txnId;
  }

  /**
   * Sets the originTimeMs. To be used only for tests.
   *
   * @param {number} originTimeMsTemp
   */
  static setOriginTimeMs(originTimeMsTemp) {
    originTimeMs = originTimeMsTemp;
  }

  /**
   * Override postMessageService for testing.
   *
   * @param {!PostMessageService} messageService
   */
  static setPostMessageService(messageService) {
    postMessageService = messageService;
  }

  /**
   * Clears the singleton variables.
   */
  static reset() {
    iframe = null;
    buffer.length = 0;
    iframeLoaded = false;
    buyFlowActivityMode = null;
  }

  /**
   * Sets whether the iframe has been loaded or not.
   *
   * @param {boolean} loaded
   */
  static setIframeLoaded(loaded) {
    iframeLoaded = loaded;
  }

  /**
   * Called whenever the iframe is loaded.
   */
  static iframeLoaded() {
    iframeLoaded = true;
    buffer.forEach(function(data) {
      PayFrameHelper.postMessage(data);
    });
    buffer.length = 0;
  }

  /**
   * Returns the events that have been buffered.
   *
   * @return {!Array<!Object>}
   */
  static getBuffer() {
    return buffer;
  }

  /**
   * Mocks the iframe as an arbitrary html element instead of actually injecting
   * it for testing.
   */
  static injectIframeForTesting() {
    PayFrameHelper.reset();
    iframe = document.createElement('p');
    PayFrameHelper.iframeLoaded();
  }

  /**
   * Returns the payframe origin based on the environment.
   *
   * @return {string}
   * @private
   */
  static getIframeOrigin_() {
    let iframeUrl = 'https://pay';
    if (environment == Constants.Environment.SANDBOX) {
      iframeUrl += '.sandbox';
    } else if (environment == Constants.Environment.PREPROD) {
      iframeUrl += '-preprod.sandbox';
    }
    return iframeUrl + '.google.com';
  }

  /**
   * Returns the payframe URL based on the environment.
   *
   * @param {string} origin The origin that is opening the payframe.
   * @param {string|null=} merchantId The merchant id.
   * @return {string}
   * @private
   */
  static getIframeUrl_(origin, merchantId) {
    // TrustedResourceUrl header needs to start with https or '//'.
    const iframeUrl = `https://pay${environment == Constants.Environment.PREPROD ?
             '-preprod.sandbox' :
             environment == Constants.Environment.SANDBOX ? '.sandbox' : ''}.google.com/gp/p/ui/payframe?origin=${origin}&mid=%{merchantId}`;
    return iframeUrl;
  }
}

// Start loading pay frame early
PayFrameHelper.load();

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

import {Constants} from './constants.js';
import {PostMessageService} from './post_message_service.js';

/**
 * Supported interactions between iframe and merchant page.
 *
 * @enum {number}
 */
// Next Id: 10
const PostMessageEventType = {
  IS_READY_TO_PAY: 6,
  LOG_BUTTON_CLICK: 5,
  LOG_IS_READY_TO_PAY_API: 0,
  LOG_LOAD_PAYMENT_DATA_API: 1,
  LOG_RENDER_BUTTON: 2,
  LOG_INITIALIZE_PAYMENTS_CLIENT: 9,
  LOG_PAY_FRAME_REQUESTED: 15,
  LOG_PAY_FRAME_LOADED: 16,
  LOG_PAY_FRAME_LOADED_WITH_ALL_JS: 17,
  LOG_INLINE_PAYMENT_WIDGET_INITIALIZE: 4,
  LOG_INLINE_PAYMENT_WIDGET_SUBMIT: 3,
  LOG_INLINE_PAYMENT_WIDGET_DISPLAYED: 7,
  LOG_INLINE_PAYMENT_WIDGET_HIDDEN: 8,
};

/**
 * Types of buy flow activity modes.
 *
 * @enum {number}
 */
const BuyFlowActivityMode = {
  UNKNOWN_MODE: 0,
  IFRAME: 1,
  POPUP: 2,
  REDIRECT: 3,
  ANDROID_NATIVE: 4,
  PAYMENT_HANDLER: 5,
};

/**
 * Types of buy flow activity modes.
 *
 * @enum {number}
 */
const PublicErrorCode = {
  UNKNOWN_ERROR_TYPE: 0,
  INTERNAL_ERROR: 1,
  DEVELOPER_ERROR: 2,
  BUYER_ACCOUNT_ERROR: 3,
  MERCHANT_ACCOUNT_ERROR: 4,
  UNSUPPORTED_API_VERSION: 5,
  BUYER_CANCEL: 6,
};

/**
 * Iframe used for logging and prefetching.
 *
 * @type {?Element}
 */
let iframe = null;

/** @type {?PostMessageService} */
let postMessageService = null;

/** @type {?string} */
let environment = null;

/** @type {?string} */
let googleTransactionId = null;

/** @type {number} */
let originTimeMs = Date.now();

/** @type {?BuyFlowActivityMode} */
let buyFlowActivityMode = null;

/** @type {boolean} */
let iframeLoaded = false;

/** @type {!Array<!Object>} */
let buffer = [];

class PayFrameHelper {
  /**
   * Creates a hidden iframe for logging and appends it to the top level
   * document.
   */
  static load() {
    if (iframe) {
      return;
    }
    const initOptions =
        /** @type {!PaymentOptions} */ (window['gpayInitParams']) || {};
    environment = initOptions.environment || Constants.Environment.PRODUCTION;
    iframe = document.createElement('iframe');
    // Pass in origin because document.referrer inside iframe is empty in
    // certain cases
    // Can be replaced by iframe.src=... in non Google context.
    iframe.src = PayFrameHelper.getIframeUrl_(
            window.location.origin,
            initOptions.merchantInfo && initOptions.merchantInfo.merchantId);
    PayFrameHelper.postMessage({
      'eventType': PostMessageEventType.LOG_PAY_FRAME_REQUESTED,
      'clientLatencyStartMs': Date.now(),
    });
    iframe.height = '0';
    iframe.width = '0';
    iframe.style.display = 'none';
    iframe.style.visibility = 'hidden';
    iframe.onload = function() {
      PayFrameHelper.postMessage({
        'eventType': PostMessageEventType.LOG_PAY_FRAME_LOADED_WITH_ALL_JS,
        'clientLatencyStartMs': Date.now(),
      });
      PayFrameHelper.iframeLoaded();
    };
    // If the body is already loaded, just append the iframe. Otherwise, we wait
    // until the DOM has loaded to append the iframe, otherwise document.body is
    // null.
    if (document.body) {
      PayFrameHelper.initialize_();
    } else {
      document.addEventListener(
          'DOMContentLoaded', () => PayFrameHelper.initialize_());
    }
  }

  /**
   * Appends the iframe to the DOM and updates the post message service.
   * @private
   */
  static initialize_() {
    document.body.appendChild(iframe);
    postMessageService = new PostMessageService(iframe.contentWindow);
  }

  /**
   * Sends a message to the iframe and wait for a response.
   * Uses the responseHandler specified only if the responseType is a match.
   *
   * @param {!Object} data
   * @param {!PostMessageEventType} eventType
   * @param {string} responseType
   * @param {function(!Event)} responseHandler
   */
  static sendAndWaitForResponse(
      data, eventType, responseType, responseHandler) {
    function callback(event) {
      if (event.data[responseType]) {
        responseHandler(event);
        // We only want to process the response from the payframe once.
        // so stop listening to the event once processed.
        PayFrameHelper.removeMessageEventListener_(callback);
      }
    }

    PayFrameHelper.addMessageEventListener_(callback);

    const postMessageData = Object.assign({'eventType': eventType}, data);
    PayFrameHelper.postMessage(postMessageData);
  }

  /**
   * Add an event listener for listening to messages received.
   *
   * @param {function(!Event)} callback
   * @private
   */
  static addMessageEventListener_(callback) {
    window.addEventListener('message', callback);
  }

  /**
   * Remove the event listener for listening to messages.
   *
   * @param {function(!Event)} callback
   * @private
   */
  static removeMessageEventListener_(callback) {
    window.removeEventListener('message', callback);
  }

  /**
   * Posts a message to the iframe with the given data.
   *
   * @param {!Object} data
   */
  static postMessage(data) {
    if (!iframeLoaded) {
      buffer.push(data);
      return;
    }
    const postMessageData = Object.assign(
        {
          'buyFlowActivityMode': buyFlowActivityMode,
          'googleTransactionId': googleTransactionId,
          'originTimeMs': originTimeMs,
        },
        data);
    postMessageService.postMessage(
        postMessageData, PayFrameHelper.getIframeOrigin_());
  }

  /**
   * Sets the activity mode.
   *
   * @param {!BuyFlowActivityMode} mode
   */
  static setBuyFlowActivityMode(mode) {
    buyFlowActivityMode = mode;
  }

  /**
   * Sets the google transaction id.
   *
   * @param {string} txnId
   */
  static setGoogleTransactionId(txnId) {
    googleTransactionId = txnId;
  }

  /**
   * Sets the originTimeMs. To be used only for tests.
   *
   * @param {number} originTimeMsTemp
   */
  static setOriginTimeMs(originTimeMsTemp) {
    originTimeMs = originTimeMsTemp;
  }

  /**
   * Override postMessageService for testing.
   *
   * @param {!PostMessageService} messageService
   */
  static setPostMessageService(messageService) {
    postMessageService = messageService;
  }

  /**
   * Clears the singleton variables.
   */
  static reset() {
    iframe = null;
    buffer.length = 0;
    iframeLoaded = false;
    buyFlowActivityMode = null;
  }

  /**
   * Sets whether the iframe has been loaded or not.
   *
   * @param {boolean} loaded
   */
  static setIframeLoaded(loaded) {
    iframeLoaded = loaded;
  }

  /**
   * Called whenever the iframe is loaded.
   */
  static iframeLoaded() {
    iframeLoaded = true;
    buffer.forEach(function(data) {
      PayFrameHelper.postMessage(data);
    });
    buffer.length = 0;
  }

  /**
   * Returns the events that have been buffered.
   *
   * @return {!Array<!Object>}
   */
  static getBuffer() {
    return buffer;
  }

  /**
   * Mocks the iframe as an arbitrary html element instead of actually injecting
   * it for testing.
   */
  static injectIframeForTesting() {
    PayFrameHelper.reset();
    iframe = document.createElement('p');
    PayFrameHelper.iframeLoaded();
  }

  /**
   * Returns the payframe origin based on the environment.
   *
   * @return {string}
   * @private
   */
  static getIframeOrigin_() {
    let iframeUrl = 'https://pay';
    if (environment == Constants.Environment.SANDBOX) {
      iframeUrl += '.sandbox';
    } else if (environment == Constants.Environment.PREPROD) {
      iframeUrl += '-preprod.sandbox';
    }
    return iframeUrl + '.google.com';
  }

  /**
   * Returns the payframe URL based on the environment.
   *
   * @param {string} origin The origin that is opening the payframe.
   * @param {string|null=} merchantId The merchant id.
   * @return {string}
   * @private
   */
  static getIframeUrl_(origin, merchantId) {
    // TrustedResourceUrl header needs to start with https or '//'.
    const iframeUrl = `https://pay${environment == Constants.Environment.PREPROD ?
             '-preprod.sandbox' :
             environment == Constants.Environment.SANDBOX ? '.sandbox' : ''}.google.com/gp/p/ui/payframe?origin=${origin}&mid=%{merchantId}`;
    return iframeUrl;
  }
}

// Start loading pay frame early
PayFrameHelper.load();

export {
  BuyFlowActivityMode,
  PayFrameHelper,
  PostMessageEventType,
  PublicErrorCode,
};
<|endoftext|>


<commit_before>function Game(canvas, ctx) {
	var that = this;

	this.tetris = new Tetris(ctx);
	this.animation = new Animation($("#animation")[0], 4, 200, 100, that.tetris.MARGIN_LEFT, 300);
	this.startScreen = new Animation($("#startScreen")[0], 60, 200, 400, that.tetris.MARGIN_LEFT, that.tetris.MARGIN_TOP);
	this.startScreen.loop = true;
	this.gameOver = new Animation($("#gameOver")[0], 60, 200, 400, that.tetris.MARGIN_LEFT, that.tetris.MARGIN_TOP);
	this.gameOver.loop = true;

	this.smgr = new SceneManager(ctx);
	this.smgr.register(this.animation);
	this.smgr.register(this.startScreen);
	this.smgr.register(this.gameOver);

	this.width = canvas.width;
	this.height = canvas.height;
	this.FPS = 60;

	this.state = {
		options: {
			showStats: false
		},

		canHold: true,
		level: 1,
		score: 0,
		lastDrop: 0,
		timeElapsed: 0,
		linesCleared: 0,
		gameState: "startScreen"
	}

	this.player = {
		tetromino: tets[Math.floor(Math.random()*tets.length)],
		rotation: 0,
		r: 0, // starting positions
		c: 3, // middle of the screen
		heldPiece: 0, // nothing
		nextPiece: tets[Math.floor(Math.random()*tets.length)]
	}

	// dt = delta time (change in time)
	// is in milliseconds
	this.update = function (dt) {
		if (that.state.gameState === "play") {
			that.framerate = Math.floor(1000.0 / dt);
			that.state.timeElapsed += dt; // timeElapsed will not increase even if we are paused!
			// difficulty formula: 1+ log(level)
			if (that.state.timeElapsed >= 1000/(1 + Math.log(that.state.level))) {
				if (!that.canMoveR(1)) {
					that.merge();
					that.playerSpawn();
				} else {
					that.player.r += 1;
				}
				that.state.lastDrop = 0;
				that.state.timeElapsed = 0;

			}
			// check if game is over
			if (!that.tetris.rowEmpty(0))
				that.state.gameState = "gameOver";
		} else if (that.state.gameState === "startScreen") {
			if (!that.startScreen.active) that.startScreen.play();
		} else if (that.state.gameState === "gameOver") {
			if (!that.gameOver.active) that.gameOver.play();
		}

		that.smgr.update(dt);
	}

	var frame = $("#frame")[0];
	this.draw = function () {
		ctx.clearRect(0, 0, that.width, that.height);

		ctx.drawImage(frame, 0, 0, frame.width, frame.height);
		that.tetris.draw();

		if (that.state.gameState === "startScreen") {
			// do nothing -- SceneManager will draw the animation
			// (SceneManager) draws the other animations on the screen.
			// Might think about making the Tetris board an entity managed
			// by the SceneManager.
		} else if (that.state.gameState === "play") {
			// why paused ? because we will show the game in the background on the pause screen.
			// that.tetris.drawAnnotations(); -- uncomment if you want to see rows & cols

			var drop = 0;
			while (that.canMoveR(++drop)) {
				// do nothing
			}

			that.tetris.drawGhost(that.player.r+drop-1,
				that.player.c,
				that.player.tetromino,
				that.player.rotation);

			that.tetris.drawTetromino(that.player.r,
				that.player.c,
				that.player.tetromino,
				that.player.rotation);
		}

		that.smgr.draw();

		// draw lines cleared
		ctx.textAlign = "center";
		ctx.fillStyle = "#FFFFFF";
		ctx.font = "18px sans-serif";
		ctx.fillText(that.state.linesCleared, 108, 480);

		// draw score
		ctx.fillText(that.state.score, 435, 350);

		// hold
		that.tetris.drawPreview(75, 169, that.player.heldPiece);

		// next
		that.tetris.drawPreview(387, 169, that.player.nextPiece);
	}

	this.onKeyDown = function (event) {
		if (that.state.gameState === "play") {
			switch (event.keyCode) {
				case 37: // LEFT
					event.preventDefault();
					if (that.canMoveC(-1)) that.player.c -= 1;
					break;
				case 39: // RIGHT
					event.preventDefault();
					if (that.canMoveC(1)) that.player.c += 1;
					break;
				case 38: // UP
					event.preventDefault();
					// Cycle through the matrices
					if (that.canRotate()) that.player.rotation = (that.player.rotation + 1) % 4;
					break;
				case 40: // DOWN
					event.preventDefault();
					if (that.canMoveR(1)) that.player.r += 1;
					break;
				case 32: // SPACE
					event.preventDefault();
					while (that.canMoveR(1)) {
						that.player.r += 1;
					}

					that.merge();
					that.playerSpawn();
					that.state.lastDrop = 0;
					that.state.timeElapsed = 0;

					break;
				case 16: // SHIFT
					event.preventDefault();
					if (that.state.canHold) {
						var piece = that.player.heldPiece;
						that.player.heldPiece = that.player.tetromino;
						if (piece == 0)
							that.playerSpawn();
						else {
							that.player.tetromino = piece;
							that.player.rotation = 0;
							that.player.r = 0;
							that.player.c = 3;
						}
						that.state.canHold = false;
					}
					break;
				case 80: // P
					event.preventDefault();
					that.state.gameState = "startScreen";
					that.startScreen.play();
					break;
			}
		} else if (that.state.gameState === "startScreen") {
			switch (event.keyCode) {
				case 32: // SPACE
					event.preventDefault();
					that.state.gameState = "play";
					that.startScreen.stop();
					break;
			}
		} else if (that.state.gameState === "gameOver") {
			switch (event.keyCode) {
				case 80: // SPACE
					event.preventDefault();

					that.tetris = new Tetris(ctx);

					that.player.tetromino = tets[Math.floor(Math.random()*tets.length)];
					that.player.rotation = 0;
					that.player.r = 0;
					that.player.c = 3;
					that.player.nextPiece =  tets[Math.floor(Math.random()*tets.length)];
					that.player.holdPiece = 0;

					that.state = {
						options: {
							showStats: false
						},

						canHold: true,
						level: 1,
						score: 0,
						lastDrop: 0,
						timeElapsed: 0,
						linesCleared: 0,
						gameState: "play"
					}

					that.gameOver.stop();

					break;

			}
		}
	}

	// Can we move (dr) many rows ?
	this.canMoveR = function(dr) {
		return (that.tetris.tInBounds(that.player.r+dr, that.player.c, that.player.tetromino, that.player.rotation)
			&& !that.tetris.tIntersect(that.player.r+dr, that.player.c, that.player.tetromino, that.player.rotation))
	}

	// Can we move (dc) many columns ?
	this.canMoveC = function(dc) {
		return (that.tetris.tInBounds(that.player.r, that.player.c+dc, that.player.tetromino, that.player.rotation)
			&& !that.tetris.tIntersect(that.player.r, that.player.c+dc, that.player.tetromino, that.player.rotation))
	}

	this.canRotate = function() {
		return (that.tetris.tInBounds(that.player.r, that.player.c, that.player.tetromino, (that.player.rotation + 1) % 4)
			&& !that.tetris.tIntersect(that.player.r, that.player.c, that.player.tetromino, (that.player.rotation + 1) % 4))
	}

	this.merge = function() {
		that.tetris.tMerge(that.player.r, that.player.c, that.player.tetromino, that.player.rotation);

		var lines = that.tetris.clearLines();
		that.state.linesCleared += lines;
		that.state.score += 10 * lines*lines;

		if (lines == 4) { // TETRIS !!
			that.animation.play();
			that.state.score += 40;
		}

		if (that.state.linesCleared > that.state.level*5) that.state.level++;
		that.state.canHold = true;
	}

	this.playerSpawn = function() {
		that.player.tetromino = that.player.nextPiece;
		that.player.rotation = 0;
		that.player.r = 0;
		that.player.c = 3;
		that.player.nextPiece =  tets[Math.floor(Math.random()*tets.length)];
	}

	var lastTime = 0;

	this.start = function () {
		// attach events to the Game
		window.addEventListener('keydown', that.onKeyDown);
		lastTime = Date.now();

		var stats = new Stats();
		stats.setMode(0); // 0: fps, 1: ms

		// Align top-left
		stats.domElement.style.position = 'absolute';
		stats.domElement.style.left = '0px';
		stats.domElement.style.top = '0px';

		document.body.appendChild( stats.domElement );

		setInterval( function () {

			stats.begin();
			that.run();
			stats.end();

		}, 1000 / that.FPS );

	}

	this.run = function () {
		that.update(Date.now() - lastTime);
		that.draw();
		lastTime = Date.now();
	}

	this.drawPreview = function(x, y, tetromino) {
		ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
		for (var r = 0; r < 4; r++) // For each row
			for (var c = 0; c < 4; c++) { // For each column
				// Stroke (outline) a rectangle of size 20x20
				ctx.strokeRect(x + c*that.SIZE,
					y + r*that.SIZE,
					that.SIZE,
					that.SIZE);

				if ((r+c) % 2 == 0) { // checkered pattern
					ctx.fillStyle = "rgba(0, 0, 0, 0.15)";
					ctx.fillRect(x + c*that.SIZE,
						y + r*that.SIZE,
						that.SIZE,
						that.SIZE);
				}
			}

		if (tetromino != 0) {
			for (var r = 0; r < 4; r++) // For each row
				for (var c = 0; c < 4; c++) { // For each column
					if (tetromino.preview[r][c] != 0)
						ctx.drawImage(
						img[tetromino.preview[r][c]],
						x + c*that.SIZE + 1,
						y + r*that.SIZE + 1,
						that.SIZE - 2,
						that.SIZE - 2
						);
			}
		}
	}
}

$(window).load(function() {
	var c = $("#gameCanvas")[0];
	window.ctx = c.getContext("2d");

	window.game = new Game(c, ctx);
	window.game.start();
});<commit_msg>fixed hold<commit_after>function Game(canvas, ctx) {
	var that = this;

	this.tetris = new Tetris(ctx);
	this.animation = new Animation($("#animation")[0], 4, 200, 100, that.tetris.MARGIN_LEFT, 300);
	this.startScreen = new Animation($("#startScreen")[0], 60, 200, 400, that.tetris.MARGIN_LEFT, that.tetris.MARGIN_TOP);
	this.startScreen.loop = true;
	this.gameOver = new Animation($("#gameOver")[0], 60, 200, 400, that.tetris.MARGIN_LEFT, that.tetris.MARGIN_TOP);
	this.gameOver.loop = true;

	this.smgr = new SceneManager(ctx);
	this.smgr.register(this.animation);
	this.smgr.register(this.startScreen);
	this.smgr.register(this.gameOver);

	this.width = canvas.width;
	this.height = canvas.height;
	this.FPS = 60;

	this.state = {
		options: {
			showStats: false
		},

		canHold: true,
		level: 1,
		score: 0,
		lastDrop: 0,
		timeElapsed: 0,
		linesCleared: 0,
		gameState: "startScreen"
	}

	this.player = {
		tetromino: tets[Math.floor(Math.random()*tets.length)],
		rotation: 0,
		r: 0, // starting positions
		c: 3, // middle of the screen
		heldPiece: 0, // nothing
		nextPiece: tets[Math.floor(Math.random()*tets.length)]
	}

	// dt = delta time (change in time)
	// is in milliseconds
	this.update = function (dt) {
		if (that.state.gameState === "play") {
			that.framerate = Math.floor(1000.0 / dt);
			that.state.timeElapsed += dt; // timeElapsed will not increase even if we are paused!
			// difficulty formula: 1+ log(level)
			if (that.state.timeElapsed >= 1000/(1 + Math.log(that.state.level))) {
				if (!that.canMoveR(1)) {
					that.merge();
					that.playerSpawn();
				} else {
					that.player.r += 1;
				}
				that.state.lastDrop = 0;
				that.state.timeElapsed = 0;

			}
			// check if game is over
			if (!that.tetris.rowEmpty(0))
				that.state.gameState = "gameOver";
		} else if (that.state.gameState === "startScreen") {
			if (!that.startScreen.active) that.startScreen.play();
		} else if (that.state.gameState === "gameOver") {
			if (!that.gameOver.active) that.gameOver.play();
		}

		that.smgr.update(dt);
	}

	var frame = $("#frame")[0];
	this.draw = function () {
		ctx.clearRect(0, 0, that.width, that.height);

		ctx.drawImage(frame, 0, 0, frame.width, frame.height);
		that.tetris.draw();

		if (that.state.gameState === "startScreen") {
			// do nothing -- SceneManager will draw the animation
			// (SceneManager) draws the other animations on the screen.
			// Might think about making the Tetris board an entity managed
			// by the SceneManager.
		} else if (that.state.gameState === "play") {
			// why paused ? because we will show the game in the background on the pause screen.
			// that.tetris.drawAnnotations(); -- uncomment if you want to see rows & cols

			var drop = 0;
			while (that.canMoveR(++drop)) {
				// do nothing
			}

			that.tetris.drawGhost(that.player.r+drop-1,
				that.player.c,
				that.player.tetromino,
				that.player.rotation);

			that.tetris.drawTetromino(that.player.r,
				that.player.c,
				that.player.tetromino,
				that.player.rotation);
		}

		that.smgr.draw();

		// draw lines cleared
		ctx.textAlign = "center";
		ctx.fillStyle = "#FFFFFF";
		ctx.font = "18px sans-serif";
		ctx.fillText(that.state.linesCleared, 108, 480);

		// draw score
		ctx.fillText(that.state.score, 435, 350);

		// hold
		that.tetris.drawPreview(75, 169, that.player.heldPiece);

		// next
		that.tetris.drawPreview(387, 169, that.player.nextPiece);
	}

	this.onKeyDown = function (event) {
		if (that.state.gameState === "play") {
			switch (event.keyCode) {
				case 37: // LEFT
					event.preventDefault();
					if (that.canMoveC(-1)) that.player.c -= 1;
					break;
				case 39: // RIGHT
					event.preventDefault();
					if (that.canMoveC(1)) that.player.c += 1;
					break;
				case 38: // UP
					event.preventDefault();
					// Cycle through the matrices
					if (that.canRotate()) that.player.rotation = (that.player.rotation + 1) % 4;
					break;
				case 40: // DOWN
					event.preventDefault();
					if (that.canMoveR(1)) that.player.r += 1;
					break;
				case 32: // SPACE
					event.preventDefault();
					while (that.canMoveR(1)) {
						that.player.r += 1;
					}

					that.merge();
					that.playerSpawn();
					that.state.lastDrop = 0;
					that.state.timeElapsed = 0;

					break;
				case 16: // SHIFT
					event.preventDefault();
					if (that.state.canHold) {
						var piece = that.player.heldPiece;
						that.player.heldPiece = that.player.tetromino;
						if (piece == 0)
							that.playerSpawn();
						else {
							that.player.tetromino = piece;
							that.player.rotation = 0;
							that.player.r = 0;
							that.player.c = 3;
						}
						that.state.canHold = false;
					}
					break;
				case 80: // P
					event.preventDefault();
					that.state.gameState = "startScreen";
					that.startScreen.play();
					break;
			}
		} else if (that.state.gameState === "startScreen") {
			switch (event.keyCode) {
				case 32: // SPACE
					event.preventDefault();
					that.state.gameState = "play";
					that.startScreen.stop();
					break;
			}
		} else if (that.state.gameState === "gameOver") {
			switch (event.keyCode) {
				case 80: // P
					event.preventDefault();

					that.tetris = new Tetris(ctx);

					that.player.tetromino = tets[Math.floor(Math.random()*tets.length)];
					that.player.rotation = 0;
					that.player.r = 0;
					that.player.c = 3;
					that.player.nextPiece =  tets[Math.floor(Math.random()*tets.length)];
					that.player.heldPiece = 0;

					that.state = {
						options: {
							showStats: false
						},

						canHold: true,
						level: 1,
						score: 0,
						lastDrop: 0,
						timeElapsed: 0,
						linesCleared: 0,
						gameState: "play"
					}

					that.gameOver.stop();

					break;

			}
		}
	}

	// Can we move (dr) many rows ?
	this.canMoveR = function(dr) {
		return (that.tetris.tInBounds(that.player.r+dr, that.player.c, that.player.tetromino, that.player.rotation)
			&& !that.tetris.tIntersect(that.player.r+dr, that.player.c, that.player.tetromino, that.player.rotation))
	}

	// Can we move (dc) many columns ?
	this.canMoveC = function(dc) {
		return (that.tetris.tInBounds(that.player.r, that.player.c+dc, that.player.tetromino, that.player.rotation)
			&& !that.tetris.tIntersect(that.player.r, that.player.c+dc, that.player.tetromino, that.player.rotation))
	}

	this.canRotate = function() {
		return (that.tetris.tInBounds(that.player.r, that.player.c, that.player.tetromino, (that.player.rotation + 1) % 4)
			&& !that.tetris.tIntersect(that.player.r, that.player.c, that.player.tetromino, (that.player.rotation + 1) % 4))
	}

	this.merge = function() {
		that.tetris.tMerge(that.player.r, that.player.c, that.player.tetromino, that.player.rotation);

		var lines = that.tetris.clearLines();
		that.state.linesCleared += lines;
		that.state.score += 10 * lines*lines;

		if (lines == 4) { // TETRIS !!
			that.animation.play();
			that.state.score += 40;
		}

		if (that.state.linesCleared > that.state.level*5) that.state.level++;
		that.state.canHold = true;
	}

	this.playerSpawn = function() {
		that.player.tetromino = that.player.nextPiece;
		that.player.rotation = 0;
		that.player.r = 0;
		that.player.c = 3;
		that.player.nextPiece =  tets[Math.floor(Math.random()*tets.length)];
	}

	var lastTime = 0;

	this.start = function () {
		// attach events to the Game
		window.addEventListener('keydown', that.onKeyDown);
		lastTime = Date.now();

		var stats = new Stats();
		stats.setMode(0); // 0: fps, 1: ms

		// Align top-left
		stats.domElement.style.position = 'absolute';
		stats.domElement.style.left = '0px';
		stats.domElement.style.top = '0px';

		document.body.appendChild( stats.domElement );

		setInterval( function () {

			stats.begin();
			that.run();
			stats.end();

		}, 1000 / that.FPS );

	}

	this.run = function () {
		that.update(Date.now() - lastTime);
		that.draw();
		lastTime = Date.now();
	}

	this.drawPreview = function(x, y, tetromino) {
		ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
		for (var r = 0; r < 4; r++) // For each row
			for (var c = 0; c < 4; c++) { // For each column
				// Stroke (outline) a rectangle of size 20x20
				ctx.strokeRect(x + c*that.SIZE,
					y + r*that.SIZE,
					that.SIZE,
					that.SIZE);

				if ((r+c) % 2 == 0) { // checkered pattern
					ctx.fillStyle = "rgba(0, 0, 0, 0.15)";
					ctx.fillRect(x + c*that.SIZE,
						y + r*that.SIZE,
						that.SIZE,
						that.SIZE);
				}
			}

		if (tetromino != 0) {
			for (var r = 0; r < 4; r++) // For each row
				for (var c = 0; c < 4; c++) { // For each column
					if (tetromino.preview[r][c] != 0)
						ctx.drawImage(
						img[tetromino.preview[r][c]],
						x + c*that.SIZE + 1,
						y + r*that.SIZE + 1,
						that.SIZE - 2,
						that.SIZE - 2
						);
			}
		}
	}
}

$(window).load(function() {
	var c = $("#gameCanvas")[0];
	window.ctx = c.getContext("2d");

	window.game = new Game(c, ctx);
	window.game.start();
});<|endoftext|>


<commit_before>var JS_GAME = {};

JS_GAME.game = (function () {
  var isKeyDown = [];
  var context;
  var userData = [];
  var enemies = [];
  var frameLength = 1;// in milliseconds
  var socket;
  var connected = false;
  var user = "";
  var pass = "";

  function init() {
    user = document.getElementById("loginInfo").user.value;
    pass = document.getElementById("loginInfo").pass.value;
    if (user.indexOf(",") >= 0 || user.indexOf(":") >= 0){
      document.getElementById("loginInfo").user.value = "INVALID INPUT";
      return;
    }
    socket = new WebSocket("ws:167.88.120.57:38734");

    socket.onopen = function() {
      connected = true;
      socket.send("login:" + user + "," + pass);
    };

socket.onmessage = function(message) {
  if (message.data.indexOf("pos") == 0){
    var regex = /pos:(\d+),(\d+)/;
    var pos = regex.exec(message.data);
    for (i = 0; i < pos.length - 1; i++){
      userData[i] = pos[i+1];
    }
} else if (message.data.indexOf("dat") == 0){
  var splitted = message.data.split(":")[1].split(",");
  enemies = [];
  for (i = 0; i < splitted.length; i++){
    enemies[i] = splitted[i];
  }
}
};

socket.onclose = function() {
  window.location.reload(false);
};

socket.onerror = function() {
};

document.body.innerHTML = "";
for (i = 0; i < 256; i++){
  isKeyDown[i] = false;
}
$('body').append('<canvas id="GameCanvas">');
$("#GameCanvas").focus();
var $canvas = $('#GameCanvas');
$canvas.attr('width', $(window).innerWidth());
$canvas.attr('height', $(window).innerHeight());
var canvas = $canvas[0];
window.addEventListener( "keydown", keyPress, false);
window.addEventListener( "keyup", keyRelease, false);
context = canvas.getContext('2d');
gameLoop();
}

function gameLoop() {
  var keyData = "";
  for (i = 0; i < 256; i++){
    keyData += isKeyDown[i] ? 1 : 0;
  }
  try {
    socket.send("keys:" + keyData);
  } catch (err) {
  }
  context.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
  context.fillStyle = userData[2];
  context.fillRect(userData[0], userData[1], 30, 50);
  context.font = "15px Arial";
  context.fillText(user,(userData[2] - (context.measureText(user).width / 2)) + 15,userData[1] - 5);
  for (i = 0; i < enemies.length; i += 4){
  context.fillStyle = enemies[i+2];
  context.fillRect(enemies[i], enemies[i+1], 30, 50);
  context.fillText(enemies[i+2],(enemies[i] - (context.measureText(enemies[i+3]).width / 2)) + 15,enemies[i+1] - 5);
  }
  setTimeout(gameLoop, frameLength);
}

function keyPress(e){
  isKeyDown[e.keyCode] = true;
}
function keyRelease(e){
  isKeyDown[e.keyCode] = false;
}
function isKeyPressed(c){
  return isKeyDown[c.charCodeAt(0)];
}

return {
  init: init
};
})();

$(document).ready(function() {
  $("#loginInfo").submit(function(event){
    event.preventDefault();
    JS_GAME.game.init();
    $(window).blur();
    this.remove();
    return false;
  });
});
<commit_msg>colorfix<commit_after>var JS_GAME = {};

JS_GAME.game = (function () {
  var isKeyDown = [];
  var context;
  var userData = [];
  var enemies = [];
  var frameLength = 1;// in milliseconds
  var socket;
  var connected = false;
  var user = "";
  var pass = "";

  function init() {
    user = document.getElementById("loginInfo").user.value;
    pass = document.getElementById("loginInfo").pass.value;
    if (user.indexOf(",") >= 0 || user.indexOf(":") >= 0){
      document.getElementById("loginInfo").user.value = "INVALID INPUT";
      return;
    }
    socket = new WebSocket("ws:167.88.120.57:38734");

    socket.onopen = function() {
      connected = true;
      socket.send("login:" + user + "," + pass);
    };

socket.onmessage = function(message) {
  if (message.data.indexOf("pos") == 0){
  userData = message.data.split(":")[1].split(",");
    }
} else if (message.data.indexOf("dat") == 0){
  enemies = message.data.split(":")[1].split(",");
}
};

socket.onclose = function() {
  window.location.reload(false);
};

socket.onerror = function() {
};

document.body.innerHTML = "";
for (i = 0; i < 256; i++){
  isKeyDown[i] = false;
}
$('body').append('<canvas id="GameCanvas">');
$("#GameCanvas").focus();
var $canvas = $('#GameCanvas');
$canvas.attr('width', $(window).innerWidth());
$canvas.attr('height', $(window).innerHeight());
var canvas = $canvas[0];
window.addEventListener( "keydown", keyPress, false);
window.addEventListener( "keyup", keyRelease, false);
context = canvas.getContext('2d');
gameLoop();
}

function gameLoop() {
  var keyData = "";
  for (i = 0; i < 256; i++){
    keyData += isKeyDown[i] ? 1 : 0;
  }
  try {
    socket.send("keys:" + keyData);
  } catch (err) {
  }
  context.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
  context.fillStyle = userData[2];
  context.fillRect(userData[0], userData[1], 30, 50);
  context.font = "15px Arial";
  context.fillText(user,(userData[2] - (context.measureText(user).width / 2)) + 15,userData[1] - 5);
  for (i = 0; i < enemies.length; i += 4){
  context.fillStyle = enemies[i+2];
  context.fillRect(enemies[i], enemies[i+1], 30, 50);
  context.fillText(enemies[i+2],(enemies[i] - (context.measureText(enemies[i+3]).width / 2)) + 15,enemies[i+1] - 5);
  }
  setTimeout(gameLoop, frameLength);
}

function keyPress(e){
  isKeyDown[e.keyCode] = true;
}
function keyRelease(e){
  isKeyDown[e.keyCode] = false;
}
function isKeyPressed(c){
  return isKeyDown[c.charCodeAt(0)];
}

return {
  init: init
};
})();

$(document).ready(function() {
  $("#loginInfo").submit(function(event){
    event.preventDefault();
    JS_GAME.game.init();
    $(window).blur();
    this.remove();
    return false;
  });
});
<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});
exports.onPrototype = onPrototype;
exports.getNode = getNode;
exports.children = children;
exports.hasClassName = hasClassName;
exports.treeForEach = treeForEach;
exports.treeFilter = treeFilter;
exports.single = single;
exports.childrenEqual = childrenEqual;
exports.nodeEqual = nodeEqual;

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _underscore = require('underscore');

var _reactAddons = require('react/addons');

var _reactAddons2 = _interopRequireDefault(_reactAddons);

var _React$addons$TestUtils = _reactAddons2['default'].addons.TestUtils;
var Simulate = _React$addons$TestUtils.Simulate;
var mockComponent = _React$addons$TestUtils.mockComponent;
var isElement = _React$addons$TestUtils.isElement;
var isElementOfType = _React$addons$TestUtils.isElementOfType;
var isDOMComponent = _React$addons$TestUtils.isDOMComponent;
var isCompositeComponent = _React$addons$TestUtils.isCompositeComponent;

function onPrototype(Component, lifecycle, method) {
  var proto = Component.prototype;
  Object.getOwnPropertyNames(proto).forEach(function (name) {
    if (typeof proto[name] !== "function") return;
    switch (name) {
      case "componentDidMount":
      case "componentWillMount":
      case "componentDidUnmount":
      case "componentWillUnmount":
      case "componentWillReceiveProps":
      case "componentDidUpdate":
      case "componentWillUpdate":
      case "shouldComponentUpdate":
      case "render":
        if (lifecycle) lifecycle(proto, name);
        break;
      case "constructor":
        // don't spy on the constructor, even though it shows up in the prototype
        break;
      default:
        if (method) method(proto, name);
        break;
    }
  });
}

function getNode(node) {
  return isDOMComponent(node) ? _reactAddons2['default'].findDOMNode(node) : node;
}

function children(node) {
  var maybeArray = node && node._store && node._store.props && node._store.props.children;
  if (!maybeArray) return [];
  if (Array.isArray(maybeArray)) return maybeArray;
  return [maybeArray];
}

function hasClassName(node, className) {
  var classes = node._store.props.className || '';
  return (' ' + classes + ' ').indexOf(' ' + className + ' ') > -1;
}

function treeForEach(tree, fn) {
  fn(tree);
  children(tree).forEach(function (node) {
    return treeForEach(node, fn);
  });
}

function treeFilter(tree, fn) {
  var results = [];
  treeForEach(tree, function (node) {
    if (fn(node)) {
      results.push(node);
    }
  });
  return results;
}

function single(array) {
  if (array.length !== 1) {
    throw new Error('Expected single element but found ' + array.length + ' instead');
  }
  return array[0];
}

function childrenEqual(a, b) {
  if (a === b) return true;
  if (!Array.isArray(a) && !Array.isArray(b)) {
    return nodeEqual(a, b);
  }
  if (!a && !b) return true;
  if (a.length !== b.length) return false;
  if (a.length === 0 && b.length === 0) return true;
  for (var i = 0; i < a.length; i++) {
    if (!nodeEqual(a[i], b[i])) return false;
  }
  return true;
}

function nodeEqual(a, b) {
  if (a.type !== b.type) return false;
  var aLength = 0;
  var bLength = 0;
  var prop;
  a = a._store.props;
  b = b._store.props;
  for (prop in a) {
    if (!a.hasOwnProperty(prop)) continue;
    aLength++;
    if (!(prop in b)) return false;
    if (prop === "children") {
      if (!childrenEqual(a.children, b.children)) return false;
    } else if (b[prop] === a[prop]) {
      // continue;
    } else if (typeof b[prop] === typeof a[prop] && typeof a[prop] === "object") {
        if (!(0, _underscore.isEqual)(a[prop], b[prop])) return false;
      } else {
        return false;
      }
  }
  for (prop in b) {
    if (!b.hasOwnProperty(prop)) continue;
    bLength++;
  }
  return aLength === bLength;
}<commit_msg>build<commit_after>'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});
exports.onPrototype = onPrototype;
exports.getNode = getNode;
exports.children = children;
exports.hasClassName = hasClassName;
exports.treeForEach = treeForEach;
exports.treeFilter = treeFilter;
exports.single = single;
exports.childrenEqual = childrenEqual;
exports.nodeEqual = nodeEqual;

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _underscore = require('underscore');

var _reactAddons = require('react/addons');

var _reactAddons2 = _interopRequireDefault(_reactAddons);

var _React$addons$TestUtils = _reactAddons2['default'].addons.TestUtils;
var Simulate = _React$addons$TestUtils.Simulate;
var mockComponent = _React$addons$TestUtils.mockComponent;
var isElement = _React$addons$TestUtils.isElement;
var isElementOfType = _React$addons$TestUtils.isElementOfType;
var isDOMComponent = _React$addons$TestUtils.isDOMComponent;
var isCompositeComponent = _React$addons$TestUtils.isCompositeComponent;

function onPrototype(Component, lifecycle, method) {
  var proto = Component.prototype;
  Object.getOwnPropertyNames(proto).forEach(function (name) {
    if (typeof proto[name] !== "function") return;
    switch (name) {
      case "componentDidMount":
      case "componentWillMount":
      case "componentDidUnmount":
      case "componentWillUnmount":
      case "componentWillReceiveProps":
      case "componentDidUpdate":
      case "componentWillUpdate":
      case "shouldComponentUpdate":
      case "render":
        if (lifecycle) lifecycle(proto, name);
        break;
      case "constructor":
        // don't spy on the constructor, even though it shows up in the prototype
        break;
      default:
        if (method) method(proto, name);
        break;
    }
  });
}

function getNode(node) {
  return isDOMComponent(node) ? _reactAddons2['default'].findDOMNode(node) : node;
}

function children(node) {
  var maybeArray = node && node._store && node._store.props && node._store.props.children;
  if (!maybeArray) return [];
  if (Array.isArray(maybeArray)) return maybeArray;
  return [maybeArray];
}

function hasClassName(node, className) {
  var classes = node && node._store && node._store.props && node._store.props.className || '';
  return (' ' + classes + ' ').indexOf(' ' + className + ' ') > -1;
}

function treeForEach(tree, fn) {
  fn(tree);
  children(tree).forEach(function (node) {
    return treeForEach(node, fn);
  });
}

function treeFilter(tree, fn) {
  var results = [];
  treeForEach(tree, function (node) {
    if (fn(node)) {
      results.push(node);
    }
  });
  return results;
}

function single(array) {
  if (array.length !== 1) {
    throw new Error('Expected single element but found ' + array.length + ' instead');
  }
  return array[0];
}

function childrenEqual(a, b) {
  if (a === b) return true;
  if (!Array.isArray(a) && !Array.isArray(b)) {
    return nodeEqual(a, b);
  }
  if (!a && !b) return true;
  if (a.length !== b.length) return false;
  if (a.length === 0 && b.length === 0) return true;
  for (var i = 0; i < a.length; i++) {
    if (!nodeEqual(a[i], b[i])) return false;
  }
  return true;
}

function nodeEqual(a, b) {
  if (a.type !== b.type) return false;
  var aLength = 0;
  var bLength = 0;
  var prop;
  a = a._store.props;
  b = b._store.props;
  for (prop in a) {
    if (!a.hasOwnProperty(prop)) continue;
    aLength++;
    if (!(prop in b)) return false;
    if (prop === "children") {
      if (!childrenEqual(a.children, b.children)) return false;
    } else if (b[prop] === a[prop]) {
      // continue;
    } else if (typeof b[prop] === typeof a[prop] && typeof a[prop] === "object") {
        if (!(0, _underscore.isEqual)(a[prop], b[prop])) return false;
      } else {
        return false;
      }
  }
  for (prop in b) {
    if (!b.hasOwnProperty(prop)) continue;
    bLength++;
  }
  return aLength === bLength;
}<|endoftext|>


<commit_before>/**
 * Converts raw AFINN data to JSON hash table.
 *
 * @package sentiment
 * @author Andrew Sliwinski <andrew@diy.org>
 */

/**
 * Dependencies
 */
var async = require('async'),
    fs = require('fs'),
    path = require('path');

function setup(callback) {
    callback(null, {});
}

/**
 * Read emoji data from original format
 */
function processEmoji(hash, callback) {
    fs.readFile(path.join(__dirname, 'Emoji_Sentiment_Data_v1.0.csv'),
        function(err, data) {
            var first = true;
            async.forEach(data.toString().split(/\n/),
                function(line, callback) {
                    if (first) { // Skip the first line with column names
                        first = false;
                        callback();
                    } else {
                        var lineItem = line.split(',');
                        var occurences = lineItem[2];
                        var negativeCount = lineItem[4];
                        var positiveCount = lineItem[6];
                        var sentiment = Math.floor(5 * (
                            (positiveCount / occurences) -
                            (negativeCount / occurences)
                        ));
                        if (!Number.isNaN(sentiment) && 0 !== sentiment) {
                            hash[line[0]] = sentiment;
                        }
                        callback();
                    }
                },
                function(err) {
                    if (err) {
                        callback(err);
                    } else {
                        callback(null, hash);
                    }
                });
        });
}

/**
 * Read AFINN data from original format
 */
function processAFINN(hash, callback) {
    fs.readFile(path.join(__dirname, 'AFINN-en-165.txt'), function(err, data) {
        // Split lines
        async.forEach(data.toString().split(/\n/), function(line, callback) {
            var item = line.split(/\t/);
            hash[item[0]] = Number(item[1]);
            callback();
        }, function(err) {
            if (err) {
                callback(err);
            } else {
                callback(null, hash);
            }
        });
    });
}

/**
 * Write sentiment score hash
 */
function finish(hash, callback) {
    fs.writeFile(
        __dirname + '/AFINN.json',
        JSON.stringify(hash),
        function(err) {
            if (err) callback(err);
            else callback(null, hash);
        });
}

async.waterfall([
    setup,
    processEmoji,
    processAFINN,
    finish
], function(error, result) {
    if (error) {
        process.stderr.write('Error');
    } else {
        process.stderr.write('Complete.\n');
    }
});
<commit_msg>Put result key count in message to stderr after build.<commit_after>/**
 * Converts raw AFINN data to JSON hash table.
 *
 * @package sentiment
 * @author Andrew Sliwinski <andrew@diy.org>
 */

/**
 * Dependencies
 */
var async = require('async'),
    fs = require('fs'),
    path = require('path');

function setup(callback) {
    callback(null, {});
}

/**
 * Read emoji data from original format
 */
function processEmoji(hash, callback) {
    fs.readFile(path.join(__dirname, 'Emoji_Sentiment_Data_v1.0.csv'),
        function(err, data) {
            var first = true;
            async.forEach(data.toString().split(/\n/),
                function(line, callback) {
                    if (first) { // Skip the first line with column names
                        first = false;
                        callback();
                    } else {
                        var lineItem = line.split(',');
                        var occurences = lineItem[2];
                        var negativeCount = lineItem[4];
                        var positiveCount = lineItem[6];
                        var sentiment = Math.floor(5 * (
                            (positiveCount / occurences) -
                            (negativeCount / occurences)
                        ));
                        if (!Number.isNaN(sentiment) && 0 !== sentiment) {
                            hash[line[0]] = sentiment;
                        }
                        callback();
                    }
                },
                function(err) {
                    if (err) {
                        callback(err);
                    } else {
                        callback(null, hash);
                    }
                });
        });
}

/**
 * Read AFINN data from original format
 */
function processAFINN(hash, callback) {
    fs.readFile(path.join(__dirname, 'AFINN-en-165.txt'), function(err, data) {
        // Split lines
        async.forEach(data.toString().split(/\n/), function(line, callback) {
            var item = line.split(/\t/);
            hash[item[0]] = Number(item[1]);
            callback();
        }, function(err) {
            if (err) {
                callback(err);
            } else {
                callback(null, hash);
            }
        });
    });
}

/**
 * Write sentiment score hash
 */
function finish(hash, callback) {
    fs.writeFile(
        __dirname + '/AFINN.json',
        JSON.stringify(hash),
        function(err) {
            if (err) callback(err);
            else callback(null, hash);
        });
}

async.waterfall([
    setup,
    processEmoji,
    processAFINN,
    finish
], function(error, result) {
    if (error) {
        process.stderr.write('Error');
    } else {
        process.stderr.write('Complete: ' +
            Object.keys(result).length +
            ' entries.\n');
    }
});
<|endoftext|>


<commit_before>var fs = require('fs')
var zlib = require('zlib')
var rollup = require('rollup')
var uglify = require('uglify-js')
var babel = require('rollup-plugin-babel')
var replace = require('rollup-plugin-replace')
var alias = require('rollup-plugin-alias')
var version = process.env.VERSION || require('../package.json').version

var banner =
  '/*!\n' +
  ' * Vue.js v' + version + '\n' +
  ' * (c) ' + new Date().getFullYear() + ' Evan You\n' +
  ' * Released under the MIT License.\n' +
  ' */'

// update main file
var main = fs
  .readFileSync('src/runtime/index.js', 'utf-8')
  .replace(/Vue\.version = '[\d\.]+'/, "Vue.version = '" + version + "'")
fs.writeFileSync('src/runtime/index.js', main)

// CommonJS build.
// this is used as the "main" field in package.json
// and used by bundlers like Webpack and Browserify.
// runtime only, because it's meant to be
// used with vue-loader which pre-compiles the template.
rollup.rollup({
  entry: 'src/runtime/index.js',
  plugins: [babel()]
})
.then(function (bundle) {
  var code = bundle.generate({
    format: 'cjs',
    banner: banner
  }).code
  return write('dist/vue.common.js', code)
})
// production CommonJS build, just for file size monitoring.
.then(function () {
  return rollup.rollup({
    entry: 'src/runtime/index.js',
    plugins: [
      replace({
        'process.env.NODE_ENV': "'production'"
      }),
      babel()
    ]
  })
}).then(function (bundle) {
  var code = bundle.generate({
    format: 'cjs'
  }).code
  return write('dist/vue.common.min.js', uglify.minify(code, {
    fromString: true,
    output: {
      ascii_only: true
    }
  }).code)
})
.then(zip('dist/vue.common.min.js'))
// Compiler CommonJS build.
// Used in Node loaders/transforms.
.then(function () {
  return rollup.rollup({
    entry: 'src/compiler/index.js',
    plugins: [babel()]
  })
  .then(function (bundle) {
    write('dist/compiler/compiler.js', bundle.generate({
      format: 'cjs'
    }).code)
  })
})
// Standalone Dev Build
.then(function () {
  return rollup.rollup({
    entry: 'src/runtime-with-compiler.js',
    plugins: [
      alias({
        entities: './entity-decoder'
      }),
      replace({
        'process.env.NODE_ENV': "'development'"
      }),
      babel()
    ]
  })
  .then(function (bundle) {
    return write('dist/vue.js', bundle.generate({
      format: 'umd',
      banner: banner,
      moduleName: 'Vue'
    }).code)
  })
})
.then(function () {
  // Standalone Production Build
  return rollup.rollup({
    entry: 'src/runtime-with-compiler.js',
    plugins: [
      alias({
        entities: './entity-decoder'
      }),
      replace({
        'process.env.NODE_ENV': "'production'"
      }),
      babel()
    ]
  })
  .then(function (bundle) {
    var code = bundle.generate({
      format: 'umd',
      moduleName: 'Vue'
    }).code
    var minified = banner + '\n' + uglify.minify(code, {
      fromString: true,
      output: {
        ascii_only: true
      }
    }).code
    return write('dist/vue.min.js', minified)
  })
  .then(zip('dist/vue.min.js'))
})
.catch(logError)

function write (dest, code) {
  return new Promise(function (resolve, reject) {
    fs.writeFile(dest, code, function (err) {
      if (err) return reject(err)
      console.log(blue(dest) + ' ' + getSize(code))
      resolve()
    })
  })
}

function zip (file) {
  return function () {
    return new Promise(function (resolve, reject) {
      fs.readFile(file, function (err, buf) {
        if (err) return reject(err)
        zlib.gzip(buf, function (err, buf) {
          if (err) return reject(err)
          write(file + '.gz', buf).then(resolve)
        })
      })
    })
  }
}

function getSize (code) {
  return (code.length / 1024).toFixed(2) + 'kb'
}

function logError (e) {
  console.log(e)
}

function blue (str) {
  return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'
}
<commit_msg>copyright year<commit_after>var fs = require('fs')
var zlib = require('zlib')
var rollup = require('rollup')
var uglify = require('uglify-js')
var babel = require('rollup-plugin-babel')
var replace = require('rollup-plugin-replace')
var alias = require('rollup-plugin-alias')
var version = process.env.VERSION || require('../package.json').version

var banner =
  '/*!\n' +
  ' * Vue.js v' + version + '\n' +
  ' * (c) 2014-' + new Date().getFullYear() + ' Evan You\n' +
  ' * Released under the MIT License.\n' +
  ' */'

// update main file
var main = fs
  .readFileSync('src/runtime/index.js', 'utf-8')
  .replace(/Vue\.version = '[\d\.]+'/, "Vue.version = '" + version + "'")
fs.writeFileSync('src/runtime/index.js', main)

// CommonJS build.
// this is used as the "main" field in package.json
// and used by bundlers like Webpack and Browserify.
// runtime only, because it's meant to be
// used with vue-loader which pre-compiles the template.
rollup.rollup({
  entry: 'src/runtime/index.js',
  plugins: [babel()]
})
.then(function (bundle) {
  var code = bundle.generate({
    format: 'cjs',
    banner: banner
  }).code
  return write('dist/vue.common.js', code)
})
// production CommonJS build, just for file size monitoring.
.then(function () {
  return rollup.rollup({
    entry: 'src/runtime/index.js',
    plugins: [
      replace({
        'process.env.NODE_ENV': "'production'"
      }),
      babel()
    ]
  })
}).then(function (bundle) {
  var code = bundle.generate({
    format: 'cjs'
  }).code
  return write('dist/vue.common.min.js', uglify.minify(code, {
    fromString: true,
    output: {
      ascii_only: true
    }
  }).code)
})
.then(zip('dist/vue.common.min.js'))
// Compiler CommonJS build.
// Used in Node loaders/transforms.
.then(function () {
  return rollup.rollup({
    entry: 'src/compiler/index.js',
    plugins: [babel()]
  })
  .then(function (bundle) {
    write('dist/compiler/compiler.js', bundle.generate({
      format: 'cjs'
    }).code)
  })
})
// Standalone Dev Build
.then(function () {
  return rollup.rollup({
    entry: 'src/runtime-with-compiler.js',
    plugins: [
      alias({
        entities: './entity-decoder'
      }),
      replace({
        'process.env.NODE_ENV': "'development'"
      }),
      babel()
    ]
  })
  .then(function (bundle) {
    return write('dist/vue.js', bundle.generate({
      format: 'umd',
      banner: banner,
      moduleName: 'Vue'
    }).code)
  })
})
.then(function () {
  // Standalone Production Build
  return rollup.rollup({
    entry: 'src/runtime-with-compiler.js',
    plugins: [
      alias({
        entities: './entity-decoder'
      }),
      replace({
        'process.env.NODE_ENV': "'production'"
      }),
      babel()
    ]
  })
  .then(function (bundle) {
    var code = bundle.generate({
      format: 'umd',
      moduleName: 'Vue'
    }).code
    var minified = banner + '\n' + uglify.minify(code, {
      fromString: true,
      output: {
        ascii_only: true
      }
    }).code
    return write('dist/vue.min.js', minified)
  })
  .then(zip('dist/vue.min.js'))
})
.catch(logError)

function write (dest, code) {
  return new Promise(function (resolve, reject) {
    fs.writeFile(dest, code, function (err) {
      if (err) return reject(err)
      console.log(blue(dest) + ' ' + getSize(code))
      resolve()
    })
  })
}

function zip (file) {
  return function () {
    return new Promise(function (resolve, reject) {
      fs.readFile(file, function (err, buf) {
        if (err) return reject(err)
        zlib.gzip(buf, function (err, buf) {
          if (err) return reject(err)
          write(file + '.gz', buf).then(resolve)
        })
      })
    })
  }
}

function getSize (code) {
  return (code.length / 1024).toFixed(2) + 'kb'
}

function logError (e) {
  console.log(e)
}

function blue (str) {
  return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'
}
<|endoftext|>


<commit_before>'use strict';

var I = require('immutable');

var pgraph = function pgraph(scalar, zero, one) {

  var Edge = I.Record({
    head : undefined,
    tail : undefined,
    shift: undefined
  });

  Edge.prototype.toString = function toString() {
    return 'Edge('+this.head+', '+this.tail+', '+this.shift+')';
  };

  Edge.prototype.reverse = function reverse() {
    return new Edge({
      head : this.tail,
      tail : this.head,
      shift: this.shift.map(scalar.negative)
    });
  };

  var _isNegative = function _isNegative(vec) {
    var d = vec.map(scalar.sgn).filter(function(x) { return x != 0; }).first();
    return d < 0;
  };

  Edge.prototype.canonical = function canonical() {
    if (this.tail < this.head ||
        (this.tail == this.head &&  _isNegative(this.shift)))
      return this.reverse();
    else
      return this;
  };

  var _makeEdge = function _makeEdge(e) {
    return new Edge({ head: e[0], tail: e[1], shift: I.List(e[2]) })
      .canonical();
  };

  var Graph = I.Record({
    dim  : undefined,
    edges: undefined
  });

  Graph.prototype.toString = function toString() {
    return 'PGraph('+this.edges+')';
  };

  var make = function make(data) {
    var edges = I.Set(data).map(_makeEdge);
    if (edges.size == 0)
      throw new Error('cannot be empty');

    var dim = edges.first().shift.size;
    if (edges.some(function(e) { return e.shift.size != dim; }))
      throw new Error('must have consistent shift dimensions');

    return new Graph({ dim: dim, edges: edges });
  };

  var adjacencies = function adjacencies(graph) {
    var res = I.Map();

    graph.edges.forEach(function(e) {
      res = res
        .update(e.head, function(a) {
          return (a || I.List()).push(I.Map({
            v: e.tail,
            s: e.shift
          }));
        })
        .update(e.tail, function(a) {
          return (a || I.List()).push(I.Map({
            v: e.head,
            s: e.shift.map(scalar.negative)
          }));
        });
    });

    return res;
  };

  var cseq = function cseq(graph, start, dist) {
    var adj  = adjacencies(graph);
    var zero = I.List(I.Repeat(0, graph.dim));
    var add  = function(s, t) {
      return I.Range(0, graph.dim).map(function(i) {
        return scalar.plus(s.get(i), t.get(i));
      });
    };

    var oldShell = I.Set();
    var thisShell = I.Set([I.Map({ v: start, s: zero })]);
    var res = I.List([1]);

    I.Range(1, dist+1).forEach(function(i) {
      var nextShell = I.Set();
      thisShell.forEach(function(v) {
        adj.get(v.get('v')).forEach(function(t) {
          var w = I.Map({ v: t.get('v'), s: add(v.get('s'), t.get('s')) });
          if (!oldShell.contains(w) && !thisShell.contains(w))
            nextShell = nextShell.add(w);
        });
      });

      res = res.push(nextShell.size);
      oldShell = thisShell;
      thisShell = nextShell;
    });

    return res;
  };

  return {
    make       : make,
    adjacencies: adjacencies,
    cseq       : cseq
  };
};

if (require.main == module) {
  var Q = require('../arithmetic/number');
  var P = pgraph(Q, 0, 1);

  var g = P.make([[1,1,[1,0,0]], [1,1,[0,-1,0]], [1,1,[0,0,1]]]);
  console.log(g);
  console.log(P.adjacencies(g));
  console.log(P.cseq(g, 1, 10));
}
<commit_msg>use plain integers for shift vectors<commit_after>'use strict';

var I = require('immutable');

var _neg = function(x) { return -x; };
var _sgn = function(x) { return (x > 0) - (x < 0); };

var Edge = I.Record({
  head : undefined,
  tail : undefined,
  shift: undefined
});

Edge.prototype.toString = function toString() {
  return 'Edge('+this.head+', '+this.tail+', '+this.shift+')';
};

Edge.prototype.reverse = function reverse() {
  return new Edge({
    head : this.tail,
    tail : this.head,
    shift: this.shift.map(_neg)
  });
};

var _isNegative = function _isNegative(vec) {
  var d = vec.map(_sgn).filter(function(x) { return x != 0; }).first();
  return d < 0;
};

Edge.prototype.canonical = function canonical() {
  if (this.tail < this.head ||
      (this.tail == this.head &&  _isNegative(this.shift)))
    return this.reverse();
  else
    return this;
};

var _makeEdge = function _makeEdge(e) {
  return new Edge({ head: e[0], tail: e[1], shift: I.List(e[2]) })
    .canonical();
};

var Graph = I.Record({
  dim  : undefined,
  edges: undefined
});

Graph.prototype.toString = function toString() {
  return 'PGraph('+this.edges+')';
};

var make = function make(data) {
  var edges = I.Set(data).map(_makeEdge);
  if (edges.size == 0)
    throw new Error('cannot be empty');

  var dim = edges.first().shift.size;
  if (edges.some(function(e) { return e.shift.size != dim; }))
    throw new Error('must have consistent shift dimensions');

  return new Graph({ dim: dim, edges: edges });
};

var adjacencies = function adjacencies(graph) {
  var res = I.Map();

  graph.edges.forEach(function(e) {
    res = res
      .update(e.head, function(a) {
        return (a || I.List()).push(I.Map({
          v: e.tail,
          s: e.shift
        }));
      })
      .update(e.tail, function(a) {
        return (a || I.List()).push(I.Map({
          v: e.head,
          s: e.shift.map(_neg)
        }));
      });
  });

  return res;
};

var cseq = function cseq(graph, start, dist) {
  var adj  = adjacencies(graph);
  var zero = I.List(I.Repeat(0, graph.dim));
  var add  = function(s, t) {
    return I.Range(0, graph.dim).map(function(i) {
      return s.get(i) + t.get(i);
    });
  };

  var oldShell = I.Set();
  var thisShell = I.Set([I.Map({ v: start, s: zero })]);
  var res = I.List([1]);

  I.Range(1, dist+1).forEach(function(i) {
    var nextShell = I.Set();
    thisShell.forEach(function(v) {
      adj.get(v.get('v')).forEach(function(t) {
        var w = I.Map({ v: t.get('v'), s: add(v.get('s'), t.get('s')) });
        if (!oldShell.contains(w) && !thisShell.contains(w))
          nextShell = nextShell.add(w);
      });
    });

    res = res.push(nextShell.size);
    oldShell = thisShell;
    thisShell = nextShell;
  });

  return res;
};

module.exports = {
  make       : make,
  adjacencies: adjacencies,
  cseq       : cseq
};

if (require.main == module) {
  var g = make([[1,1,[1,0,0]], [1,1,[0,-1,0]], [1,1,[0,0,1]]]);
  console.log(g);
  console.log(adjacencies(g));
  console.log(cseq(g, 1, 10));
}
<|endoftext|>