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

'use strict';
const moment = require('moment');
const parseColor = require('parse-color');
const prism = require('prismjs');

exports.contrastColor = function(hexcolor) {
  if (!hexcolor) {
    return 'white';
  }

  // Assume that a 6 digit string is a color.
  if (hexcolor.length === 6 && hexcolor[0] !== '#') {
    hexcolor = '#' + hexcolor;
  }

  const parsedColor = parseColor(hexcolor);
  const r = parsedColor.rgb[0];
  const g = parsedColor.rgb[1];
  const b = parsedColor.rgb[2];

  const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
  return (yiq >= 128) ? 'black' : 'white';
};

exports.firstLetter = function(text) {
  return (text ? text[0] : '').toUpperCase();
};

exports.moment = function(date) {
  return moment(date).fromNow();
};

function syntaxHighlight(json) {
    json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
    return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
        var cls = 'number';
        if (/^"/.test(match)) {
            if (/:$/.test(match)) {
                cls = 'key';
            } else {
                cls = 'string';
            }
        } else if (/true|false/.test(match)) {
            cls = 'boolean';
        } else if (/null/.test(match)) {
            cls = 'null';
        }
        return '' + match + '';
    });
}

exports.prettyJson = function(object) {
  return JSON.stringify(object, null, 4);
};

exports.highlightedJson = function(object) {
  return syntaxHighlight(JSON.stringify(object, null, 4));
};

exports.getAggregationTableRow = function(aggregation) {
  var row = '
'
          + '' + aggregation.name + '	'
          + '' + aggregation.overall + '	'
          + '
';
  return row;
};

exports.getAuditTableRow = function(audit) {
  var row = '
'
          + '' + audit.description + '	'
          + '' + audit.score + '	'
          + '
';
  return row;
};

exports.registerHelpers = function(hbs) {
  hbs.registerHelper('firstLetter', exports.firstLetter);
  hbs.registerHelper('contrastColor', exports.contrastColor);
  hbs.registerHelper('moment', exports.moment);
  hbs.registerHelper('prettyJson', exports.prettyJson);
  hbs.registerHelper('highlightedJson', exports.highlightedJson);
  hbs.registerHelper('getAggregationTableRow', exports.getAggregationTableRow);
  hbs.registerHelper('getAuditTableRow', exports.getAuditTableRow);
};
<commit_msg>Remove unused require for prism module<commit_after>/**
 * Copyright 2015-2016, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';
const moment = require('moment');
const parseColor = require('parse-color');

exports.contrastColor = function(hexcolor) {
  if (!hexcolor) {
    return 'white';
  }

  // Assume that a 6 digit string is a color.
  if (hexcolor.length === 6 && hexcolor[0] !== '#') {
    hexcolor = '#' + hexcolor;
  }

  const parsedColor = parseColor(hexcolor);
  const r = parsedColor.rgb[0];
  const g = parsedColor.rgb[1];
  const b = parsedColor.rgb[2];

  const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
  return (yiq >= 128) ? 'black' : 'white';
};

exports.firstLetter = function(text) {
  return (text ? text[0] : '').toUpperCase();
};

exports.moment = function(date) {
  return moment(date).fromNow();
};

function syntaxHighlight(json) {
    json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
    return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
        var cls = 'number';
        if (/^"/.test(match)) {
            if (/:$/.test(match)) {
                cls = 'key';
            } else {
                cls = 'string';
            }
        } else if (/true|false/.test(match)) {
            cls = 'boolean';
        } else if (/null/.test(match)) {
            cls = 'null';
        }
        return '' + match + '';
    });
}

exports.prettyJson = function(object) {
  return JSON.stringify(object, null, 4);
};

exports.highlightedJson = function(object) {
  return syntaxHighlight(JSON.stringify(object, null, 4));
};

exports.getAggregationTableRow = function(aggregation) {
  var row = '
'
          + '' + aggregation.name + '	'
          + '' + aggregation.overall + '	'
          + '
';
  return row;
};

exports.getAuditTableRow = function(audit) {
  var row = '
'
          + '' + audit.description + '	'
          + '' + audit.score + '	'
          + '
';
  return row;
};

exports.registerHelpers = function(hbs) {
  hbs.registerHelper('firstLetter', exports.firstLetter);
  hbs.registerHelper('contrastColor', exports.contrastColor);
  hbs.registerHelper('moment', exports.moment);
  hbs.registerHelper('prettyJson', exports.prettyJson);
  hbs.registerHelper('highlightedJson', exports.highlightedJson);
  hbs.registerHelper('getAggregationTableRow', exports.getAggregationTableRow);
  hbs.registerHelper('getAuditTableRow', exports.getAuditTableRow);
};
<|endoftext|>


<commit_before>/**
 * Copyright 2018 The Subscribe with Google Authors. 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 {ActivityIframeView} from '../ui/activity-iframe-view';
import {PayStartFlow} from './pay-flow';
import {SubscriptionFlows, ProductType} from '../api/subscriptions';
import {feArgs, feUrl} from './services';

/**
 * Offers view is closable when request was originated from 'AbbrvOfferFlow'
 * or from 'SubscribeOptionFlow'.
 */
const OFFERS_VIEW_CLOSABLE = true;

/**
 * The class for Offers flow.
 */
export class OffersFlow {
  /**
   * @param {!./deps.DepsDef} deps
   * @param {!../api/subscriptions.OffersRequest|undefined} options
   */
  constructor(deps, options) {
    /** @private @const {!./deps.DepsDef} */
    this.deps_ = deps;

    /** @private @const {!Window} */
    this.win_ = deps.win();

    /** @private @const {!../components/activities.ActivityPorts} */
    this.activityPorts_ = deps.activities();

    /** @private @const {!../components/dialog-manager.DialogManager} */
    this.dialogManager_ = deps.dialogManager();

    let isClosable = options && options.isClosable;
    if (isClosable == undefined) {
      isClosable = false; // Default is to hide Close button.
    }

    const feArgsObj = {
      'productId': deps.pageConfig().getProductId(),
      'publicationId': deps.pageConfig().getPublicationId(),
      'showNative': deps.callbacks().hasSubscribeRequestCallback(),
      'productType': ProductType.SUBSCRIPTION,
      'list': (options && options.list) || 'default',
      'skus': (options && options.skus) || null,
      'isClosable': isClosable,
    };

    if (options && options.oldSku) {
      feArgsObj['oldSku'] = options.oldSku;
    }

    if (feArgsObj['oldSku']) {
      if (!feArgsObj['skus']) {
        console.error('Need a sku list if old sku is provided!');
        return;
      }
      // remove old sku from offers if in list
      let skuList = feArgsObj['skus'];
      const /** @type {String} */ oldSku = feArgsObj['oldSku'];
      skuList = skuList.filter(sku => sku !== oldSku);
      if (skuList.length > 0) {
        feArgsObj['skus'] = skuList;
      } else {
        console.error('Sku list only contained offer user already has');
        return;
      }
    }

    // redirect to payments if only one upgrade option is passed
    if (feArgsObj['skus'] && feArgsObj['skus'].length === 1) {
      const sku = feArgsObj['skus'][0];
      const /** @type {String} */ oldSku = feArgsObj['oldSku'];
      // object currently requires experimental flag
      // so we need to check for oldSku to decide what to send
      if (oldSku) {
        new PayStartFlow(this.deps_, {
          skuId: sku,
          oldSkuId: oldSku,
        }).start();
        return;
      } else {
        new PayStartFlow(this.deps_, sku).start();
        return;
      }
    }
    /** @private @const {!ActivityIframeView} */
    this.activityIframeView_ = new ActivityIframeView(
      this.win_,
      this.activityPorts_,
      feUrl('/offersiframe'),
      feArgs(feArgsObj),
      /* shouldFadeBody */ true
    );
  }

  /**
   * Starts the offers flow or alreadySubscribed flow.
   * @return {!Promise}
   */
  start() {
    if (this.activityIframeView_) {
      // so no error is thrown if offers skipped
      // Start/cancel events.
      this.deps_.callbacks().triggerFlowStarted(SubscriptionFlows.SHOW_OFFERS);
      this.activityIframeView_.onCancel(() => {
        this.deps_
          .callbacks()
          .triggerFlowCanceled(SubscriptionFlows.SHOW_OFFERS);
      });

      // If result is due to OfferSelection, redirect to payments.
      this.activityIframeView_.onMessageDeprecated(result => {
        if (result['alreadySubscribed']) {
          this.deps_.callbacks().triggerLoginRequest({
            linkRequested: !!result['linkRequested'],
          });
          return;
        }
        if (result['oldSku']) {
          new PayStartFlow(this.deps_, {
            skuId: result['sku'],
            oldSkuId: result['oldSku'],
          }).start();
          return;
        }
        if (result['sku']) {
          new PayStartFlow(
            this.deps_,
            /** @type {string} */ (result['sku'])
          ).start();
          return;
        }
        if (result['native']) {
          this.deps_.callbacks().triggerSubscribeRequest();
          return;
        }
      });

      return this.dialogManager_.openView(this.activityIframeView_);
    }
  }
}

/**
 * The class for subscribe option flow.
 */
export class SubscribeOptionFlow {
  /**
   * @param {!./deps.DepsDef} deps
   * @param {!../api/subscriptions.OffersRequest|undefined} options
   */
  constructor(deps, options) {
    /** @private @const {!./deps.DepsDef} */
    this.deps_ = deps;

    /** @private @const {!../api/subscriptions.OffersRequest|undefined} */
    this.options_ = options;

    /** @private @const {!../components/activities.ActivityPorts} */
    this.activityPorts_ = deps.activities();

    /** @private @const {!../components/dialog-manager.DialogManager} */
    this.dialogManager_ = deps.dialogManager();

    /** @private @const {!ActivityIframeView} */
    this.activityIframeView_ = new ActivityIframeView(
      deps.win(),
      this.activityPorts_,
      feUrl('/optionsiframe'),
      feArgs({
        'publicationId': deps.pageConfig().getPublicationId(),
        'productId': deps.pageConfig().getProductId(),
        'list': (options && options.list) || 'default',
        'skus': (options && options.skus) || null,
        'isClosable': true,
      }),
      /* shouldFadeBody */ false
    );
  }

  /**
   * Starts the offers flow or alreadySubscribed flow.
   * @return {!Promise}
   */
  start() {
    // Start/cancel events.
    this.deps_
      .callbacks()
      .triggerFlowStarted(SubscriptionFlows.SHOW_SUBSCRIBE_OPTION);
    this.activityIframeView_.onCancel(() => {
      this.deps_
        .callbacks()
        .triggerFlowCanceled(SubscriptionFlows.SHOW_SUBSCRIBE_OPTION);
    });

    this.activityIframeView_.onMessageDeprecated(data => {
      this.maybeOpenOffersFlow_(data);
    });
    this.activityIframeView_.acceptResult().then(
      result => {
        this.maybeOpenOffersFlow_(result.data);
      },
      reason => {
        this.dialogManager_.completeView(this.activityIframeView_);
        throw reason;
      }
    );
    return this.dialogManager_.openView(this.activityIframeView_);
  }

