<commit_before>/*
 * Copyright 2010 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.
 */

addScriptToInject(function() {

window.chrome_comp = (function() {
  var targetPageURL_ = window.location;
  // >=0 if hook is enabled.
  var hookDisabledCount_ = 0;

  var messageCache_ = {};

  var BLOCK_DISPLAY_VALUES = {
    block: true,
    'inline-block': true,
    'list-item': true,
    table: true,
    'inline-table': true,
    'table-cell': true,
    'table-caption': true
  };

  return {

    COLOR_TRANSPARENT: 'rgba(0, 0, 0, 0)',

    SPECIFIED_VALUE: 'chrome_comp_specified_value',

    WHITESPACE: /[ \t\r\n]/,
    LEADING_WHITESPACES: /^[ \t\r\n]+/,
    TRAILING_WHITESPACES: /[ \t\r\n]+$/,

    // cache Node reference
    Node: window.Node,

    enableHooks: function(enable) {
      hookDisabledCount_ += (enable ? 1 : -1);
    },

    areHooksDisabled: function() {
      return hookDisabledCount_ < 0;
    },

    // Uses it to prompt debug message.
    trace: function(msg) {
      if (chrome_comp.CompDetectorConfig.canTraceBug) {
        console.log(new Date().getTime() + ' $chrome_comp for : ' +
            chrome_comp.getTargetPageURL() + '$');
        console.log(msg);
      }
    },

    // Uses it to implement inherit logic in JavaScript
    extend: function(subClass, superClass) {
      // Use prototype chain to inherit baseClass's method.
      function tempCtor() {};
      tempCtor.prototype = superClass.prototype;
      subClass.superclass = superClass.prototype;
      subClass.prototype = new tempCtor();
      subClass.prototype.constructor = subClass;

      // TODO: is the following necessary?
      if (superClass.prototype.constructor == Object.prototype.constructor) {
        superClass.prototype.constructor = superClass;
      }
    },

    clone: function(object) {
      function stubObj() {}
      stubObj.prototype = object;
      var newObj = new stubObj();
      // TODO: add comments here
      newObj.chrome_comp_getInternalObject = function() {
        return this.__proto__;
      }
      // TODO: add comments here
      newObj.toString = function() {
        try {
          return this.__proto__.toString();
        } catch (e) {
          return 'object Object';
        }
      }
      return newObj;
    },

    ellipsize: function(string, maxLength) {
      return string ? (string.length > maxLength ?
                       string.substring(0, maxLength - 3) + '...' : string)
                    : '';
    },

    /**
     * Trim leading and trailing white spaces. It differs from String.trim()
     * that this function doesn't trim non-breakable spaces (\xA0).
     */
    trim: function(s) {
      return s.replace(chrome_comp.LEADING_WHITESPACES, '')
              .replace(chrome_comp.TRAILING_WHITESPACES, '');
    },

    /**
     * Send a request to the content script. The content script uses
     * document.documentElement.addEventListener(name, function()...) to
     * listen to the request. The parameters and result are passed with
     * attributes of document.documentElement.
     */
    sendRequest: function(name, params, resultName) {
      var event = document.createEvent('Event');
      event.initEvent(name, true, true);
      if (params) {
        for (var i in params) {
          if (params[i] != undefined)
            document.documentElement.setAttribute(i, params[i]);
        }
      }
      document.documentElement.dispatchEvent(event);
      if (params) {
        for (var i in params)
          document.documentElement.removeAttribute(i);
      }
      if (resultName) {
        var result = document.documentElement.getAttribute(resultName);
        document.documentElement.removeAttribute(resultName);
        return result;
      }
    },

    getMessage: function(name, params) {
      var result;
      if (!params) {
        result = messageCache_[name];
        if (result)
          return result;
      }

      result = chrome_comp.sendRequest('chrome_comp_getMessage', {
        chrome_comp_messageName: name,
        chrome_comp_messageParams: JSON.stringify(params)
      }, 'chrome_comp_messageResult');

      if (!params)
        messageCache_[name] = result;
      return result;
    },

    /**
     * Dumps the current calling stack, stripping out all frames that are in
     * detector injected code.
     */
    dumpStack: function() {
      // Disable hooks during dumpStack() because Error.stack might enumerate
      // properties which will trigger some property hook.
      chrome_comp.enableHooks(false);
      try {
        var stack = new Error().stack;
        var pos = stack.lastIndexOf('chrome_comp_injector');
        var pos1 = stack.indexOf('\n', pos);
        return pos1 == -1 ? '' : stack.substring(pos1 + 1);
      } finally {
        chrome_comp.enableHooks(true);
      }
    },

    getSourceAndLine: function(stack) {
      stack = stack || chrome_comp.dumpStack();
      var r = /at .*:[0-9]+(?=:[0-9]+)/.exec(stack);
      return r ? r[0].replace(/^at /, '') : null;
    },

    /**
     * Don't directly use Error.stack because it will cause recursive property
     * hooks. Use this function instead.
     */
    printError: function(message, e) {
      if (!e)
        e = new Error();
      chrome_comp.enableHooks(false);
      try {
        chrome_comp.trace(message + (e.stack || e));
      } finally {
        chrome_comp.enableHooks(true);
      }
    },

    /**
     * Check if a call stack is called directly or indirectly from an extension.
     */
    isCalledFromExtension: function(stackDump) {
      return (stackDump || chrome_comp.dumpStack()).
          indexOf('chrome-extension://') >= 0;
    },

    getCallSite: function(stackDump) {
      if (!stackDump)
        stackDump = chrome_comp.dumpStack();
      var pos = stackDump.indexOf('\n', pos);
      return pos == -1 ? stackDump : stackDump.substring(0, pos);
    },

    setPropertyIfNeed: function(obj, property, value) {
      if (typeof obj[property] == 'undefined')
        obj[property] = value;
    },

    filterFunctionCallStackByFunctionSignature: function(initialCallStack,
                                                          functionSignature) {
      var currentCallStack = initialCallStack;
      var i = 0;
      var caller, callerContent;
      while (currentCallStack.caller) {
        if (i > 20) {
          chrome_comp.trace('caller checking stack overflow: ' + callerContent);
          break;
        }
        try {
          caller = currentCallStack.caller;
          callerContent = caller.toString();
          // When found the call is called by some library, we ignore this
          // call.
          if (callerContent.search(functionSignature) > -1) {
            return true;
          }
        } catch (e) {
          chrome_comp.printError('trace caller stack error: ', e);
        }
        currentCallStack = caller.arguments.callee;
        i++;
      }
      return false;
    },

    getTargetPageURL: function() {
      return targetPageURL_;
    },

    nodeContents: function(node) {
      // TODO: avoid using outerHTML to improve performance.
      if (this.Node.ELEMENT_NODE == node.nodeType)
        return node.outerHTML;
      else if (this.Node.TEXT_NODE == node.nodeType)
        return node.nodeValue;
      else
        return node.toString();
    },

    getAttributeLowerCase: function(ele, name) {
      if (!ele || !name || Node.ELEMENT_NODE != ele.nodeType)
        return null;
      var value = ele.getAttribute(name);
      return value ? value.toLowerCase() : value;
    },

    getComputedStyle: function(ele, pseudo) {
      if (!ele)
        return;
      var computedStyle = ele.chrome_comp_computedStyleCache;
      if (computedStyle)
        return computedStyle;
      try {
        computedStyle = ele.ownerDocument.defaultView.getComputedStyle(ele,
            pseudo);
        ele.chrome_comp_computedStyleCache = computedStyle;
        return computedStyle;
      } catch (e) {
        chrome_comp.printError('getComputedStyle error: ', e);
        chrome_comp.trace(ele);
      }
    },

    /**
     * The cacheSpecifiedValue function caches the specified value of margin,
     * border, padding, width and height properties in the property of every
     * element. So we retrieve these values here. If there is no cached value or
     * there is no specified node, we just return the empty object.
     * @param {object} ele the specified node.
     * @return {object} return the specified value of the node or the empty
     *     object.
     */
    getSpecifiedValue: function(ele) {
      if (!ele || !ele[chrome_comp.SPECIFIED_VALUE])
        return {};<commit_msg>for http://codereview.appspot.com/4315041/ because the CL was broken on my local.<commit_after>/*
 * Copyright 2010 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.
 */

addScriptToInject(function() {

window.chrome_comp = (function() {
  var targetPageURL_ = window.location;
  // >=0 if hook is enabled.
  var hookDisabledCount_ = 0;

  var messageCache_ = {};

  var BLOCK_DISPLAY_VALUES = {
    block: true,
    'inline-block': true,
    'list-item': true,
    table: true,
    'inline-table': true,
    'table-cell': true,
    'table-caption': true
  };

  return {

    COLOR_TRANSPARENT: 'rgba(0, 0, 0, 0)',

    SPECIFIED_VALUE: 'chrome_comp_specified_value',

    WHITESPACE: /[ \t\r\n]/,
    LEADING_WHITESPACES: /^[ \t\r\n]+/,
    TRAILING_WHITESPACES: /[ \t\r\n]+$/,

    // cache Node reference
    Node: window.Node,

    enableHooks: function(enable) {
      hookDisabledCount_ += (enable ? 1 : -1);
    },

    areHooksDisabled: function() {
      return hookDisabledCount_ < 0;
    },

    // Uses it to prompt debug message.
    trace: function(msg) {
      if (chrome_comp.CompDetectorConfig.canTraceBug) {
        console.log(new Date().getTime() + ' $chrome_comp for : ' +
            chrome_comp.getTargetPageURL() + '$');
        console.log(msg);
      }
    },

    // Uses it to implement inherit logic in JavaScript
    extend: function(subClass, superClass) {
      // Use prototype chain to inherit baseClass's method.
      function tempCtor() {};
      tempCtor.prototype = superClass.prototype;
      subClass.superclass = superClass.prototype;
      subClass.prototype = new tempCtor();
      subClass.prototype.constructor = subClass;

      // TODO: is the following necessary?
      if (superClass.prototype.constructor == Object.prototype.constructor) {
        superClass.prototype.constructor = superClass;
      }
    },

    clone: function(object) {
      function stubObj() {}
      stubObj.prototype = object;
      var newObj = new stubObj();
      // TODO: add comments here
      newObj.chrome_comp_getInternalObject = function() {
        return this.__proto__;
      }
      // TODO: add comments here
      newObj.toString = function() {
        try {
          return this.__proto__.toString();
        } catch (e) {
          return 'object Object';
        }
      }
      return newObj;
    },

    ellipsize: function(string, maxLength) {
      return string ? (string.length > maxLength ?
                       string.substring(0, maxLength - 3) + '...' : string)
                    : '';
    },

    /**
     * Trim leading and trailing white spaces. It differs from String.trim()
     * that this function doesn't trim non-breakable spaces (\xA0).
     */
    trim: function(s) {
      return s.replace(chrome_comp.LEADING_WHITESPACES, '')
              .replace(chrome_comp.TRAILING_WHITESPACES, '');
    },

    /**
     * Send a request to the content script. The content script uses
     * document.documentElement.addEventListener(name, function()...) to
     * listen to the request. The parameters and result are passed with
     * attributes of document.documentElement.
     */
    sendRequest: function(name, params, resultName) {
      var event = document.createEvent('Event');
      event.initEvent(name, true, true);
      if (params) {
        for (var i in params) {
          if (params[i] != undefined)
            document.documentElement.setAttribute(i, params[i]);
        }
      }
      document.documentElement.dispatchEvent(event);
      if (params) {
        for (var i in params)
          document.documentElement.removeAttribute(i);
      }
      if (resultName) {
        var result = document.documentElement.getAttribute(resultName);
        document.documentElement.removeAttribute(resultName);
        return result;
      }
    },

    getMessage: function(name, params) {
      var result;
      if (!params) {
        result = messageCache_[name];
        if (result)
          return result;
      }

      result = chrome_comp.sendRequest('chrome_comp_getMessage', {
        chrome_comp_messageName: name,
        chrome_comp_messageParams: JSON.stringify(params)
      }, 'chrome_comp_messageResult');

      if (!params)
        messageCache_[name] = result;
      return result;
    },

    /**
     * Dumps the current calling stack, stripping out all frames that are in
     * detector injected code.
     */
    dumpStack: function() {
      // Disable hooks during dumpStack() because Error.stack might enumerate
      // properties which will trigger some property hook.
      chrome_comp.enableHooks(false);
      try {
        var stack = new Error().stack;
        var pos = stack.lastIndexOf('chrome_comp_injector');
        var pos1 = stack.indexOf('\n', pos);
        return pos1 == -1 ? '' : stack.substring(pos1 + 1);
      } finally {
        chrome_comp.enableHooks(true);
      }
    },

    getSourceAndLine: function(stack) {
      stack = stack || chrome_comp.dumpStack();
      var r = /at .*:[0-9]+(?=:[0-9]+)/.exec(stack);
      return r ? r[0].replace(/^at /, '') : null;
    },

    /**
     * Don't directly use Error.stack because it will cause recursive property
     * hooks. Use this function instead.
     */
    printError: function(message, e) {
      if (!e)
        e = new Error();
      chrome_comp.enableHooks(false);
      try {
        chrome_comp.trace(message + (e.stack || e));
      } finally {
        chrome_comp.enableHooks(true);
      }
    },

    /**
     * Check if a call stack is called directly or indirectly from an extension.
     */
    isCalledFromExtension: function(stackDump) {
      return (stackDump || chrome_comp.dumpStack()).
          indexOf('chrome-extension://') >= 0;
    },

    getCallSite: function(stackDump) {
      if (!stackDump)
        stackDump = chrome_comp.dumpStack();
      var pos = stackDump.indexOf('\n', pos);
      return pos == -1 ? stackDump : stackDump.substring(0, pos);
    },

    setPropertyIfNeed: function(obj, property, value) {
      if (typeof obj[property] == 'undefined')
        obj[property] = value;
    },

    filterFunctionCallStackByFunctionSignature: function(initialCallStack,
                                                          functionSignature) {
      var currentCallStack = initialCallStack;
      var i = 0;
      var caller, callerContent;
      while (currentCallStack.caller) {
        if (i > 20) {
          chrome_comp.trace('caller checking stack overflow: ' + callerContent);
          break;
        }
        try {
          caller = currentCallStack.caller;
          callerContent = caller.toString();
          // When found the call is called by some library, we ignore this
          // call.
          if (callerContent.search(functionSignature) > -1) {
            return true;
          }
        } catch (e) {
          chrome_comp.printError('trace caller stack error: ', e);
        }
        currentCallStack = caller.arguments.callee;
        i++;
      }
      return false;
    },

    getTargetPageURL: function() {
      return targetPageURL_;
    },

    nodeContents: function(node) {
      // TODO: avoid using outerHTML to improve performance.
      if (this.Node.ELEMENT_NODE == node.nodeType)
        return node.outerHTML;
      else if (this.Node.TEXT_NODE == node.nodeType)
        return node.nodeValue;
      else
        return node.toString();
    },

    getAttributeLowerCase: function(ele, name) {
      if (!ele || !name || Node.ELEMENT_NODE != ele.nodeType)
        return null;
      var value = ele.getAttribute(name);
      return value ? value.toLowerCase() : value;
    },

    getComputedStyle: function(ele, pseudo) {
      if (!ele)
        return;
      var computedStyle = ele.chrome_comp_computedStyleCache;
      if (computedStyle && !pseudo)
        return computedStyle;
      try {
        computedStyle = ele.ownerDocument.defaultView.getComputedStyle(ele,
            pseudo);
        // We cannot cache the style of the pseudo element on the current
        // element here, or it will override the style of this element itself.
        if (!pseudo)
          ele.chrome_comp_computedStyleCache = computedStyle;
        return computedStyle;
      } catch (e) {
        chrome_comp.printError('getComputedStyle error: ', e);
        chrome_comp.trace(ele);
      }
    },

    /**
     * The cacheSpecifiedValue function caches the specified value of margin,
     * border, padding, width and height properties in the property of every
     * element. So we retrieve these values here. If there is no cached value or
     * there is no specified node, we just return the empty object.
     * @param {object} ele the specified node.
     * @return {object} return the specified value of the node or the empty
     *     object.
     */
    getSpecifiedValue: function(ele) {
      if (!ele || !ele[chrome_comp.SPECIFIED_VALUE])
        return {};
{'fraction_non_alphanumeric': 0.11029529985529771, 'fraction_numerical': 0.004341068653196849, 'mean_word_length': 2.3038243626062322, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2592469', 'n_tokens_mistral': 5357, 'n_tokens_neox': 5205, 'n_words': 1439}