<commit_before>'use strict';

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

goog.provide('tachyfont');
goog.provide('tachyfont.Error');
goog.provide('tachyfont.TachyFont');

goog.require('goog.Promise');
goog.require('goog.Uri');
goog.require('goog.debug.Logger');
goog.require('goog.log');
goog.require('goog.log.Level');
/** @suppress {extraRequire} */
goog.require('tachyfont.FontsInfo');
goog.require('tachyfont.IncrementalFont');
goog.require('tachyfont.Logger');
goog.require('tachyfont.MetadataDefines');
goog.require('tachyfont.Persist');
goog.require('tachyfont.Reporter');
goog.require('tachyfont.TachyFontSet');
goog.require('tachyfont.utils');



/**
 * TachyFont - A namespace.
 * @param {!tachyfont.FontInfo} fontInfo The font info.
 * @param {boolean} dropData If true then drop the persistent store data.
 * @param {!Object=} opt_params Optional parameters.
 * @constructor
 */
tachyfont.TachyFont = function(fontInfo, dropData, opt_params) {
  var params = opt_params || {};

  /**
   * The object that handles the binary manipulation of the font data.
   *
   * TODO(bstell): integrate the manager into this object.
   */
  this.incrfont = tachyfont.IncrementalFont.createManager(fontInfo, dropData,
      params);
};


/**
 * Lazily load the data for these chars.;
 */
tachyfont.TachyFont.prototype.loadNeededChars = function() {
  this.incrfont.loadChars();
};


/**
 * The persistence 'stable' time.
 * If the data has been in persistent store longer than this then the data is
 * considered to be stable; ie: not being automatically cleared. The time is in
 * milliseconds.
 * @type {number}
 */
tachyfont.TachyFont.GLOBAL_STABLE_DATA_TIME = 24 * 60 * 60 * 1000;


/**
 * Enum for error values.
 * @enum {string}
 */
tachyfont.Error = {
  FILE_ID: 'ETF',
  WINDOW_ON_ERROR: '01',  // '01' is deprecated.
  SET_FONT: '02',
  GET_BASE: '03',
  MISSING_FEATURE: '04',
  KNOWN_WINDOW_ON_ERROR: '05',
  UNKNOWN_WINDOW_ON_ERROR: '06',
  NOT_ENOUGH_STORAGE: '07',
  STORAGE_INFORMATION_FUNCTION: '08',
  GET_STORAGE_INFORMATION: '09',
  NO_PRELUDE_REPORTS: '10',
  PRELUDE_REPORT_TYPE: '11',
  BELOW_GLOBAL_STABLE_TIME: '12',
  OPEN_GLOBAL_DATABASE: '13',
  NO_INDEXED_DB: '14',
  NO_MUTATION_OBSERVER: '15',
  NO_FONT_LOADER: '16',
  PAGE_LOADED: '17',
  END: '00'
};


/**
 * The error reporter for this file.
 *
 * @param {string} errNum The error number (encoded in a string);
 * @param {*} errInfo The error object;
 * @private
 */
tachyfont.reportError_ = function(errNum, errInfo) {
  if (tachyfont.Reporter.isReady()) {
    tachyfont.Reporter.reportError(tachyfont.Error.FILE_ID + errNum, '000',
        errInfo);
  } else {
    var obj = {};
    obj.errNum = errNum;
    obj.errInfo = errInfo;
    setTimeout(function() {
      tachyfont.delayedReportError_(obj);
    }.bind(obj), 1000);
  }
};


/**
 * Re-run the error report.
 *
 * @param {!Object} obj An object holding the parameters for the error report.
 * @private
 */
tachyfont.delayedReportError_ = function(obj) {
  goog.log.error(tachyfont.Logger.logger, 'delayedReportError_');
  tachyfont.reportError_(obj.errNum, obj.errInfo);
};


if (window.addEventListener) {
  /**
   * Report any uncaught errors.
   *
   * @param {!Event} error The error information.
   * @private
   */
  tachyfont.windowOnError_ = function(error) {
    if (!error['filename']) {
      // The information is stripped from the report because of CORS issues.
      tachyfont.reportError_(tachyfont.Error.UNKNOWN_WINDOW_ON_ERROR, '');
      return;
    }
    var errorObj = {};
    errorObj['message'] = error['message'];
    errorObj['filename'] = error['filename'];
    errorObj['lineno'] = error['lineno'];
    errorObj['colno'] = error['colno'];
    if (error.error) {
      errorObj['stack'] = error['error']['stack'].substring(0, 1000);
    }
    var errorStr = JSON.stringify(errorObj);
    tachyfont.reportError_(tachyfont.Error.KNOWN_WINDOW_ON_ERROR, errorStr);
    tachyfont.reportError_(tachyfont.Error.WINDOW_ON_ERROR, errorStr);
  };
  window.addEventListener('error', tachyfont.windowOnError_, false);
}