  /**
   * @param {*} data
   * @private
   */
  maybeOpenOffersFlow_(data) {
    if (data && data['subscribe']) {
      const options = this.options_ || {};
      if (options.isClosable == undefined) {
        options.isClosable = OFFERS_VIEW_CLOSABLE;
      }
      new OffersFlow(this.deps_, options).start();
    }
  }
}

/**
 * The class for Abbreviated Offer flow.
 *
 */
export class AbbrvOfferFlow {
  /**
   * @param {!./deps.DepsDef} deps
   * @param {!../api/subscriptions.OffersRequest=} options
   */
  constructor(deps, options = {}) {
    /** @private @const {!./deps.DepsDef} */
    this.deps_ = deps;

    /** @private @const {!../api/subscriptions.OffersRequest|undefined} */
    this.options_ = options;

    /** @private @const {!Window} */
    this.win_ = deps.win();

    /** @private @const {!../components/activities.ActivityPorts} */
    this.activityPorts_ = deps.activities();

    /** @private @const {!../components/dialog-manager.DialogManager} */
    this.dialogManager_ = deps.dialogManager();

    /** @private @const {!ActivityIframeView} */
    this.activityIframeView_ = new ActivityIframeView(
      this.win_,
      this.activityPorts_,
      feUrl('/abbrvofferiframe'),
      feArgs({
        'publicationId': deps.pageConfig().getPublicationId(),
        'productId': deps.pageConfig().getProductId(),
        'showNative': deps.callbacks().hasSubscribeRequestCallback(),
        'list': (options && options.list) || 'default',
        'skus': (options && options.skus) || null,
        'isClosable': true,
      }),
      /* shouldFadeBody */ false
    );
  }

  /**
   * Starts the offers flow
   * @return {!Promise}
   */
  start() {
    // Start/cancel events.
    this.deps_
      .callbacks()
      .triggerFlowStarted(SubscriptionFlows.SHOW_ABBRV_OFFER);
    this.activityIframeView_.onCancel(() => {
      this.deps_
        .callbacks()
        .triggerFlowCanceled(SubscriptionFlows.SHOW_ABBRV_OFFER);
    });

    // If the user is already subscribed, trigger login flow
    this.activityIframeView_.onMessageDeprecated(data => {
      if (data['alreadySubscribed']) {
        this.deps_.callbacks().triggerLoginRequest({
          linkRequested: !!data['linkRequested'],
        });
        return;
      }
    });
    // If result is due to requesting offers, redirect to offers flow
    this.activityIframeView_.acceptResult().then(result => {
      if (result.data['viewOffers']) {
        const options = this.options_ || {};
        if (options.isClosable == undefined) {
          options.isClosable = OFFERS_VIEW_CLOSABLE;
        }
        new OffersFlow(this.deps_, options).start();
        return;
      }
      if (result.data['native']) {
        this.deps_.callbacks().triggerSubscribeRequest();
        // The flow is complete.
        this.dialogManager_.completeView(this.activityIframeView_);
        return;
      }
    });

    return this.dialogManager_.openView(this.activityIframeView_);
  }
}
<commit_msg>Fixed type error (hopefully) by adding default proration<commit_after>/**
 * Copyright 2018 The Subscribe with Google Authors. 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 {ActivityIframeView} from '../ui/activity-iframe-view';
import {PayStartFlow} from './pay-flow';
import {SubscriptionFlows, ProductType, ReplaceSkuProrationMode} from '../api/subscriptions';
import {feArgs, feUrl} from './services';

/**
 * Offers view is closable when request was originated from 'AbbrvOfferFlow'
 * or from 'SubscribeOptionFlow'.
 */
const OFFERS_VIEW_CLOSABLE = true;

/**
 * The class for Offers flow.
 */
export class OffersFlow {
  /**
   * @param {!./deps.DepsDef} deps
   * @param {!../api/subscriptions.OffersRequest|undefined} options
   */
  constructor(deps, options) {
    /** @private @const {!./deps.DepsDef} */
    this.deps_ = deps;

    /** @private @const {!Window} */
    this.win_ = deps.win();

    /** @private @const {!../components/activities.ActivityPorts} */
    this.activityPorts_ = deps.activities();

    /** @private @const {!../components/dialog-manager.DialogManager} */
    this.dialogManager_ = deps.dialogManager();

    let isClosable = options && options.isClosable;
    if (isClosable == undefined) {
      isClosable = false; // Default is to hide Close button.
    }

    const feArgsObj = {
      'productId': deps.pageConfig().getProductId(),
      'publicationId': deps.pageConfig().getPublicationId(),
      'showNative': deps.callbacks().hasSubscribeRequestCallback(),
      'productType': ProductType.SUBSCRIPTION,
      'list': (options && options.list) || 'default',
      'skus': (options && options.skus) || null,
      'isClosable': isClosable,
    };

    if (options && options.oldSku) {
      feArgsObj['oldSku'] = options.oldSku;
    }

    if (feArgsObj['oldSku']) {
      if (!feArgsObj['skus']) {
        console.error('Need a sku list if old sku is provided!');
        return;
      }
      // remove old sku from offers if in list
      let skuList = feArgsObj['skus'];
      const /** @type {String} */ oldSku = feArgsObj['oldSku'];
      skuList = skuList.filter(sku => sku !== oldSku);
      if (skuList.length > 0) {
        feArgsObj['skus'] = skuList;
      } else {
        console.error('Sku list only contained offer user already has');
        return;
      }
    }

    // redirect to payments if only one upgrade option is passed
    if (feArgsObj['skus'] && feArgsObj['skus'].length === 1) {
      const sku = feArgsObj['skus'][0];
      const /** @type {String} */ oldSku = feArgsObj['oldSku'];
      // object currently requires experimental flag
      // so we need to check for oldSku to decide what to send
      if (oldSku) {
        new PayStartFlow(this.deps_, {
          skuId: sku,
          oldSkuId: oldSku,
          replaceSkuProrationMode: ReplaceSkuProrationMode.IMMEDIATE_WITH_TIME_PRORATION,
        }).start();
        return;
      } else {
        new PayStartFlow(this.deps_, sku).start();
        return;
      }
    }
    /** @private @const {!ActivityIframeView} */
    this.activityIframeView_ = new ActivityIframeView(
      this.win_,
      this.activityPorts_,
      feUrl('/offersiframe'),
      feArgs(feArgsObj),
      /* shouldFadeBody */ true
    );
  }

  /**
   * Starts the offers flow or alreadySubscribed flow.
   * @return {!Promise}
   */
  start() {
    if (this.activityIframeView_) {
      // so no error is thrown if offers skipped
      // Start/cancel events.
      this.deps_.callbacks().triggerFlowStarted(SubscriptionFlows.SHOW_OFFERS);
      this.activityIframeView_.onCancel(() => {
        this.deps_
          .callbacks()
          .triggerFlowCanceled(SubscriptionFlows.SHOW_OFFERS);
      });

      // If result is due to OfferSelection, redirect to payments.
      this.activityIframeView_.onMessageDeprecated(result => {
        if (result['alreadySubscribed']) {
          this.deps_.callbacks().triggerLoginRequest({
            linkRequested: !!result['linkRequested'],
          });
          return new Promise();
        }
        if (result['oldSku']) {
          new PayStartFlow(this.deps_, {
            skuId: result['sku'],
            oldSkuId: result['oldSku'],
            replaceSkuProrationMode: ReplaceSkuProrationMode.IMMEDIATE_WITH_TIME_PRORATION,
          }).start();
          return new Promise();
        }
        if (result['sku']) {
          new PayStartFlow(
            this.deps_,
            /** @type {string} */ (result['sku'])
          ).start();
          return new Promise();
        }
        if (result['native']) {
          this.deps_.callbacks().triggerSubscribeRequest();
          return new Promise();
        }
      });

      return this.dialogManager_.openView(this.activityIframeView_);
    }
  }
}

/**
 * The class for subscribe option flow.
 */
export class SubscribeOptionFlow {
  /**
   * @param {!./deps.DepsDef} deps
   * @param {!../api/subscriptions.OffersRequest|undefined} options
   */
  constructor(deps, options) {
    /** @private @const {!./deps.DepsDef} */
    this.deps_ = deps;

    /** @private @const {!../api/subscriptions.OffersRequest|undefined} */
    this.options_ = options;

    /** @private @const {!../components/activities.ActivityPorts} */
    this.activityPorts_ = deps.activities();

    /** @private @const {!../components/dialog-manager.DialogManager} */
    this.dialogManager_ = deps.dialogManager();

    /** @private @const {!ActivityIframeView} */
    this.activityIframeView_ = new ActivityIframeView(
      deps.win(),
      this.activityPorts_,
      feUrl('/optionsiframe'),
      feArgs({
        'publicationId': deps.pageConfig().getPublicationId(),
        'productId': deps.pageConfig().getProductId(),
        'list': (options && options.list) || 'default',
        'skus': (options && options.skus) || null,
        'isClosable': true,
      }),
      /* shouldFadeBody */ false
    );
  }

  /**
   * Starts the offers flow or alreadySubscribed flow.
   * @return {!Promise}
   */
  start() {
    // Start/cancel events.
    this.deps_
      .callbacks()
      .triggerFlowStarted(SubscriptionFlows.SHOW_SUBSCRIBE_OPTION);
    this.activityIframeView_.onCancel(() => {
      this.deps_
        .callbacks()
        .triggerFlowCanceled(SubscriptionFlows.SHOW_SUBSCRIBE_OPTION);
    });

    this.activityIframeView_.onMessageDeprecated(data => {
      this.maybeOpenOffersFlow_(data);
    });
    this.activityIframeView_.acceptResult().then(
      result => {
        this.maybeOpenOffersFlow_(result.data);
      },
      reason => {
        this.dialogManager_.completeView(this.activityIframeView_);
        throw reason;
      }
    );
    return this.dialogManager_.openView(this.activityIframeView_);
  }

  /**
   * @param {*} data
   * @private
   */
  maybeOpenOffersFlow_(data) {
    if (data && data['subscribe']) {
      const options = this.options_ || {};
      if (options.isClosable == undefined) {
        options.isClosable = OFFERS_VIEW_CLOSABLE;
      }
      new OffersFlow(this.deps_, options).start();
    }
  }
}

/**
 * The class for Abbreviated Offer flow.
 *
 */
export class AbbrvOfferFlow {
  /**
   * @param {!./deps.DepsDef} deps
   * @param {!../api/subscriptions.OffersRequest=} options
   */
  constructor(deps, options = {}) {
    /** @private @const {!./deps.DepsDef} */
    this.deps_ = deps;

    /** @private @const {!../api/subscriptions.OffersRequest|undefined} */
    this.options_ = options;

    /** @private @const {!Window} */
    this.win_ = deps.win();

    /** @private @const {!../components/activities.ActivityPorts} */
    this.activityPorts_ = deps.activities();

    /** @private @const {!../components/dialog-manager.DialogManager} */
    this.dialogManager_ = deps.dialogManager();

    /** @private @const {!ActivityIframeView} */
    this.activityIframeView_ = new ActivityIframeView(
      this.win_,
      this.activityPorts_,
      feUrl('/abbrvofferiframe'),
      feArgs({
        'publicationId': deps.pageConfig().getPublicationId(),
        'productId': deps.pageConfig().getProductId(),
        'showNative': deps.callbacks().hasSubscribeRequestCallback(),
        'list': (options && options.list) || 'default',
        'skus': (options && options.skus) || null,
        'isClosable': true,
      }),
      /* shouldFadeBody */ false
    );
  }