if (goog.DEBUG) {
  /**
   * A class variable to limit debug initialization to a single time.
   * @private {boolean}
   */
  tachyfont.hasInitializedDebug_ = false;

  /**
   * A function to initialize the debug setup.
   *
   * @private
   */
  tachyfont.debugInitialization_ = function() {
    if (tachyfont.hasInitializedDebug_) {
      return;
    }

    tachyfont.hasInitializedDebug_ = true;

    var uri = goog.Uri.parse(window.location.href);
    var debugLevel;
    var debugLevelStr =
        uri.getParameterValue('TachyFontDebugLevel') || 'WARNING';
    debugLevel = goog.debug.Logger.Level.getPredefinedLevel(debugLevelStr);
    tachyfont.Logger.init(debugLevel);

    /**
     * For debugging: option to disable the obfuscation.
     *
     * Obfuscation is a security feature. If a page was presenting a short
     * security key it is possible that a TachyFont server could figure out the
     * security key from the character request. Obfuscation adds random
     * characters to small character data requests to make this difficult.
     *
     * For debugging this obfuscation adds noise to the characters requests.
     */
    var noObfuscateStr = uri.getParameterValue('TachyFontNoObfuscate') || '';
    tachyfont.utils.noObfuscate = noObfuscateStr.toLowerCase() == 'true';

    /**
     * Enable checking cmap against fileInfo and charList.
     */
    var checkCmapStr = uri.getParameterValue('TachyFontCheckCmap') || '';
    /** @type {boolean} */
    tachyfont.checkCmap = checkCmapStr.toLowerCase() == 'true';
  };
}


/**
 * Enum for logging values.
 * @enum {string}
 * @private
 */
tachyfont.Log_ = {
  LOAD_FONTS: 'LTFLF.',
  LOAD_FONTS_WAIT_PREVIOUS: 'LTFLW.',
  END: ''
};


/**
 * Load a list of TachyFonts
 * @param {string} familyName The font-family name.
 * @param {!tachyfont.FontsInfo} fontsInfo Information about the fonts.
 * @param {!Object<string, string>=} opt_params Optional parameters.
 * @return {!goog.Promise<?tachyfont.TachyFontSet,?>} A promise that returns the
 *     TachyFontSet object or null if the fonts are not loaded.
 */
tachyfont.loadFonts = function(familyName, fontsInfo, opt_params) {
  if (goog.DEBUG) {
    tachyfont.debugInitialization_();
  }
  tachyfont.loadFonts_initReporter(fontsInfo);
  // Sent an "errro" report so the number of page loads can be determined on the
  // dashboard.
  tachyfont.reportError_(tachyfont.Error.PAGE_LOADED, '');
  tachyfont.sendPreludeReports();
  tachyfont.loadFonts_initFontInfosUrls(fontsInfo);
  return tachyfont.checkSystem()
      .then(function() {
        // Check how much can be stored.
        var fontInfos = fontsInfo.getPrioritySortedFonts();
        return tachyfont.manageStorageUsage(fontInfos);
      })
      .then(function() {
        // Initialize the objects.
        var tachyFontSet =
            tachyfont.loadFonts_init_(familyName, fontsInfo, opt_params);
        // Load the fonts.
        tachyfont.loadFonts_loadAndUse_(tachyFontSet);

        // Run this in parallel with loading the fonts.
        tachyfont.loadFonts_setupTextListeners_(tachyFontSet);

        return tachyFontSet;
      })
      .thenCatch(function() {
        // Catch any errors.
        return null;
      });
};


/**
 * Checks that the system can use TachyFont.
 * @return {!goog.Promise<?,?>}
 */