  /**
   * Starts the offers flow
   * @return {!Promise}
   */
  start() {
    // Start/cancel events.
    this.deps_
      .callbacks()
      .triggerFlowStarted(SubscriptionFlows.SHOW_ABBRV_OFFER);
    this.activityIframeView_.onCancel(() => {
      this.deps_
        .callbacks()
        .triggerFlowCanceled(SubscriptionFlows.SHOW_ABBRV_OFFER);
    });

    // If the user is already subscribed, trigger login flow
    this.activityIframeView_.onMessageDeprecated(data => {
      if (data['alreadySubscribed']) {
        this.deps_.callbacks().triggerLoginRequest({
          linkRequested: !!data['linkRequested'],
        });
        return;
      }
    });
    // If result is due to requesting offers, redirect to offers flow
    this.activityIframeView_.acceptResult().then(result => {
      if (result.data['viewOffers']) {
        const options = this.options_ || {};
        if (options.isClosable == undefined) {
          options.isClosable = OFFERS_VIEW_CLOSABLE;
        }
        new OffersFlow(this.deps_, options).start();
        return;
      }
      if (result.data['native']) {
        this.deps_.callbacks().triggerSubscribeRequest();
        // The flow is complete.
        this.dialogManager_.completeView(this.activityIframeView_);
        return;
      }
    });

    return this.dialogManager_.openView(this.activityIframeView_);
  }
}
<|endoftext|>