tachyfont.checkSystem = function() {
  // TODO(bstell): initialize tachyfont.Reporter here so the errors in
  // isSupportedBrowser can be reported.
  // Check if this browser has the necessary features to run TachyFont.
  if (!tachyfont.isSupportedBrowser()) {
    return goog.Promise.reject('unsupported browser');
  }

  // Check for TachyFont metadata.
  return tachyfont.Persist.openGlobalDatabase().then(<commit_msg>Add a URL parameter to enable Compact TachyFont.<commit_after>'use strict';

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

goog.provide('tachyfont');
goog.provide('tachyfont.Error');
goog.provide('tachyfont.TachyFont');

goog.require('goog.Promise');
goog.require('goog.Uri');
goog.require('goog.debug.Logger');
goog.require('goog.log');
goog.require('goog.log.Level');
/** @suppress {extraRequire} */
goog.require('tachyfont.FontsInfo');
goog.require('tachyfont.IncrementalFont');
goog.require('tachyfont.Logger');
goog.require('tachyfont.MetadataDefines');
goog.require('tachyfont.Persist');
goog.require('tachyfont.Reporter');
goog.require('tachyfont.TachyFontSet');
goog.require('tachyfont.utils');



/**
 * TachyFont - A namespace.
 * @param {!tachyfont.FontInfo} fontInfo The font info.
 * @param {boolean} dropData If true then drop the persistent store data.
 * @param {!Object=} opt_params Optional parameters.
 * @constructor
 */
tachyfont.TachyFont = function(fontInfo, dropData, opt_params) {
  var params = opt_params || {};

  /**
   * The object that handles the binary manipulation of the font data.
   *
   * TODO(bstell): integrate the manager into this object.
   */
  this.incrfont = tachyfont.IncrementalFont.createManager(fontInfo, dropData,
      params);
};


/**
 * Lazily load the data for these chars.;
 */
tachyfont.TachyFont.prototype.loadNeededChars = function() {
  this.incrfont.loadChars();
};


/**
 * The persistence 'stable' time.
 * If the data has been in persistent store longer than this then the data is
 * considered to be stable; ie: not being automatically cleared. The time is in
 * milliseconds.
 * @type {number}
 */
tachyfont.TachyFont.GLOBAL_STABLE_DATA_TIME = 24 * 60 * 60 * 1000;


/**
 * Enum for error values.
 * @enum {string}
 */
tachyfont.Error = {
  FILE_ID: 'ETF',
  WINDOW_ON_ERROR: '01',  // '01' is deprecated.
  SET_FONT: '02',
  GET_BASE: '03',
  MISSING_FEATURE: '04',
  KNOWN_WINDOW_ON_ERROR: '05',
  UNKNOWN_WINDOW_ON_ERROR: '06',
  NOT_ENOUGH_STORAGE: '07',
  STORAGE_INFORMATION_FUNCTION: '08',
  GET_STORAGE_INFORMATION: '09',
  NO_PRELUDE_REPORTS: '10',
  PRELUDE_REPORT_TYPE: '11',
  BELOW_GLOBAL_STABLE_TIME: '12',
  OPEN_GLOBAL_DATABASE: '13',
  NO_INDEXED_DB: '14',
  NO_MUTATION_OBSERVER: '15',
  NO_FONT_LOADER: '16',
  PAGE_LOADED: '17',
  END: '00'
};


/**
 * The error reporter for this file.
 *
 * @param {string} errNum The error number (encoded in a string);
 * @param {*} errInfo The error object;
 * @private
 */
tachyfont.reportError_ = function(errNum, errInfo) {
  if (tachyfont.Reporter.isReady()) {
    tachyfont.Reporter.reportError(tachyfont.Error.FILE_ID + errNum, '000',
        errInfo);
  } else {
    var obj = {};
    obj.errNum = errNum;
    obj.errInfo = errInfo;
    setTimeout(function() {
      tachyfont.delayedReportError_(obj);
    }.bind(obj), 1000);
  }
};


/**
 * Re-run the error report.
 *
 * @param {!Object} obj An object holding the parameters for the error report.
 * @private
 */
tachyfont.delayedReportError_ = function(obj) {
  goog.log.error(tachyfont.Logger.logger, 'delayedReportError_');
  tachyfont.reportError_(obj.errNum, obj.errInfo);
};


if (window.addEventListener) {
  /**
   * Report any uncaught errors.
   *
   * @param {!Event} error The error information.
   * @private
   */
  tachyfont.windowOnError_ = function(error) {
    if (!error['filename']) {
      // The information is stripped from the report because of CORS issues.
      tachyfont.reportError_(tachyfont.Error.UNKNOWN_WINDOW_ON_ERROR, '');
      return;
    }
    var errorObj = {};
    errorObj['message'] = error['message'];
    errorObj['filename'] = error['filename'];
    errorObj['lineno'] = error['lineno'];
    errorObj['colno'] = error['colno'];
    if (error.error) {
      errorObj['stack'] = error['error']['stack'].substring(0, 1000);
    }
    var errorStr = JSON.stringify(errorObj);
    tachyfont.reportError_(tachyfont.Error.KNOWN_WINDOW_ON_ERROR, errorStr);
    tachyfont.reportError_(tachyfont.Error.WINDOW_ON_ERROR, errorStr);
  };
  window.addEventListener('error', tachyfont.windowOnError_, false);
}

if (goog.DEBUG) {
  /**
   * A class variable to limit debug initialization to a single time.
   * @private {boolean}
   */
  tachyfont.hasInitializedDebug_ = false;

  /**
   * A function to initialize the debug setup.
   *
   * @private
   */
  tachyfont.debugInitialization_ = function() {
    if (tachyfont.hasInitializedDebug_) {
      return;
    }

    tachyfont.hasInitializedDebug_ = true;

    var uri = goog.Uri.parse(window.location.href);
    var debugLevel;
    var debugLevelStr =
        uri.getParameterValue('TachyFontDebugLevel') || 'WARNING';
    debugLevel = goog.debug.Logger.Level.getPredefinedLevel(debugLevelStr);
    tachyfont.Logger.init(debugLevel);

    /**
     * Enable Compact TachyFont.
     */
    var compactTachyFontStr = uri.getParameterValue('CompactTachyFont') || '';
    /** @type {boolean} */
    tachyfont.compactTachyFont = compactTachyFontStr.toLowerCase() == 'true';

    /**
     * For debugging: option to disable the obfuscation.
     *
     * Obfuscation is a security feature. If a page was presenting a short
     * security key it is possible that a TachyFont server could figure out the
     * security key from the character request. Obfuscation adds random
     * characters to small character data requests to make this difficult.
     *
     * For debugging this obfuscation adds noise to the characters requests.
     */
    var noObfuscateStr = uri.getParameterValue('TachyFontNoObfuscate') || '';
    tachyfont.utils.noObfuscate = noObfuscateStr.toLowerCase() == 'true';

    /**
     * Enable checking cmap against fileInfo and charList.
     */
    var checkCmapStr = uri.getParameterValue('TachyFontCheckCmap') || '';
    /** @type {boolean} */
    tachyfont.checkCmap = checkCmapStr.toLowerCase() == 'true';
  };
}


/**
 * Enum for logging values.
 * @enum {string}
 * @private
 */
tachyfont.Log_ = {
  LOAD_FONTS: 'LTFLF.',
  LOAD_FONTS_WAIT_PREVIOUS: 'LTFLW.',
  END: ''
};


/**
 * Load a list of TachyFonts
 * @param {string} familyName The font-family name.
 * @param {!tachyfont.FontsInfo} fontsInfo Information about the fonts.
 * @param {!Object<string, string>=} opt_params Optional parameters.
 * @return {!goog.Promise<?tachyfont.TachyFontSet,?>} A promise that returns the
 *     TachyFontSet object or null if the fonts are not loaded.
 */
tachyfont.loadFonts = function(familyName, fontsInfo, opt_params) {
  if (goog.DEBUG) {
    tachyfont.debugInitialization_();
  }
  tachyfont.loadFonts_initReporter(fontsInfo);
  // Sent an "errro" report so the number of page loads can be determined on the
  // dashboard.
  tachyfont.reportError_(tachyfont.Error.PAGE_LOADED, '');
  tachyfont.sendPreludeReports();
  tachyfont.loadFonts_initFontInfosUrls(fontsInfo);
  return tachyfont.checkSystem()
      .then(function() {
        // Check how much can be stored.
        var fontInfos = fontsInfo.getPrioritySortedFonts();
        return tachyfont.manageStorageUsage(fontInfos);
      })
      .then(function() {
        // Initialize the objects.
        var tachyFontSet =
            tachyfont.loadFonts_init_(familyName, fontsInfo, opt_params);
        // Load the fonts.
        tachyfont.loadFonts_loadAndUse_(tachyFontSet);

        // Run this in parallel with loading the fonts.
        tachyfont.loadFonts_setupTextListeners_(tachyFontSet);

        return tachyFontSet;
      })
      .thenCatch(function() {
        // Catch any errors.
        return null;
      });
};


/**
 * Checks that the system can use TachyFont.
 * @return {!goog.Promise<?,?>}
 */
tachyfont.checkSystem = function() {
  // Check if this browser has the necessary features to run TachyFont.
  if (!tachyfont.isSupportedBrowser()) {
    return goog.Promise.reject('unsupported browser');
  }

  // Check for TachyFont metadata.
  return tachyfont.Persist.openGlobalDatabase().then(
{'fraction_non_alphanumeric': 0.12540591604180198, 'fraction_numerical': 0.00802975733600992, 'mean_word_length': 3.6545754328112117, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5007636', 'n_tokens_mistral': 5756, 'n_tokens_neox': 5339, 'n_words': 1355}