<commit_before>(function() {
    tm.asset = tm.asset || {};

    _modelPath = "";

    tm.define("tm.asset.MQO", {
        superClass: "tm.event.EventDispatcher",

        model: null,

        init: function(path) {
            this.superInit();
            this.loadFromURL(path);
        },

        // URLからロード
        loadFromURL: function(path) {
            var modelurl = path.split("/");
            _modelPath = "";
            for (var i = 0, len = modelurl.length; i < len-1; i++) {
                _modelPath += modelurl[i];
            }

            var req = new XMLHttpRequest();
            req.open("GET", path, true);
            req.onload = function() {
                var data = req.responseText;
                that.loadFromData(data);
            };
            req.send(null);
            var that = this;
        },

        //データからロード
        loadFromData: function(data) {
            this.model = tm.MQOModel(data);
            this.flare("load");
        },
    });

    //ローダーに拡張子登録
    tm.asset.Loader.register("mqo", function(path) {
        return tm.asset.MQO(path);
    });

    /*
     * メタセコイアモデル
     */
    tm.define("tm.MQOModel", {
        //変換後メッシュアレイ
        meshes: [],

        //メッシュアレイ
        _rawMeshes: [],

        //マテリアルアレイ
        _rawMaterials: null,

        init: function(data) {
            this.parse(data);
            this.convert();
        },

        parse: function(data) {
            // マテリアル
            var materialText = data.match(/^Material [\s\S]*?^\}/m);
            this._rawMaterials = tm.MQOMaterial(materialText[0]);       //マテリアルチャンクは原則一つ

            // オブジェクト
            var objectText = data.match(/^Object [\s\S]*?^\}/gm);
            for (var i = 0, len = objectText.length; i < len; ++i) {
                var mesh = tm.MQOMesh(objectText[i]);
                this._rawMeshes.push(mesh);
            }
        },

        convert: function(){
            this.meshes = [];
            for (var i = 0, len = this._rawMeshes.length; i < len; i++) {
                var mesh = this._rawMeshes[i];
                var list = mesh.convert(this._rawMaterials);
                for (var j = 0, len = list.length; j < len; j++) {
                    this.meshes.push(list[j]);
                }
            }
        },
    });

    /*
     * メタセコイアメッシュ
     */
    tm.define("tm.MQOMesh", {
        vertices: [],   // 頂点
        faces: [],      // 面情報
        vertNormals: [],// 頂点法線

        facet: 59.5,    // スムージング角度

        mirror: 0,      //ミラーリング
        mirrorAxis: 0,  //ミラーリング軸

        init: function(text) {
            this.parse(text);
        },

        parse:function(text){
            //オブジェクト名
            var name = text.split(' ');
            this.name = name[1].replace(/"/g, "");

            //スムージング角
            var facet = text.match(/facet ([0-9\.]+)/);
            if( facet ){ this.facet = Number(facet[1]); }

            //可視フラグ
            var visible = text.match(/visible ([0-9\.]+)/);
            if( visible ){ this.visible = Number(visible[1]); }

            //ミラーリング
            var mirror = text.match(/mirror ([0-9])/m);
            if( mirror ){
                this.mirror = Number(mirror[1]);
                // 軸
                var mirrorAxis = text.match(/mirror_axis ([0-9])/m);
                if( mirrorAxis ){
                    this.mirrorAxis = Number(mirrorAxis[1]);
                }
            }

            //頂点情報
            var vertex_txt = text.match(/vertex ([0-9]+).+\{\s([\w\W]+)}$/gm);
            this._parseVertices( RegExp.$1, RegExp.$2 );

            //フェース情報
            var face_txt = text.match(/face ([0-9]+).+\{\s([\w\W]+)}$/gm);
            this._parseFaces( RegExp.$1, RegExp.$2 );
        },

        convert: function(materials){
            //不可視設定の場合は処理をスキップ
            if( this.visible == 0 ){
                return [];  //空の配列を返す
            }

            //フェースが使用するマテリアルを調べる
            var facemat = [];
            facemat[facemat.length] = this.faces[0].m[0];
            for (var i = 0, lf = this.faces.length; i < lf; i++) {
                var fm = -1;
                for (var j = 0, lfm = facemat.length; j < lfm; j++) {
                    if( facemat[j] != this.faces[i].m[0] )fm = this.faces[i].m[0];
                }
                if( fm != -1 )facemat.push(fm);
            }

            //使用マテリアルに応じてオブジェクトを分割変換
            var meshList = []
            for (var mn = 0; mn < facemat.length; mn++) {
                var matnum = facemat[mn];
                var sp = this.build(matnum, materials.materials[matnum]);
                meshList.push(sp);
            }
            return meshList;
        },

        /*
         * フェース情報からマテリアルに対応した頂点情報を構築
         * THREE形式専用
         */
        build: function(num, mqoMat) {
            //マテリアル情報
            //シェーダーパラメータによってマテリアルを使い分ける
            var mat = null;
            if(mqoMat.shader == 2) {
                mat = new THREE.MeshLambertMaterial();
            } else if(mqoMat.shader == 3) {
                mat = new THREE.MeshPhongMaterial();
            } else  {
                mat = new THREE.MeshBasicMaterial();
            }
            var r = mqoMat.col[0];
            var g = mqoMat.col[1];
            var b = mqoMat.col[2];
            if (mat.color) mat.color.setRGB(r*mqoMat.dif, g*mqoMat.dif, b*mqoMat.dif);
            if (mat.emissive) mat.emissive.setRGB(r*mqoMat.emi, g*mqoMat.emi, b*mqoMat.emi);
            if (mat.ambient) mat.ambient.setRGB(r*mqoMat.amb, g*mqoMat.amb, b*mqoMat.amb);
            if (mat.specular) mat.specular.setRGB(r*mqoMat.spc, g*mqoMat.spc, b*mqoMat.spc);
            if (mqoMat.tex) {
                mat.map = THREE.ImageUtils.loadTexture(_modelPath+"/"+mqoMat.tex);
            }
            mat.transparent = true;
            mat.shiness = mqoMat.power;
            mat.opacity = mqoMat.col[3]

            //頂点情報
            var scale = 10;
            var geo = new THREE.Geometry();
            for(var i = 0; i < this.vertices.length; i+=3) {
                geo.vertices.push(new THREE.Vector3(
                    this.vertices[i+0]*scale,
                    this.vertices[i+1]*scale,
                    this.vertices[i+2]*scale));
            }

            //インデックス情報
            for (var i = 0, len = this.faces.length; i < len; i++) {
                var face = this.faces[i];
                var vIndex = face.v;
                var index = geo.vertices.length;
                if (face.vNum == 3) {
                    var face3 = new THREE.Face3(vIndex[2], vIndex[1], vIndex[0], undefined, undefined, face.m[0]);
                    geo.faces.push(face3);

                    //法線

                    // ＵＶ座標
                    geo.faceVertexUvs[0].push([
                        new THREE.Vector2(face.uv[4], 1.0 - face.uv[5]),
                        new THREE.Vector2(face.uv[2], 1.0 - face.uv[3]),
                        new THREE.Vector2(face.uv[0], 1.0 - face.uv[1])]);
                } else if (face.vNum == 4) {
                }
            }

            //メッシュ生成
            var obj = new THREE.Mesh(geo, mat);
            return obj;
        },

        //頂点情報のパース
        _parseVertices: function(num, text) {
            var vertexTextList = text.split('\n');
            for (var i = 1; i <= num; i++) {
                var vertex = vertexTextList[i].split(' ');
                vertex[0] = Number(vertex[0])*0.01;
                vertex[1] = Number(vertex[1])*0.01;
                vertex[2] = Number(vertex[2])*0.01;
                this.vertices.push(vertex);
            }

            //ミラーリング対応
            if (this.mirror) {
                var self = this;
                var toMirror = (function(){
                    return {
                        1: function(v) { return [ v[0]*-1, v[1], v[2] ]; },
                        2: function(v) { return [ v[0], v[1]*-1, v[2] ]; },
                        4: function(v) { return [ v[0], v[1], v[2]*-1 ]; },
                    }[self.mirrorAxis];
                })();
                var len = this.vertices.length;
                for (var i = 0; i < len; i++) {
                    this.vertices.push(toMirror(this.vertices[i]));
                }
            }
        },

        //フェース情報のパース
        _parseFaces: function(num, text) {
            var faceTextList = text.split('\n');

            //法線計算
            var calcNormalize = function(a, b, c) {
                var v1 = [ a[0] - b[0], a[1] - b[1], a[2] - b[2] ];
                var v2 = [ c[0] - b[0], c[1] - b[1], c[2] - b[2] ];
                var v3 = [
                    v1[1]*v2[2] - v1[2]*v2[1],
                    v1[2]*v2[0] - v1[0]*v2[2],
                    v1[0]*v2[1] - v1[1]*v2[0]
                ];
                var len = Math.sqrt(v3[0]*v3[0] + v3[1]*v3[1] + v3[2]*v3[2]);
                v3[0] /= len;
                v3[1] /= len;
                v3[2] /= len;

                return v3;
            };

            for (var i = 1; i <= num; i++ ){
                // トリムっとく
                var faceText = faceTextList[i].replace(/^\s+|\s+$/g, "");
                // 面の数
                var vertex_num = Number(faceText[0]);

                var info = faceText.match(/([A-Za-z]+)\(([\w\s\-\.\(\)]+?)\)/gi);
                var face = { vNum: vertex_num };

                for (var j = 0, len = info.length; j < len; j++) {
                    var m = info[j].match(/([A-Za-z]+)\(([\w\s\-\.\(\)]+?)\)/);
                    var key = m[1].toLowerCase();
                    var value = m[2].split(" ");
                    value.forEach(function(elm, i, arr){
                        arr[i] = Number(elm);
                    });
                    face[key] = value;
                }

                // UV デフォルト値
                if (!face.uv) {
                    face.uv = [0, 0, 0, 0, 0, 0, 0, 0];
                }

                // マテリアル デフォルト値
                if (!face.m) {
                    face.m = [undefined];
                }

                // 法線（面の場合のみ）
                if (face.v.length > 2) {
                    face.n = calcNormalize(this.vertices[face.v[0]], this.vertices[face.v[1]], this.vertices[face.v[2]]);
                }

                this.faces.push(face);
            }

            // ミラーリング対応
            if( this.mirror ){
                var swap = function(a,b){ var temp = this[a]; this[a] = this[b]; this[b] = temp; return this; };
                var len = this.faces.length;
                var vertexOffset = (this.vertices.length/2);
                for(var i = 0; i < len; i++) {
                    var targetFace = this.faces[i];
                    var face = {
                        uv  : [],
                        v   : [],
                        vNum: targetFace.vNum,
                    };
                    for (var j = 0; j < targetFace.v.length; j++) { face.v[j] = targetFace.v[j] + vertexOffset; }
                    for (var j = 0; j < targetFace.uv.length; j++) { face.uv[j] = targetFace.uv[j]; }

                    if (face.vNum == 3) {
                        swap.call(face.v, 1, 2);
                    } else {
                        swap.call(face.v, 0, 1);
                        swap.call(face.v, 2, 3);
                    }

                    face.n = targetFace.n;
                    face.m = targetFace.m;

                    this.faces.push(face);
                }
            }

            // 頂点法線を求める
            var vertNormal = Array(this.vertices.length);
            for (var i = 0, len = this.vertices.length; i < len; i++) vertNormal[i] = [];

            for (var i = 0; i < this.faces.length; i++) {
                var face = this.faces[i];
                var vIndices = face.v;

                for (var j = 0; j < face.vNum; j++) {
                    var index = vIndices[j];
                    vertNormal[index].push.apply(vertNormal[index], face.n);
                }
            }

            for (var i = 0; i < vertNormal.length; i++) {
                var vn = vertNormal[i];
                var result = [0, 0, 0];
                var len = vn.length/3;
                for (var j = 0; j < len; j++) {
                    result[0] += vn[j*3+0];
                    result[1] += vn[j*3+1];
                    result[2] += vn[j*3+2];
                }

                result[0] /= len;
                result[1] /= len;
                result[2] /= len;

                var len = Math.sqrt(result[0]*result[0] + result[1]*result[1] + result[2]*result[2]);
                result[0] /= len;
                result[1] /= len;
                result[2] /= len;

                this.vertNormals[i] = result;
            }
        },
    });

    /*
     * メタセコイアマテリアル
     */
    tm.define("tm.MQOMaterial", {
        materials: [],

        init: function(data) {
            this.parse(data);
        },

        //マテリアル情報のパース
        parse: function(data) {
            var infoText    = data.match(/^Material [0-9]* \{\r\n([\s\S]*?)\n^\}$/m);
            var matTextList = infoText[1].split('\n');

            for (var i = 0, len = matTextList.length; i < len; i++) {
                var mat = {};
                // トリムっとく
                var matText = matTextList[i].replace(/^\s+|\s+$/g, "");
                var info = matText.match(/([A-Za-z]+)\(([\w\W]+?)\)/gi);    //マテリアル情報一個分抜く

                var nl = matText.split(' ');    //マテリアル名取得
                mat['name'] = nl[0].replace(/"/g, "");

                for( var j = 0, len2 = info.length; j < len2; j++ ){
                    var m = info[j].match(/([A-Za-z]+)\(([\w\W]+?)\)/); //要素を抜き出す
                    var key = m[1].toLowerCase();   //文字列小文字化
                    var value = null;

                    if( key != "tex" && key != "aplane" ){
                        //テクスチャ以外の要素
                        value = m[2].split(" ");
                        value.forEach(function(elm, i, arr){
                            arr[i] = Number(elm);
                        });
                    }else{
                        //テクスチャの場合
                        value = m[2].replace(/"/g, "");
                    }
                    mat[key] = value;
                }
                this.materials.push(mat);
            }
        },
        convert: function() {
        },
    });

})();

<commit_msg>delete comment<commit_after>(function() {
    tm.asset = tm.asset || {};

    _modelPath = "";

    tm.define("tm.asset.MQO", {
        superClass: "tm.event.EventDispatcher",

        model: null,

        init: function(path) {
            this.superInit();
            this.loadFromURL(path);
        },

        loadFromURL: function(path) {
            var modelurl = path.split("/");
            _modelPath = "";
            for (var i = 0, len = modelurl.length; i < len-1; i++) {
                _modelPath += modelurl[i];
            }

            var req = new XMLHttpRequest();
            req.open("GET", path, true);
            req.onload = function() {
                var data = req.responseText;
                that.loadFromData(data);
            };
            req.send(null);
            var that = this;
        },

        loadFromData: function(data) {
            this.model = tm.MQOModel(data);
            this.flare("load");
        },
    });

    tm.asset.Loader.register("mqo", function(path) {
        return tm.asset.MQO(path);
    });

    tm.define("tm.MQOModel", {
        meshes: [],
        _rawMeshes: [],
        _rawMaterials: null,

        init: function(data) {
            this.parse(data);
            this.convert();
        },

        parse: function(data) {
            var materialText = data.match(/^Material [\s\S]*?^\}/m);
            this._rawMaterials = tm.MQOMaterial(materialText[0]);

            var objectText = data.match(/^Object [\s\S]*?^\}/gm);
            for (var i = 0, len = objectText.length; i < len; ++i) {
                var mesh = tm.MQOMesh(objectText[i]);
                this._rawMeshes.push(mesh);
            }
        },

        convert: function(){
            this.meshes = [];
            for (var i = 0, len = this._rawMeshes.length; i < len; i++) {
                var mesh = this._rawMeshes[i];
                var list = mesh.convert(this._rawMaterials);
                for (var j = 0, len = list.length; j < len; j++) {
                    this.meshes.push(list[j]);
                }
            }
        },
    });

    tm.define("tm.MQOMesh", {
        vertices: [],
        faces: [],
        vertNormals: [],

        facet: 59.5,

        mirror: 0,
        mirrorAxis: 0,

        init: function(text) {
            this.parse(text);
        },

        parse:function(text){
            var name = text.split(' ');
            this.name = name[1].replace(/"/g, "");

            var facet = text.match(/facet ([0-9\.]+)/);
            if( facet ){ this.facet = Number(facet[1]); }

            var visible = text.match(/visible ([0-9\.]+)/);
            if( visible ){ this.visible = Number(visible[1]); }

            var mirror = text.match(/mirror ([0-9])/m);
            if( mirror ){
                this.mirror = Number(mirror[1]);

                var mirrorAxis = text.match(/mirror_axis ([0-9])/m);
                if( mirrorAxis ){
                    this.mirrorAxis = Number(mirrorAxis[1]);
                }
            }

            var vertex_txt = text.match(/vertex ([0-9]+).+\{\s([\w\W]+)}$/gm);
            this._parseVertices( RegExp.$1, RegExp.$2 );

            var face_txt = text.match(/face ([0-9]+).+\{\s([\w\W]+)}$/gm);
            this._parseFaces( RegExp.$1, RegExp.$2 );
        },

        convert: function(materials){
            if( this.visible == 0 ){
                return [];
            }

            var facemat = [];
            facemat[facemat.length] = this.faces[0].m[0];
            for (var i = 0, lf = this.faces.length; i < lf; i++) {
                var fm = -1;
                for (var j = 0, lfm = facemat.length; j < lfm; j++) {
                    if( facemat[j] != this.faces[i].m[0] )fm = this.faces[i].m[0];
                }
                if( fm != -1 )facemat.push(fm);
            }

            var meshList = []
            for (var mn = 0; mn < facemat.length; mn++) {
                var matnum = facemat[mn];
                var sp = this.build(matnum, materials.materials[matnum]);
                meshList.push(sp);
            }
            return meshList;
        },

        build: function(num, mqoMat) {
            var mat = null;
            if(mqoMat.shader == 2) {
                mat = new THREE.MeshLambertMaterial();
            } else if(mqoMat.shader == 3) {
                mat = new THREE.MeshPhongMaterial();
            } else  {
                mat = new THREE.MeshBasicMaterial();
            }
            var r = mqoMat.col[0];
            var g = mqoMat.col[1];
            var b = mqoMat.col[2];
            if (mat.color) mat.color.setRGB(r*mqoMat.dif, g*mqoMat.dif, b*mqoMat.dif);
            if (mat.emissive) mat.emissive.setRGB(r*mqoMat.emi, g*mqoMat.emi, b*mqoMat.emi);
            if (mat.ambient) mat.ambient.setRGB(r*mqoMat.amb, g*mqoMat.amb, b*mqoMat.amb);
            if (mat.specular) mat.specular.setRGB(r*mqoMat.spc, g*mqoMat.spc, b*mqoMat.spc);
            if (mqoMat.tex) {
                mat.map = THREE.ImageUtils.loadTexture(_modelPath+"/"+mqoMat.tex);
            }
            mat.transparent = true;
            mat.shiness = mqoMat.power;
            mat.opacity = mqoMat.col[3]

            var scale = 10;
            var geo = new THREE.Geometry();
            for(var i = 0; i < this.vertices.length; i+=3) {
                geo.vertices.push(new THREE.Vector3(
                    this.vertices[i+0]*scale,
                    this.vertices[i+1]*scale,
                    this.vertices[i+2]*scale));
            }

            for (var i = 0, len = this.faces.length; i < len; i++) {
                var face = this.faces[i];
                var vIndex = face.v;
                var index = geo.vertices.length;
                if (face.vNum == 3) {
                    var face3 = new THREE.Face3(vIndex[2], vIndex[1], vIndex[0], undefined, undefined, face.m[0]);
                    geo.faces.push(face3);

                    geo.faceVertexUvs[0].push([
                        new THREE.Vector2(face.uv[4], 1.0 - face.uv[5]),
                        new THREE.Vector2(face.uv[2], 1.0 - face.uv[3]),
                        new THREE.Vector2(face.uv[0], 1.0 - face.uv[1])]);
                } else if (face.vNum == 4) {
                }
            }

            var obj = new THREE.Mesh(geo, mat);
            return obj;
        },

        _parseVertices: function(num, text) {
            var vertexTextList = text.split('\n');
            for (var i = 1; i <= num; i++) {
                var vertex = vertexTextList[i].split(' ');
                vertex[0] = Number(vertex[0])*0.01;
                vertex[1] = Number(vertex[1])*0.01;
                vertex[2] = Number(vertex[2])*0.01;
                this.vertices.push(vertex);
            }

            if (this.mirror) {
                var self = this;
                var toMirror = (function(){
                    return {
                        1: function(v) { return [ v[0]*-1, v[1], v[2] ]; },
                        2: function(v) { return [ v[0], v[1]*-1, v[2] ]; },
                        4: function(v) { return [ v[0], v[1], v[2]*-1 ]; },
                    }[self.mirrorAxis];
                })();
                var len = this.vertices.length;
                for (var i = 0; i < len; i++) {
                    this.vertices.push(toMirror(this.vertices[i]));
                }
            }
        },

        _parseFaces: function(num, text) {
            var faceTextList = text.split('\n');

            var calcNormalize = function(a, b, c) {
                var v1 = [ a[0] - b[0], a[1] - b[1], a[2] - b[2] ];
                var v2 = [ c[0] - b[0], c[1] - b[1], c[2] - b[2] ];
                var v3 = [
                    v1[1]*v2[2] - v1[2]*v2[1],
                    v1[2]*v2[0] - v1[0]*v2[2],
                    v1[0]*v2[1] - v1[1]*v2[0]
                ];
                var len = Math.sqrt(v3[0]*v3[0] + v3[1]*v3[1] + v3[2]*v3[2]);
                v3[0] /= len;
                v3[1] /= len;
                v3[2] /= len;

                return v3;
            };

            for (var i = 1; i <= num; i++ ){

                var faceText = faceTextList[i].replace(/^\s+|\s+$/g, "");

                var vertex_num = Number(faceText[0]);

                var info = faceText.match(/([A-Za-z]+)\(([\w\s\-\.\(\)]+?)\)/gi);
                var face = { vNum: vertex_num };

                for (var j = 0, len = info.length; j < len; j++) {
                    var m = info[j].match(/([A-Za-z]+)\(([\w\s\-\.\(\)]+?)\)/);
                    var key = m[1].toLowerCase();
                    var value = m[2].split(" ");
                    value.forEach(function(elm, i, arr){
                        arr[i] = Number(elm);
                    });
                    face[key] = value;
                }

                if (!face.uv) {
                    face.uv = [0, 0, 0, 0, 0, 0, 0, 0];
                }

                if (!face.m) {
                    face.m = [undefined];
                }

                if (face.v.length > 2) {
                    face.n = calcNormalize(this.vertices[face.v[0]], this.vertices[face.v[1]], this.vertices[face.v[2]]);
                }

                this.faces.push(face);
            }

            if( this.mirror ){
                var swap = function(a,b){ var temp = this[a]; this[a] = this[b]; this[b] = temp; return this; };
                var len = this.faces.length;
                var vertexOffset = (this.vertices.length/2);
                for(var i = 0; i < len; i++) {
                    var targetFace = this.faces[i];
                    var face = {
                        uv  : [],
                        v   : [],
                        vNum: targetFace.vNum,
                    };
                    for (var j = 0; j < targetFace.v.length; j++) { face.v[j] = targetFace.v[j] + vertexOffset; }
                    for (var j = 0; j < targetFace.uv.length; j++) { face.uv[j] = targetFace.uv[j]; }

                    if (face.vNum == 3) {
                        swap.call(face.v, 1, 2);
                    } else {
                        swap.call(face.v, 0, 1);
                        swap.call(face.v, 2, 3);
                    }

                    face.n = targetFace.n;
                    face.m = targetFace.m;

                    this.faces.push(face);
                }
            }

            var vertNormal = Array(this.vertices.length);
            for (var i = 0, len = this.vertices.length; i < len; i++) vertNormal[i] = [];

            for (var i = 0; i < this.faces.length; i++) {
                var face = this.faces[i];
                var vIndices = face.v;

                for (var j = 0; j < face.vNum; j++) {
                    var index = vIndices[j];
                    vertNormal[index].push.apply(vertNormal[index], face.n);
                }
            }

            for (var i = 0; i < vertNormal.length; i++) {
                var vn = vertNormal[i];
                var result = [0, 0, 0];
                var len = vn.length/3;
                for (var j = 0; j < len; j++) {
                    result[0] += vn[j*3+0];
                    result[1] += vn[j*3+1];
                    result[2] += vn[j*3+2];
                }

                result[0] /= len;
                result[1] /= len;
                result[2] /= len;

                var len = Math.sqrt(result[0]*result[0] + result[1]*result[1] + result[2]*result[2]);
                result[0] /= len;
                result[1] /= len;
                result[2] /= len;

                this.vertNormals[i] = result;
            }
        },
    });

    tm.define("tm.MQOMaterial", {
        materials: [],

        init: function(data) {
            this.parse(data);
        },

        parse: function(data) {
            var infoText    = data.match(/^Material [0-9]* \{\r\n([\s\S]*?)\n^\}$/m);
            var matTextList = infoText[1].split('\n');

            for (var i = 0, len = matTextList.length; i < len; i++) {
                var mat = {};

                var matText = matTextList[i].replace(/^\s+|\s+$/g, "");
                var info = matText.match(/([A-Za-z]+)\(([\w\W]+?)\)/gi);

                var nl = matText.split(' ');
                mat['name'] = nl[0].replace(/"/g, "");

                for( var j = 0, len2 = info.length; j < len2; j++ ){
                    var m = info[j].match(/([A-Za-z]+)\(([\w\W]+?)\)/);
                    var key = m[1].toLowerCase();
                    var value = null;

                    if( key != "tex" && key != "aplane" ){

                        value = m[2].split(" ");
                        value.forEach(function(elm, i, arr){
                            arr[i] = Number(elm);
                        });
                    }else{

                        value = m[2].replace(/"/g, "");
                    }
                    mat[key] = value;
                }
                this.materials.push(mat);
            }
        },
        convert: function() {
        },
    });

})();

<|endoftext|>


<commit_before><commit_msg>template of all the log entires<commit_after><|endoftext|>


<commit_before>var handlebars = require('./handlebars');
var type = require('./utils/get-type');

console.log(getType)
var APIDocGenerator = function() {
	this.generate = function(context, requests, options) {
		var request = context.getCurrentRequest();

		var headers = [];
		var params = [];
		var response = [];

		var responseBody = JSON.parse(request.getLastExchange().responseBody);
		if (responseBody.status === `SUCCESS` && responseBody.data) {
			for (var key in responseBody.data) {
				response.push({
					name: key,
					type: type.get(responseBody.data[key])
				});
			}
		}

		for (var key in request.headers) {
			headers.push({
				name: key,
				type: type.get(request.headers[key])
			});
		}

		for (var key in request.jsonBody) {
			params.push({
				name: key,
				type: type.get(request.jsonBody[key])
			});
		}

		var view = {
			headers: headers,
			params: params,
			response: response,
			method: request.method,
			request_name: request.name,
			request_description: request.description,
			request_group: request.parent ? request.parent.name : `...`,
			url: request.urlBase
		};

		var template = handlebars.compile(readFile('./ApiDocTemplate.hbs'));

		return template(view);
	};
};

APIDocGenerator.identifier = 'com.ygilany.PawExtensions.apiDocGenerator';
APIDocGenerator.title = 'ApiDoc Paw Generator';
APIDocGenerator.languageHighlighter = 'javascript'; // The Javascript highlighter doesn't highlight :(
APIDocGenerator.fileExtension = 'js';

registerCodeGenerator(APIDocGenerator);<commit_msg>get the types for the data (not done)<commit_after>var handlebars = require('./handlebars');

var APIDocGenerator = function () {
	this.generate = function (context, requests, options) {

		var getType = function (obj) {
			if (obj === undefined) return 'Undefined';
			if (obj === null) return 'Null';

			var typeString = Object.prototype.toString.call(obj);
			return typeString.slice(typeString.indexOf(' ') + 1, -1);
		};
		var request = context.getCurrentRequest();

		var headers = [];
		var params = [];
		var response = [];

		var responseBody = JSON.parse(request.getLastExchange().responseBody);
		if (responseBody.status === `SUCCESS` && responseBody.data) {
			for (var key in responseBody.data) {
				response.push({
					name: key,
					type: getType(responseBody.data[key])
				});
			}
		}

		for (var key in request.headers) {
			headers.push({
				name: key,
				type: getType(request.headers[key])
			});
		}

		for (var key in request.jsonBody) {
			params.push({
				name: key,
				type: getType(request.jsonBody[key])
			});
		}

		var view = {
			headers: headers,
			params: params,
			response: response,
			method: request.method,
			request_name: request.name,
			request_description: request.description,
			request_group: request.parent ? request.parent.name : `...`,
			url: request.urlBase
		};

		var template = handlebars.compile(readFile('./ApiDocTemplate.hbs'));

		return template(view);
	};
};

APIDocGenerator.identifier = 'com.ygilany.PawExtensions.apiDocGenerator';
APIDocGenerator.title = 'ApiDoc Paw Generator';
APIDocGenerator.languageHighlighter = 'javascript'; // The Javascript highlighter doesn't highlight :(
APIDocGenerator.fileExtension = 'js';

registerCodeGenerator(APIDocGenerator);<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var Game = function() {

  var dice = [];
  for (var i=0;i<5;++i) {
    dice.push(1 + (Math.random() * 6 | 0));
  }

  return {
    dice: function() {
      return dice;
    }
  };
};

var Chance = function() {};
var Yahtzee = function() {};
var Single = function(n) {};
var Pair = function() {};
var TwoPairs = function() {};
var ThreeOfAKind = function() {};
var FourOfAKind = function() {};
var SmallStraight = function() {};
var LargeStraight = function() {};
var FullHouse = function() {};

var categories = [
  new Chance(),
  new Yahtzee(),
  new Single(1),
  new Single(2),
  new Single(3),
  new Single(4),
  new Single(5),
  new Single(6),
  new Pair(),
  new TwoPairs(),
  new ThreeOfAKind(),
  new FourOfAKind(),
  new SmallStraight(),
  new LargeStraight(),
  new FullHouse()
];

describe('yahtzee', function() {
  describe('five dice', function() {
    it('should consist of 5 values between 1 and 6', function() {
      var yahtzee = new Game();
      assert(yahtzee);

      assert.equal(5, yahtzee.dice().length);

      for(var d=0;d<5;d++) {
        assert(yahtzee.dice()[d] > 0 && yahtzee.dice()[d] < 7);
      }
    });
  });

  describe('categories', function() {
    it('should have 15 categories', function() {
      assert.equal(15, categories.length);
    });
  });
});<commit_msg>failing test<commit_after>"use strict";

var assert = require('assert');

var Game = function() {

  var dice = [];
  for (var i=0;i<5;++i) {
    dice.push(1 + (Math.random() * 6 | 0));
  }

  return {
    dice: function() {
      return dice;
    }
  };
};

var Chance = function() {};
var Yahtzee = function() {};
var Single = function(n) {};
var Pair = function() {};
var TwoPairs = function() {};
var ThreeOfAKind = function() {};
var FourOfAKind = function() {};
var SmallStraight = function() {};
var LargeStraight = function() {};
var FullHouse = function() {};

var categories = [
  new Chance(),
  new Yahtzee(),
  new Single(1),
  new Single(2),
  new Single(3),
  new Single(4),
  new Single(5),
  new Single(6),
  new Pair(),
  new TwoPairs(),
  new ThreeOfAKind(),
  new FourOfAKind(),
  new SmallStraight(),
  new LargeStraight(),
  new FullHouse()
];

describe('yahtzee', function() {
  describe('five dice', function() {
    it('should consist of 5 values between 1 and 6', function() {
      var yahtzee = new Game();
      assert(yahtzee);

      assert.equal(5, yahtzee.dice().length);

      for(var d=0;d<5;d++) {
        assert(yahtzee.dice()[d] > 0 && yahtzee.dice()[d] < 7);
      }
    });
  });

  describe('categories', function() {
    it('should have 15 categories', function() {
      assert.equal(15, categories.length);
    });

    it('always accept chance', function() {
      assert(new Game().score(new Chance()) > 0);
    });
  });
});<|endoftext|>


<commit_before>import { DEAD, CHECKING, READY, PLAYING } from './player.js';
import { KinectBodyRenderer } from './kinect-body-renderer.js';

const FOREGROUND_COLOR = '#FFFFFF';
const BACKGROUND_COLOR = '#111111';
const PIPE_COLOR = 'rgb(170, 168, 57)';
const COLORS = [
  [45, 136, 45],
  [57, 50, 118],
  [170, 145, 57],
  [170, 57, 57],
  [85, 43, 114],
  [38, 114, 87],
  [170, 94, 57]
];

const INTERFACE_TEXT_SCALING = 0.03;
const INTERFACE_FONT = "1px 'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace";

var colorFor = function (index, alpha) {
  'use strict';

  let color = COLORS[index];
  if (alpha) {
    return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',0.5)';
  } else {
    return 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
  }
};

export class Renderer {
  constructor(canvas, options) {
    this.canvas = canvas;
    this.context = canvas.getContext('2d');

    if (options.kinect) {
      this.kinectBodyRenderer = new KinectBodyRenderer(this.context, options.kinect);
    }
  }

  render(gameState) {
    var context = this.context;

    context.save();
    this.clear();

    context.font = INTERFACE_FONT;
    context.translate(0.5 * this.canvas.width, 0.575 * this.canvas.height);
    context.scale(this.canvas.width, -0.85*this.canvas.height);
    this.renderStars(gameState.stars);
    this.renderBoxes(gameState.boxes);
    this.renderPlayers(gameState.players);
    this.renderParticles(gameState.particles);
    this.renderInterface(gameState);
    context.restore();

    if (this.kinectBodyRenderer) {
      context.save();
      context.scale(1.0, 0.15);
      context.rect(0, 0, this.canvas.width, this.canvas.height);
      context.clip();
      this.kinectBodyRenderer.clear(this.canvas.width, this.canvas.height);
      this.kinectBodyRenderer.renderBodiesFromPlayers(gameState.players);
      context.restore();
    }
  }

  clear() {
    let context = this.context;

    context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    context.fillStyle = BACKGROUND_COLOR;
    context.fillRect(0, 0, this.canvas.width, this.canvas.height);
  }

  renderStars(stars) {
    var context = this.context;

    context.fillStyle = '#FFFFFF';
    _.forEach(stars, function (star) {
      let size = 0.15 * star.speed;
      context.fillRect(star.x - size/2, star.y - size/2, size, size);
      context.beginPath();
      context.arc(star.x, star.y, 0.3 * star.speed, 0, 2*Math.PI);
      context.fill();
    });
  }

  renderBoxes(boxes) {
    var context = this.context;

    _.forEach(boxes, function (box) {
      context.fillStyle = PIPE_COLOR;
      context.fillRect(
        box.position.x - box.halfWidth,
        box.position.y - box.halfHeight,
        box.halfWidth * 2,
        box.halfHeight * 2
      );
    });
  }

  renderPlayers(players) {
    var context = this.context;

    _.forEach(players, function (player, index) {
      switch (player.state) {
        case DEAD:
          break;

        case CHECKING:
          context.fillStyle = colorFor(player.color, true);
          break;

        case PLAYING:
        case READY:
          context.fillStyle = colorFor(player.color);
          break;

        default:
          throw 'Invalid state!';
      }

      if (player.state !== DEAD) {
        context.fillRect(
          player.position.x - player.halfSize,
          player.position.y - player.halfSize,
          2.0 * player.halfSize,
          2.0 * player.halfSize
        );

        if (player.overheadText) {
          context.save();
          context.translate(player.position.x, player.position.y);
          context.scale(0.1, -0.1);
          let width = context.measureText(player.overheadText).width;
          context.fillText(player.overheadText, -width / 2.0, -0.7);
          context.restore();
        }
      }

      context.save();
      context.fillStyle = colorFor(player.color);
      context.translate(player.position.x, -0.45);
      context.scale(INTERFACE_TEXT_SCALING, -INTERFACE_TEXT_SCALING);
      let width = context.measureText(player.currentScore).width;
      context.fillText(player.currentScore, -width / 2.0, 0.0);
      context.restore();

      context.save();
      context.fillStyle = colorFor(player.color);
      context.translate(-0.48, 0.45 - (index + 2) * 0.05);
      context.scale(INTERFACE_TEXT_SCALING, -INTERFACE_TEXT_SCALING);
      let text = player.name + ': ' + player.highScore;
      context.fillText(text, 0.0, 0.0);
      context.restore();
    });
  }

  renderParticles(particles) {
    var context = this.context;

    _.forEach(particles, function (particle) {
      context.fillStyle = colorFor(particle.color);
      context.fillRect(
          particle.x - particle.halfSize,
          particle.y - particle.halfSize,
          2.0 * particle.halfSize,
          2.0 * particle.halfSize
      );
    });
  }

  renderInterface(gameState) {
    let context = this.context;
    context.fillStyle = FOREGROUND_COLOR;

    context.save();
    context.translate(-0.45, -0.45);
    context.scale(INTERFACE_TEXT_SCALING, -INTERFACE_TEXT_SCALING);
    context.fillText('Score', 0.0, 0.0);
    context.restore();

    context.save();
    context.fillStyle = '#FFFFFF';
    context.translate(-0.48, 0.47);

    context.save();
    context.scale(INTERFACE_TEXT_SCALING, -INTERFACE_TEXT_SCALING);
    if (gameState.highestScore.name) {
      context.fillText('Champion: ' + gameState.highestScore.score + ' [' + gameState.highestScore.name + ']', 0.0, 0.0);
    } else {
      context.fillText('Champion: [to be claimed]', 0.0, 0.0);
    }
    context.restore();

    context.translate(0.0, -0.07);
    context.scale(INTERFACE_TEXT_SCALING, -INTERFACE_TEXT_SCALING);
    context.fillText('High Scores', 0.0, 0.0);
    context.restore();
  }
}
<commit_msg>use text align methods<commit_after>import { DEAD, CHECKING, READY, PLAYING } from './player.js';
import { KinectBodyRenderer } from './kinect-body-renderer.js';

const FOREGROUND_COLOR = '#FFFFFF';
const BACKGROUND_COLOR = '#111111';
const PIPE_COLOR = 'rgb(170, 168, 57)';
const COLORS = [
  [45, 136, 45],
  [57, 50, 118],
  [170, 145, 57],
  [170, 57, 57],
  [85, 43, 114],
  [38, 114, 87],
  [170, 94, 57]
];

const INTERFACE_TEXT_SCALING = 0.03;
const INTERFACE_FONT = "1px 'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace";

var colorFor = function (index, alpha) {
  'use strict';

  let color = COLORS[index];
  if (alpha) {
    return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',0.5)';
  } else {
    return 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
  }
};

export class Renderer {
    constructor(canvas, options) {
        this.canvas = canvas;
        this.context = canvas.getContext('2d');

        if (options.kinect) {
            this.kinectBodyRenderer = new KinectBodyRenderer(this.context, options.kinect);
        }
    }

    render(gameState) {
        var context = this.context;

        context.save();
        this.clear();

        context.font = INTERFACE_FONT;
        context.translate(0.5 * this.canvas.width, 0.575 * this.canvas.height);
        context.scale(this.canvas.width, -0.85*this.canvas.height);
        this.renderStars(gameState.stars);
        this.renderBoxes(gameState.boxes);
        this.renderPlayers(gameState.players);
        this.renderParticles(gameState.particles);
        this.renderInterface(gameState);
        context.restore();

        if (this.kinectBodyRenderer) {
            context.save();
            context.scale(1.0, 0.15);
            context.rect(0, 0, this.canvas.width, this.canvas.height);
            context.clip();
            this.kinectBodyRenderer.clear(this.canvas.width, this.canvas.height);
            this.kinectBodyRenderer.renderBodiesFromPlayers(gameState.players);
            context.restore();
        }
    }

    clear() {
        let context = this.context;

        context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        context.fillStyle = BACKGROUND_COLOR;
        context.fillRect(0, 0, this.canvas.width, this.canvas.height);
    }

    renderStars(stars) {
        var context = this.context;

        context.fillStyle = '#FFFFFF';
        _.forEach(stars, function (star) {
            let size = 0.15 * star.speed;
            context.fillRect(star.x - size/2, star.y - size/2, size, size);
            context.beginPath();
            context.arc(star.x, star.y, 0.3 * star.speed, 0, 2*Math.PI);
            context.fill();
        });
    }

    renderBoxes(boxes) {
        var context = this.context;

        _.forEach(boxes, function (box) {
            context.fillStyle = PIPE_COLOR;
            context.fillRect(
              box.position.x - box.halfWidth,
              box.position.y - box.halfHeight,
              box.halfWidth * 2,
              box.halfHeight * 2
            );
        });
    }

    renderPlayers(players) {
        var self = this,
            context = this.context;

        _.forEach(players, function (player, index) {
            switch (player.state) {
                case DEAD:
                    break;

                case CHECKING:
                    context.fillStyle = colorFor(player.color, true);
                    break;

                case PLAYING:
                case READY:
                    context.fillStyle = colorFor(player.color);
                    break;

                default:
                    throw 'Invalid state!';
            }

            if (player.state !== DEAD) {
                context.fillRect(
                  player.position.x - player.halfSize,
                  player.position.y - player.halfSize,
                  2.0 * player.halfSize,
                  2.0 * player.halfSize
                );

                if (player.overheadText) {
                    context.save();
                    context.translate(player.position.x, player.position.y);
                    context.scale(0.1, -0.1);
                    context.textAlign = 'center';
                    context.fillText(player.overheadText, 0.0, -0.7);
                    context.restore();
                }
            }

            context.save();
            context.fillStyle = colorFor(player.color);
            context.translate(player.position.x, -0.45);
            context.scale(INTERFACE_TEXT_SCALING / self.aspectRatio, -INTERFACE_TEXT_SCALING);
            context.textAlign = 'center';
            context.fillText(player.currentScore, 0.0, 0.0);
            context.restore();

            context.save();
            context.fillStyle = colorFor(player.color);
            context.translate(-0.48, 0.45 - (index + 2) * 0.05);
            context.scale(INTERFACE_TEXT_SCALING / self.aspectRatio, -INTERFACE_TEXT_SCALING);
            context.textAlign = 'left';
            let text = player.name + ': ' + player.highScore;
            context.fillText(text, 0.0, 0.0);
            context.restore();
        });
    }

    renderParticles(particles) {
        var context = this.context;

        _.forEach(particles, function (particle) {
            context.fillStyle = colorFor(particle.color);
            context.fillRect(
                particle.x - particle.halfSize,
                particle.y - particle.halfSize,
                2.0 * particle.halfSize,
                2.0 * particle.halfSize
            );
        });
    }

    renderInterface(gameState) {
        let context = this.context;
        context.fillStyle = FOREGROUND_COLOR;

        context.save();
        context.translate(-0.45, -0.45);
        context.scale(INTERFACE_TEXT_SCALING / this.aspectRatio, -INTERFACE_TEXT_SCALING);
        context.textAlign = 'left';
        context.fillText('Score', 0.0, 0.0);
        context.restore();

        context.save();
        context.fillStyle = '#FFFFFF';
        context.translate(-0.48, 0.47);

        context.save();
        context.scale(INTERFACE_TEXT_SCALING / this.aspectRatio, -INTERFACE_TEXT_SCALING);
        context.textAlign = 'left';
        if (gameState.highestScore.name) {
            context.fillText('Champion: ' + gameState.highestScore.score + ' [' + gameState.highestScore.name + ']', 0.0, 0.0);
        } else {
            context.fillText('Champion: [to be claimed]', 0.0, 0.0);
        }
        context.restore();

        context.translate(0.0, -0.07);
        context.scale(INTERFACE_TEXT_SCALING / this.aspectRatio, -INTERFACE_TEXT_SCALING);
        context.textAlign = 'left';
        context.fillText('High Scores', 0.0, 0.0);
        context.restore();
    }

    get aspectRatio() {
        return this.canvas.width / this.canvas.height;
    }
}
<|endoftext|>


<commit_before>/*
* Viry3D
* Copyright 2014-2018 by Stack - stackos@qq.com
*
* 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.
*/

let gl = null;
const Engine = {
    Init: null,
    Done: null,
    Update: null,
    events: new Array(),
    down: false,
};

function OnMouseDown(e) {
    const x = e.clientX - gl.canvas.offsetLeft;
    const y = e.clientY - gl.canvas.offsetTop;

    if (!Engine.down) {
        Engine.events.push({
            type: "MouseDown",
            x: x,
            y: y,
        });
        Engine.down = true;
    }
}

function OnMouseMove(e) {
    const x = e.clientX - gl.canvas.offsetLeft;
    const y = e.clientY - gl.canvas.offsetTop;

    if (Engine.down) {
        Engine.events.push({
            type: "MouseMove",
            x: x,
            y: y,
        });
    }
}

function OnMouseUp(e) {
    const x = e.clientX - gl.canvas.offsetLeft;
    const y = e.clientY - gl.canvas.offsetTop;

    if (Engine.down) {
        Engine.events.push({
            type: "MouseUp",
            x: x,
            y: y,
        });
        Engine.down = false;
    }
}

function IsMobilePlatform() {
    return /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent);
}

function Render() {
    const msg = {
        events: Engine.events,
    };

    Engine.Update(JSON.stringify(msg));

    // clear events
    Engine.events.splice(0, Engine.events.length);

    window.requestAnimationFrame(Render);
}

function Main() {
    Engine.Init = Module.cwrap("InitEngine", null, ["string"]);
    Engine.Done = Module.cwrap("DoneEngine", null, ["string"]);
    Engine.Update = Module.cwrap("UpdateEngine", null, ["string"]);

    let glesv3 = false;
    const canvas = Module.canvas;
    let context = GL.createContext(canvas, {
        majorVersion: 2,
        minorVersion: 0,
    })
    if (context == 0) {
        context = GL.createContext(canvas, {
            majorVersion: 1,
            minorVersion: 0,
        })
    } else {
        glesv3 = true;
    }
    GL.makeContextCurrent(context);
    gl = Module.ctx;

    const is_mobile = IsMobilePlatform();
    const has_touch = !!(('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch));

    console.log(navigator.userAgent);
    if (is_mobile) {
        console.log("Running on mobile platform");
    } else {
        console.log("Running on desktop platform");
    }
    console.log("Has touch " + has_touch);

    if (is_mobile || document.body.clientWidth < 1280) {
        canvas.width = document.body.clientWidth;
        canvas.height = canvas.width * 720 / 1280;
    } else {
        canvas.width = 1280;
        canvas.height = 720;
    }

    if (has_touch) {
        canvas.addEventListener("touchstart", OnMouseDown, false);
        canvas.addEventListener("touchmove", OnMouseMove, false);
        canvas.addEventListener("touchend", OnMouseUp, false);
    } else {
        canvas.addEventListener("mousedown", OnMouseDown, false);
        canvas.addEventListener("mousemove", OnMouseMove, false);
        canvas.addEventListener("mouseup", OnMouseUp, false);
    }

    const canvas_width = canvas.width;
    const canvas_height = canvas.height;

    const msg = {
        name: "Viry3D",
        width: canvas_width,
        height: canvas_height,
        glesv3: glesv3,
    };

    Engine.Init(JSON.stringify(msg));

    Render();
}

var Module = {
    preRun: [],
    postRun: function () {
        Main();
    },
    print: (function () {
        return function (text) {
            if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
            console.log(text);
        };
    })(),
    printErr: function (text) {
        if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
        if (0) { // XXX disabled for safety typeof dump == 'function') {
            dump(text + '\n'); // fast, straight to the real console
        } else {
            console.error(text);
        }
    },
    canvas: (function () {
        var canvas = document.getElementById("canvas");

        // As a default initial behavior, pop up an alert when webgl context is lost. To make your
        // application robust, you may want to override this behavior before shipping!
        // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
        canvas.addEventListener("webglcontextlost", function (e) {
            alert("WebGL context lost. You will need to reload the page.");
            e.preventDefault();
        }, false);

        return canvas;
    })()
};

window.onerror = function (event) {
    Module.setStatus = function (text) {
        if (text) Module.printErr("[post-exception status] " + text);
    };
};
<commit_msg>wasm add touch.<commit_after>/*
* Viry3D
* Copyright 2014-2018 by Stack - stackos@qq.com
*
* 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.
*/

let gl = null;
const Engine = {
    Init: null,
    Done: null,
    Update: null,
    events: new Array(),
    down: false,
};

function OnMouseDown(e) {
    const x = e.clientX - gl.canvas.offsetLeft;
    const y = e.clientY - gl.canvas.offsetTop;

    if (!Engine.down) {
        Engine.events.push({
            type: "MouseDown",
            x: x,
            y: y,
        });
        Engine.down = true;
    }
}

function OnMouseMove(e) {
    const x = e.clientX - gl.canvas.offsetLeft;
    const y = e.clientY - gl.canvas.offsetTop;

    if (Engine.down) {
        Engine.events.push({
            type: "MouseMove",
            x: x,
            y: y,
        });
    }
}

function OnMouseUp(e) {
    const x = e.clientX - gl.canvas.offsetLeft;
    const y = e.clientY - gl.canvas.offsetTop;

    if (Engine.down) {
        Engine.events.push({
            type: "MouseUp",
            x: x,
            y: y,
        });
        Engine.down = false;
    }
}

const Platform = {
    Android: 0,
    iOS: 1,
    Other: 2,
};

function GetPlatform() {
    const agent = navigator.userAgent;
    if (agent.indexOf("Android") >= 0) {
        return Platform.Android;
    } else if (agent.indexOf("iPhone") >= 0 || agent.indexOf("iPad") >= 0 || agent.indexOf("iPod") >= 0) {
        return Platform.iOS;
    } else {
        return Platform.Other;
    }
}

function Render() {
    const msg = {
        events: Engine.events,
    };

    Engine.Update(JSON.stringify(msg));

    // clear events
    Engine.events.splice(0, Engine.events.length);

    window.requestAnimationFrame(Render);
}

function Main() {
    Engine.Init = Module.cwrap("InitEngine", null, ["string"]);
    Engine.Done = Module.cwrap("DoneEngine", null, ["string"]);
    Engine.Update = Module.cwrap("UpdateEngine", null, ["string"]);

    let glesv3 = false;
    const canvas = Module.canvas;
    let context = GL.createContext(canvas, {
        majorVersion: 2,
        minorVersion: 0,
    })
    if (context == 0) {
        context = GL.createContext(canvas, {
            majorVersion: 1,
            minorVersion: 0,
        })
    } else {
        glesv3 = true;
    }
    GL.makeContextCurrent(context);
    gl = Module.ctx;

    const platform = GetPlatform();
    const has_touch = !!(('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch));

    console.log(navigator.userAgent);
    if (platform == Platform.Android) {
        console.log("Running on Android platform");
    } else if (platform == Platform.iOS) {
        console.log("Running on iOS platform");
    } else {
        console.log("Running on desktop platform");
    }
    console.log("Has touch " + has_touch);

    if (platform == Platform.Android || platform == Platform.iOS || document.body.clientWidth < 1280) {
        canvas.width = document.body.clientWidth;
        canvas.height = canvas.width * 720 / 1280;
    } else {
        canvas.width = 1280;
        canvas.height = 720;
    }

    if (has_touch) {
        canvas.addEventListener("touchstart", function(e) {
            e.preventDefault();
            const touches = e.changedTouches;
            if (touches.length > 0) {
                OnMouseDown(touches[0]);
            }
        });
        canvas.addEventListener("touchmove", function(e) {
            e.preventDefault();
            const touches = e.changedTouches;
            if (touches.length > 0) {
                OnMouseMove(touches[0]);
            }
        });
        canvas.addEventListener("touchend", function(e) {
            e.preventDefault();
            const touches = e.changedTouches;
            if (touches.length > 0) {
                OnMouseUp(touches[0]);
            }
        });
        canvas.addEventListener("touchcancel", function(e) {
            e.preventDefault();
            const touches = e.changedTouches;
            if (touches.length > 0) {
                OnMouseUp(touches[0]);
            }
        });
    } else {
        canvas.addEventListener("mousedown", OnMouseDown, false);
        canvas.addEventListener("mousemove", OnMouseMove, false);
        canvas.addEventListener("mouseup", OnMouseUp, false);
    }

    const canvas_width = canvas.width;
    const canvas_height = canvas.height;

    const msg = {
        name: "Viry3D",
        width: canvas_width,
        height: canvas_height,
        glesv3: glesv3,
    };

    Engine.Init(JSON.stringify(msg));

    Render();
}

var Module = {
    preRun: [],
    postRun: function () {
        Main();
    },
    print: (function () {
        return function (text) {
            if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
            console.log(text);
        };
    })(),
    printErr: function (text) {
        if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
        if (0) { // XXX disabled for safety typeof dump == 'function') {
            dump(text + '\n'); // fast, straight to the real console
        } else {
            console.error(text);
        }
    },
    canvas: (function () {
        var canvas = document.getElementById("canvas");

        // As a default initial behavior, pop up an alert when webgl context is lost. To make your
        // application robust, you may want to override this behavior before shipping!
        // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
        canvas.addEventListener("webglcontextlost", function (e) {
            alert("WebGL context lost. You will need to reload the page.");
            e.preventDefault();
        }, false);

        return canvas;
    })()
};

window.onerror = function (event) {
    Module.setStatus = function (text) {
        if (text) Module.printErr("[post-exception status] " + text);
    };
};
<|endoftext|>


<commit_before>var niclabs = niclabs || {};

/**
 * Insight is a generic web dashboard for smart city projects.
 *
 * It allows to combine different chart and visualization tools to better
 * understand what is going on in the city
 *
 * @namespace
 * @requires jQuery 1.11.1+
 */
niclabs.insight = (function($) {
    "use strict";

    /**
     * Initial required configurations
     */

    /**
     * JQuery plugin to make an element resizable
     * TODO: missing documentation/source
     */
    $.fn.resizable = function(orientation) {
        var resizer = $('<div>').addClass('resizer').addClass(orientation + '-resize');
        this.append(resizer).addClass('resizable');

        resizer.on('mousedown', initDrag);

        var startX, startY, startWidth, startHeight;

        var resizable = this;

        function initDrag(e) {
            startX = e.clientX;
            startY = e.clientY;
            startWidth = resizable.outerWidth();
            startHeight = resizable.outerHeight();

            $(document).on('mousemove', doDrag);
            $(document).on('mouseup', stopDrag);
        }

        var east, south, north, west;
        south = orientation.search("s") >= 0;
        east = orientation.search("e") >= 0;
        north = orientation.search("n") >= 0;
        west = orientation.search("w") >= 0;

        function doDrag(e) {
            if (south)
                resizable.css('height', (startHeight + e.clientY - startY) + 'px');
            if (east)
                resizable.css('width', (startWidth + e.clientX - startX) + 'px');
            if (north)
                resizable.css('top', (e.clientY) + 'px')
                .css('height', (startHeight + startY - e.clientY) + 'px');
            if (west)
                resizable.css('left', (e.clientX) + 'px')
                .css('width', (startWidth - e.clientX) + 'px');
        }

        function stopDrag(e) {
            $(document).off('mousemove', doDrag);
            $(document).off('mouseup', stopDrag);
            resizable.trigger('resize');
        }

        this.scroll(function(e) {
            resizer.css('top', resizable.scrollTop());
        });

        return this;
    };

    /**
     * Set the id for the jQuery selector
     */
    $.fn.setID = function(selector) {
        if (selector.charAt(0) === '#')
            selector = selector.slice(1);
        this.attr('id', selector);
        return this;
    };

    /**
     * JQuery plugin to make an element movable
     * TODO: missing documentation/source
     */
    $.fn.movable = function() {

        var panel = this.children('.options-panel');
        if (!panel.length) {
            panel = $('<span>').addClass('options-panel');
            this.prepend(panel);
        }

        var up = $('<span>').addClass('up-button').append('▲');
        var down = $('<span>').addClass('down-button').append('▼');
        panel.prepend(down);
        panel.prepend(up);

        var _this = this;

        up.on('click', function() {

            _this.insertBefore(_this.prev());

        });

        down.on('click', function() {

            _this.insertAfter(_this.next());

        });

        return this;
    };

    /**
     * JQuery plugin to make an element closeable
     * TODO: Missing documentation
     */
    $.fn.closable = function(handler) {
        if (!handler) {
            handler = function() {
                return;
            };
        }

        var panel = this.children('.options-panel');
        if (!panel.length) {
            panel = $('<span>').addClass('options-panel');
            this.prepend(panel);
        }

        var close = $('<span>').addClass('close-button').text('X');

        panel.append(close);

        var _this = this;

        close.on('click', function() {
            _this.remove();
            handler();
        });

        return this;
    };

    /**
     * Check if indexOf exists in Array.prototype or use jQuery.inArray();
     */
     Array.prototype.indexOf = 'indexOf' in Array.prototype ? Array.prototype.indexOf : function(item, start) {
         return $.inArray(item, this, start);
     };

     var dashboard;
     var map;
     var info;

     var handlers = {};

     /**
      * Constructs an insight element (visualization, layer, etc.)
      *
      * @callback niclabs.insight~handler
      * @param {Object} options - configuration options for the handler, dependent on the type
      */

     return {
         /**
          * Register a handler of a specific insight element ('layer', 'visualization', etc.)
          * to manage the creation, rendering of a specific part of the UI.
          *
          * Third-party extensions to the insight need only to register their visualization
          * elements with this function for the dashboard UI to correctly recognize them
          * TODO: improve this
          *
          * @memberof niclabs.insight
          * @param {string} name - name for the handler to return, register
          * @param {string=} type - type for the handler
          * @param {insight~handler=} callback - function to create the element
          * @returns {insight~handler} handler for the registered name
          */
         handler: function(name, type, callback) {
             if (name in handlers) {
                 type = type === 'undefined' ? handlers[name].type : type;
                 callback = callback === 'undefined' ? handlers[name].callback : callback;

                 if (type !== handlers[name].type) {
                     throw new Error('There already exists a handler with name '+name+' for type '+type);
                 }
             }
             else if (type === 'undefined' && callback === 'undefined') {
                 throw new Error('Handler ' + name + ' does not exist');
             }

             handlers[name] = {'type': type, 'callback': callback};
             return callback;
         },

         /**
          * Construct and configure a {@link niclabs.insight.Dashboard}
          *
          * @memberof niclabs.insight
          * @param {Object} options - list of configuration options for the dashboard see {@link niclabs.insight.Dashboard}
          * @returns {niclabs.insight.Dashboard} dashboard object
          */
         init: function(options) {
             dashboard = niclabs.insight.Dashboard(options);
             return dashboard;
         },
     };
})(jQuery);
<commit_msg>Minor changes to handler method for clarity<commit_after>var niclabs = niclabs || {};

/**
 * Insight is a generic web dashboard for smart city projects.
 *
 * It allows to combine different chart and visualization tools to better
 * understand what is going on in the city
 *
 * @namespace
 * @requires jQuery 1.11.1+
 */
niclabs.insight = (function($) {
    "use strict";

    /**
     * Initial required configurations
     */

    /**
     * JQuery plugin to make an element resizable
     * TODO: missing documentation/source
     */
    $.fn.resizable = function(orientation) {
        var resizer = $('<div>').addClass('resizer').addClass(orientation + '-resize');
        this.append(resizer).addClass('resizable');

        resizer.on('mousedown', initDrag);

        var startX, startY, startWidth, startHeight;

        var resizable = this;

        function initDrag(e) {
            startX = e.clientX;
            startY = e.clientY;
            startWidth = resizable.outerWidth();
            startHeight = resizable.outerHeight();

            $(document).on('mousemove', doDrag);
            $(document).on('mouseup', stopDrag);
        }

        var east, south, north, west;
        south = orientation.search("s") >= 0;
        east = orientation.search("e") >= 0;
        north = orientation.search("n") >= 0;
        west = orientation.search("w") >= 0;

        function doDrag(e) {
            if (south)
                resizable.css('height', (startHeight + e.clientY - startY) + 'px');
            if (east)
                resizable.css('width', (startWidth + e.clientX - startX) + 'px');
            if (north)
                resizable.css('top', (e.clientY) + 'px')
                .css('height', (startHeight + startY - e.clientY) + 'px');
            if (west)
                resizable.css('left', (e.clientX) + 'px')
                .css('width', (startWidth - e.clientX) + 'px');
        }

        function stopDrag(e) {
            $(document).off('mousemove', doDrag);
            $(document).off('mouseup', stopDrag);
            resizable.trigger('resize');
        }

        this.scroll(function(e) {
            resizer.css('top', resizable.scrollTop());
        });

        return this;
    };

    /**
     * Set the id for the jQuery selector
     */
    $.fn.setID = function(selector) {
        if (selector.charAt(0) === '#')
            selector = selector.slice(1);
        this.attr('id', selector);
        return this;
    };

    /**
     * JQuery plugin to make an element movable
     * TODO: missing documentation/source
     */
    $.fn.movable = function() {

        var panel = this.children('.options-panel');
        if (!panel.length) {
            panel = $('<span>').addClass('options-panel');
            this.prepend(panel);
        }

        var up = $('<span>').addClass('up-button').append('▲');
        var down = $('<span>').addClass('down-button').append('▼');
        panel.prepend(down);
        panel.prepend(up);

        var _this = this;

        up.on('click', function() {

            _this.insertBefore(_this.prev());

        });

        down.on('click', function() {

            _this.insertAfter(_this.next());

        });

        return this;
    };

    /**
     * JQuery plugin to make an element closeable
     * TODO: Missing documentation
     */
    $.fn.closable = function(handler) {
        if (!handler) {
            handler = function() {
                return;
            };
        }

        var panel = this.children('.options-panel');
        if (!panel.length) {
            panel = $('<span>').addClass('options-panel');
            this.prepend(panel);
        }

        var close = $('<span>').addClass('close-button').text('X');

        panel.append(close);

        var _this = this;

        close.on('click', function() {
            _this.remove();
            handler();
        });

        return this;
    };

    /**
     * Check if indexOf exists in Array.prototype or use jQuery.inArray();
     */
     Array.prototype.indexOf = 'indexOf' in Array.prototype ? Array.prototype.indexOf : function(item, start) {
         return $.inArray(item, this, start);
     };

     var dashboard;
     var map;
     var info;

     var handlers = {};

     /**
      * Constructs an insight element (visualization, layer, etc.)
      *
      * @callback niclabs.insight~handler
      * @param {niclabs.insight.Dashboard} dashboard to assign to the handler
      * @param {Object} options - configuration options for the handler, depending on the kind
      */

     return {
         /**
          * Register a handler of a specific insight element ('layer', 'visualization', etc.)
          * to manage the creation, rendering of a specific part of the UI.
          *
          * Third-party extensions to the insight need only to register their visualization
          * elements with this function for the dashboard UI to correctly recognize them
          * TODO: improve this
          *
          * @memberof niclabs.insight
          * @param {string} name - name for the handler to return, register
          * @param {string=} kind - kind for the handler
          * @param {niclabs.insight~handler=} handler - callback to create the element
          * @returns {niclabs.insight~handler} handler for the registered name
          */
         handler: function(name, kind, handler) {
             if (name in handlers) {
                 kind = kind === 'undefined' ? handlers[name].kind : kind;
                 handler = handler === 'undefined' ? handlers[name].handler : handler;

                 if (kind !== handlers[name].kind) {
                     throw new Error('There already exists a handler with name '+name+' for kind '+kind);
                 }
             }
             else if (kind === 'undefined' && handler === 'undefined') {
                 throw new Error('Handler ' + name + ' does not exist');
             }

             handlers[name] = {'kind': kind, 'handler': handler};
             return handler;
         },

         /**
          * Construct and configure a {@link niclabs.insight.Dashboard}
          *
          * @memberof niclabs.insight
          * @param {Object} options - list of configuration options for the dashboard see {@link niclabs.insight.Dashboard}
          * @returns {niclabs.insight.Dashboard} dashboard object
          */
         init: function(options) {
             dashboard = niclabs.insight.Dashboard(options);
             return dashboard;
         },
     };
})(jQuery);
<|endoftext|>