<commit_before>/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/*
 * Copyright 2013 Mozilla Foundation
 *
 * 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.
 */
/*global avm1lib, Proxy, Multiname, ActionsDataStream, TelemetryService,
         isNumeric, forEachPublicProperty, construct */

var AVM1_TRACE_ENABLED = false;
var AVM1_ERRORS_IGNORED = true;
var MAX_AVM1_INSTRUCTIONS_LIMIT = 100000;
var MAX_AVM1_ERRORS_LIMIT = 1000;
var MAX_AVM1_STACK_LIMIT = 256;

function AS2ScopeListItem(scope, next) {
  this.scope = scope;
  this.next = next;
}
AS2ScopeListItem.prototype = {
  create: function (scope) {
    return new AS2ScopeListItem(scope, this);
  }
};

function AS2Context(swfVersion) {
  this.swfVersion = swfVersion;
  this.globals = new avm1lib.AS2Globals(this);
  this.initialScope = new AS2ScopeListItem(this.globals, null);
  this.assets = {};
  this.instructionsExecuted = 0;
  this.stackDepth = 0;
  this.isTryCatchListening = false;
  this.errorsIgnored = 0;
  this.deferScriptExecution = true;
  this.pendingScripts = [];
}
AS2Context.instance = null;
AS2Context.prototype = {
  addAssets: function(assets) {
    for (var i = 0; i < assets.length; i++) {
      if (assets[i].className) {
        this.assets[assets[i].className] = assets[i];
      }
    }
  },
  resolveTarget: function(target) {
    if (!target) {
      target = this.defaultTarget;
    } else if (typeof target === 'string') {
      target = lookupAS2Children(target, this.defaultTarget,
                                 this.globals.asGetPublicProperty('_root'));
    }
    if (typeof target !== 'object' || target === null ||
        !('$nativeObject' in target)) {
      throw new Error('Invalid AS2 target object: ' +
                      Object.prototype.toString.call(target));
    }

    return target;
  },
  resolveLevel: function(level) {
    return this.resolveTarget(this.globals['_level' + level]);
  },
  addToPendingScripts: function (fn) {
    if (!this.deferScriptExecution) {
      return fn();
    }
    this.pendingScripts.push(fn);
  },
  flushPendingScripts: function () {
    var scripts = this.pendingScripts;
    while (scripts.length) {
      scripts.shift()();
    }
    this.deferScriptExecution = false;
  }
};

function AS2Error(error) {
  this.error = error;
}

function AS2CriticalError(message, error) {
  this.message = message;
  this.error = error;
}
AS2CriticalError.prototype = Object.create(Error.prototype);

function isAS2MovieClip(obj) {
  return typeof obj === 'object' && obj &&
         obj instanceof avm1lib.AS2MovieClip;
}

function as2GetType(v) {
  if (v === null) {
    return 'null';
  }

  var type = typeof v;
  if (type === 'function') {
    return 'object';
  }
  if (type === 'object' && isAS2MovieClip(v)) {
    return 'movieclip';
  }
  return type;
}

function as2ToPrimitive(value) {
  return as2GetType(value) !== 'object' ? value : value.valueOf();
}

function as2ToAddPrimitive(value) {
  if (as2GetType(value) !== 'object') {
    return value;
  }

  if (value instanceof Date && AS2Context.instance.swfVersion >= 6) {
    return value.toString();
  } else {
    return value.valueOf();
  }
}

function as2ToBoolean(value) {
  switch (as2GetType(value)) {
  default:
  case 'undefined':
  case 'null':
    return false;
  case 'boolean':
    return value;
  case 'number':
    return value !== 0 && !isNaN(value);
  case 'string':
    return value.length !== 0;
  case 'movieclip':
  case 'object':
    return true;
  }
}

function as2ToNumber(value) {
  value = as2ToPrimitive(value);
  switch (as2GetType(value)) {
  case 'undefined':
  case 'null':
    return AS2Context.instance.swfVersion >= 7 ? NaN : 0;
  default:
    return AS2Context.instance.swfVersion >= 5 ? NaN : 0;
  case 'null':
    return NaN;
  case 'boolean':
    return value ? 1 : +0;
  case 'number':
    return value;
  case 'string':
    if (value === '' && AS2Context.instance.swfVersion < 5) {
      return 0;
    }
    return +value;
  }
}

function as2ToInteger(value) {
  var result = as2ToNumber(value);
  if (isNaN(result)) {
    return 0;
  }
  if (!isFinite(result) || result === 0) {
    return result;
  }
  return (result < 0 ? -1 : 1) * Math.abs(result)|0;
}

function as2ToInt32(value) {
  var result = as2ToNumber(value);
  return (isNaN(result) || !isFinite(result) || result === 0) ? 0 :
    (result | 0);
}

function as2ToString(value) {
  switch (as2GetType(value)) {
  case 'undefined':
    return AS2Context.instance.swfVersion >= 7 ? 'undefined' : '';
  case 'null':
    return 'null';
  case 'boolean':
    return value ? 'true' : 'false';
  case 'number':
    return value.toString();
  case 'string':
    return value;
  case 'undefined':
    return 'undefined';
  case 'movieclip':
    return value.$targetPath;
  case 'object':
    var result = value.toString !== Function.prototype.toString ?
      value.toString() : value;
    if (typeof result === 'string') {
      return result;
    }
    return typeof value === 'function' ? '[type Function]'
                                       : '[type Object]';
  }
}

function as2Compare(x, y) {
  var x2 = as2ToPrimitive(x);
  var y2 = as2ToPrimitive(y);
  if (typeof x2 === 'string' && typeof y2 === 'string') {
    return x2 < y2;
  } else {
    return as2ToNumber(x2) < as2ToNumber(y2);
  }
}

function as2InstanceOf(obj, constructor) {
  if (obj instanceof constructor) {
    return true;
  }
  // TODO interface check
  return false;
}

function as2ResolveProperty(obj, name) {
  // checking if avm2 public property is present
  var avm2PublicName = Multiname.getPublicQualifiedName(name);
  if (avm2PublicName in obj) {
    return name;
  }
  if (isNumeric(name)) {
    return null;
  }
  var lowerCaseName = avm2PublicName.toLowerCase();
  for (var i in obj) {
    if (i.toLowerCase() === lowerCaseName) {
      return i.substr(Multiname.PUBLIC_QUALIFIED_NAME_PREFIX.length);
    }
  }
  return null;
}

function as2GetPrototype(obj) {
  return obj && obj.asGetPublicProperty('prototype');
}

function isAvm2Class(obj) {
  return typeof obj === 'object' && obj !== null && 'instanceConstructor' in obj;
}

function as2CreatePrototypeProxy(obj) {
  var prototype = obj.asGetPublicProperty('prototype');
  if (typeof Proxy === 'undefined') {
    console.error('ES6 proxies are not found');
    return prototype;
  }
  return Proxy.create({
    getOwnPropertyDescriptor: function(name) {
      return Object.getOwnPropertyDescriptor(prototype, name);
    },
    getPropertyDescriptor:  function(name) {
      // ES6: return getPropertyDescriptor(prototype, name);
      for (var p = prototype; p; p = Object.getPrototypeOf(p)) {
        var desc = Object.getOwnPropertyDescriptor(p, name);
        if (desc) return desc;
      }
    },
    getOwnPropertyNames: function() {
      return Object.getOwnPropertyNames(prototype);
    },
    getPropertyNames: function() {
      // ES6: return getPropertyNames(prototype, name);
      var names = Object.getOwnPropertyNames(prototype);
      for (var p = Object.getPrototypeOf(prototype); p;
           p = Object.getPrototypeOf(p)) {
        names = names.concat(Object.getOwnPropertyNames(p));
      }
      return names;
    },
    defineProperty: function(name, desc) {
      if (desc) {
        if (typeof desc.value === 'function' && desc.value._setClass) {
          desc.value._setClass(obj);
        }
        if (typeof desc.get === 'function' && desc.get._setClass) {
          desc.get._setClass(obj);
        }
        if (typeof desc.set === 'function' && desc.set._setClass) {
          desc.set._setClass(obj);
        }
      }
      return Object.defineProperty(prototype, name, desc);
    },
    delete: function(name) {
      return delete prototype[name];
    },
    fix: function() {
      return undefined;
    }
  });
}

function executeActions(actionsData, context, scope, assets) {
  var actionTracer = ActionTracerFactory.get();

  var scopeContainer = context.initialScope.create(scope);
  var savedContext = AS2Context.instance;
  try {
    AS2Context.instance = context;
    context.defaultTarget = scope;
    context.globals.asSetPublicProperty('this', scope);
    if (assets) {
      context.addAssets(assets);
    }
    actionTracer.message('ActionScript Execution Starts');
    actionTracer.indent();
    interpretActions(actionsData, scopeContainer, null, []);
  } finally {
    context.instructionsExecuted = 0;
    context.errorsIgnored = 0;

    actionTracer.unindent();
    actionTracer.message('ActionScript Execution Stops');
    AS2Context.instance = savedContext;
  }
}

function lookupAS2Children(targetPath, defaultTarget, root) {
  var path = targetPath.split(/[\/.]/g);
  if (path[path.length - 1] === '') {
    path.pop();
  }
  var obj = defaultTarget;
  if (path[0] === '' || path[0] === '_level0' || path[0] === '_root') {
    obj = root;
    path.shift();
  }
  while (path.length > 0) {
    var prevObj = obj;
    obj = obj.$lookupChild(path[0]);
    if (!obj) {
      throw new Error(path[0] + ' (expr ' + targetPath + ') is not found in ' +
                      prevObj._target);
    }
    path.shift();
  }
  return obj;
}

function createBuiltinType(obj, args) {
  if (obj === Array) {
    // special case of array
    var result = args;
    if (args.length == 1 && typeof args[0] === 'number') {
      result = [];
      result.length = args[0];
    }
    return result;
  }
  if (obj === Boolean || obj === Number || obj === String || obj === Function) {
    return obj.apply(null, args);
  }
  if (obj === Date) {
    switch (args.length) {
      case 0:
        return new Date();
      case 1:
        return new Date(args[0]);
      default:
        return new Date(args[0], args[1],
          args.length > 2 ? args[2] : 1,
          args.length > 3 ? args[3] : 0,
          args.length > 4 ? args[4] : 0,
          args.length > 5 ? args[5] : 0,
          args.length > 6 ? args[6] : 0);
    }
  }
  if (obj === Object) {
    return {};
  }
}

var AS2_SUPER_STUB = {};

function interpretActions(actionsData, scopeContainer,
                          constantPool, registers) {
  var currentContext = AS2Context.instance;

  function setTarget(targetPath) {
    if (!targetPath) {
      currentContext.defaultTarget = scope;
      return;
    }

    try {
      currentContext.defaultTarget =
        lookupAS2Children(targetPath, defaultTarget, _global.asGetPublicProperty('_root'));
    } catch (e) {
      currentContext.defaultTarget = null;
      throw e;
    }
  }

  function defineFunction(functionName, parametersNames,
                          registersAllocation, actionsData) {
    var ownerClass;
    var fn = (function() {
      var newScope = {};
      newScope.asSetPublicProperty('this', this);
      newScope.asSetPublicProperty('arguments', arguments);
      newScope.asSetPublicProperty('super', AS2_SUPER_STUB);
      newScope.asSetPublicProperty('__class', ownerClass);
      var newScopeContainer = scopeContainer.create(newScope);
      var i;

      for (i = 0; i < arguments.length || i < parametersNames.length; i++) {
        newScope[parametersNames[i]] = arguments[i];
      }
      var registers = [];
      if (registersAllocation) {
        for (i = 0; i < registersAllocation.length; i++) {
          var registerAllocation = registersAllocation[i];
          if (!registerAllocation) {
            continue;
          }
          if (registerAllocation.type == 'param') {
            registers[i] = arguments[registerAllocation.index];
          } else { // var
            switch (registerAllocation.name) {
              case 'this':
                registers[i] = this;
                break;
              case 'arguments':
                registers[i] = arguments;
                break;
              case 'super':
                registers[i] = AS2_SUPER_STUB;
                break;
              case '_global':
                registers[i] = _global;
                break;
              case '_parent':
                registers[i] = scope.asGetPublicProperty('_parent');
                break;
              case '_root':
                registers[i] = _global.asGetPublicProperty('_root');
                break;
            }
          }
        }
      }

      var savedContext = AS2Context.instance;
      var resetCounters;
      try
      {
        // switching contexts if called outside main thread
        AS2Context.instance = currentContext;
        resetCounters = currentContext.instructionsExecuted === 0;
        currentContext.defaultTarget = scope;
        actionTracer.indent();
        currentContext.stackDepth++;
        if (currentContext.stackDepth >= MAX_AVM1_STACK_LIMIT) {
          throw new AS2CriticalError('long running script -- AVM1 recursion limit is reached');
        }
        return interpretActions(actionsData, newScopeContainer,
          constantPool, registers);
      } finally {
        if (resetCounters) {
          currentContext.instructionsExecuted = 0;
          currentContext.errorsIgnored = 0;
        }
        currentContext.stackDepth--;
        actionTracer.unindent();
        currentContext.defaultTarget = defaultTarget;
        AS2Context.instance = savedContext;
      }
    });

    ownerClass = fn;
    fn._setClass = function (class_) {
      ownerClass = class_;
    };

    fn.instanceConstructor = fn;
    fn.debugName = 'avm1 ' + (functionName || '<function>');
    if (functionName) {
      fn.name = functionName;
    }
    return fn;
  }
  function deleteProperty(propertyName) {
    for (var p = scopeContainer; p; p = p.next) {
      if (p.scope.asHasProperty(undefined, propertyName, 0)) {
        p.scope.asSetPublicProperty(propertyName, undefined); // in some cases we need to cleanup events binding
        return p.scope.asDeleteProperty(undefined, propertyName, 0);
      }
    }
    return false;
  }
  function resolveVariableName(variableName, nonStrict) {
    var obj, name, i;
    if (variableName.indexOf(':') >= 0) {
      // "/A/B:FOO references the FOO variable in the movie clip with a target path of /A/B."
      var parts = variableName.split(':');
      obj = lookupAS2Children(parts[0], defaultTarget,
                              _global.asGetPublicProperty('_root'));
      if (!obj) {
        throw new Error(parts[0] + ' is undefined');
      }
      name = parts[1];
    } else if (variableName.indexOf('.') >= 0) {
      // new object reference
      var objPath = variableName.split('.');
      name = objPath.pop();
      obj = _global;
      for (i = 0; i < objPath.length; i++) {
        obj = obj.asGetPublicProperty(objPath[i]) || obj[objPath[i]];
        if (!obj) {
          throw new Error(objPath.slice(0, i + 1) + ' is undefined');
        }
      }
    }

    if (!obj) {
      return null; // local variable
    }

    var resolvedName = as2ResolveProperty(obj, name);
    var resolved = resolvedName !== null;
    if (resolved || nonStrict) {
      return { obj: obj, name: resolvedName || name, resolved: resolved };
    }

    return null;
  }
  function getThis() {
    var _this = scope.asGetPublicProperty('this');
    if (_this) {
      return _this;
    }
    for (var p = scopeContainer; p; p = p.next) {
      resolvedName = as2ResolveProperty(p.scope, 'this');
      if (resolvedName !== null) {
        return p.scope.asGetPublicProperty(resolvedName);
      }
    }
  }
  function getVariable(variableName) {
    // fast check if variable in the current scope
    if (scope.asHasProperty(undefined, variableName, 0)) {
      return scope.asGetPublicProperty(variableName);
    }

    var target = resolveVariableName(variableName);
    if (target) {
      return target.obj.asGetPublicProperty(target.name);
    }
    var resolvedName, _this = getThis();
    for (var p = scopeContainer; p; p = p.next) {
      resolvedName = as2ResolveProperty(p.scope, variableName);
      if (resolvedName !== null) {
        return p.scope.asGetPublicProperty(resolvedName);
      }
    }
    if(_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
      return _this.asGetPublicProperty(resolvedName);
    }
    // trying movie clip children (if object is a MovieClip)
    var mc = isAS2MovieClip(defaultTarget) &&
             defaultTarget.$lookupChild(variableName);
    if (mc) {
      return mc;
    }
  }

  function setVariable(variableName, value) {
    // fast check if variable in the current scope
    if (scope.asHasProperty(undefined, variableName, 0)) {
      scope.asSetPublicProperty(variableName, value);
      return;
    }

    var target = resolveVariableName(variableName, true);
    if (target) {
      target.obj.asSetPublicProperty(target.name, value);
      return;
    }
    var resolvedName, _this = getThis();
    if(_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
      return _this.asSetPublicProperty(resolvedName, value);
    }

    for (var p = scopeContainer; p; p = p.next) {
      resolvedName = as2ResolveProperty(p.scope, variableName);
      if (resolvedName !== null) {
        return p.scope.asSetPublicProperty(resolvedName, value);
      }
    }
    (_this || scope).asSetPublicProperty(variableName, value);
  }
  function getFunction(functionName) {
    var fn = getVariable(functionName);
    if (!(fn instanceof Function)) {<commit_msg>Fixes flocons regression (e898daa415e85)<commit_after>/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/*
 * Copyright 2013 Mozilla Foundation
 *
 * 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.
 */
/*global avm1lib, Proxy, Multiname, ActionsDataStream, TelemetryService,
         isNumeric, forEachPublicProperty, construct */

var AVM1_TRACE_ENABLED = false;
var AVM1_ERRORS_IGNORED = true;
var MAX_AVM1_INSTRUCTIONS_LIMIT = 100000;
var MAX_AVM1_ERRORS_LIMIT = 1000;
var MAX_AVM1_STACK_LIMIT = 256;

function AS2ScopeListItem(scope, next) {
  this.scope = scope;
  this.next = next;
}
AS2ScopeListItem.prototype = {
  create: function (scope) {
    return new AS2ScopeListItem(scope, this);
  }
};

function AS2Context(swfVersion) {
  this.swfVersion = swfVersion;
  this.globals = new avm1lib.AS2Globals(this);
  this.initialScope = new AS2ScopeListItem(this.globals, null);
  this.assets = {};
  this.instructionsExecuted = 0;
  this.stackDepth = 0;
  this.isTryCatchListening = false;
  this.errorsIgnored = 0;
  this.deferScriptExecution = true;
  this.pendingScripts = [];
}
AS2Context.instance = null;
AS2Context.prototype = {
  addAssets: function(assets) {
    for (var i = 0; i < assets.length; i++) {
      if (assets[i].className) {
        this.assets[assets[i].className] = assets[i];
      }
    }
  },
  resolveTarget: function(target) {
    if (!target) {
      target = this.defaultTarget;
    } else if (typeof target === 'string') {
      target = lookupAS2Children(target, this.defaultTarget,
                                 this.globals.asGetPublicProperty('_root'));
    }
    if (typeof target !== 'object' || target === null ||
        !('$nativeObject' in target)) {
      throw new Error('Invalid AS2 target object: ' +
                      Object.prototype.toString.call(target));
    }

    return target;
  },
  resolveLevel: function(level) {
    return this.resolveTarget(this.globals['_level' + level]);
  },
  addToPendingScripts: function (fn) {
    if (!this.deferScriptExecution) {
      return fn();
    }
    this.pendingScripts.push(fn);
  },
  flushPendingScripts: function () {
    var scripts = this.pendingScripts;
    while (scripts.length) {
      scripts.shift()();
    }
    this.deferScriptExecution = false;
  }
};

function AS2Error(error) {
  this.error = error;
}

function AS2CriticalError(message, error) {
  this.message = message;
  this.error = error;
}
AS2CriticalError.prototype = Object.create(Error.prototype);

function isAS2MovieClip(obj) {
  return typeof obj === 'object' && obj &&
         obj instanceof avm1lib.AS2MovieClip;
}

function as2GetType(v) {
  if (v === null) {
    return 'null';
  }

  var type = typeof v;
  if (type === 'function') {
    return 'object';
  }
  if (type === 'object' && isAS2MovieClip(v)) {
    return 'movieclip';
  }
  return type;
}

function as2ToPrimitive(value) {
  return as2GetType(value) !== 'object' ? value : value.valueOf();
}

function as2ToAddPrimitive(value) {
  if (as2GetType(value) !== 'object') {
    return value;
  }

  if (value instanceof Date && AS2Context.instance.swfVersion >= 6) {
    return value.toString();
  } else {
    return value.valueOf();
  }
}

function as2ToBoolean(value) {
  switch (as2GetType(value)) {
  default:
  case 'undefined':
  case 'null':
    return false;
  case 'boolean':
    return value;
  case 'number':
    return value !== 0 && !isNaN(value);
  case 'string':
    return value.length !== 0;
  case 'movieclip':
  case 'object':
    return true;
  }
}

function as2ToNumber(value) {
  value = as2ToPrimitive(value);
  switch (as2GetType(value)) {
  case 'undefined':
  case 'null':
    return AS2Context.instance.swfVersion >= 7 ? NaN : 0;
  default:
    return AS2Context.instance.swfVersion >= 5 ? NaN : 0;
  case 'null':
    return NaN;
  case 'boolean':
    return value ? 1 : +0;
  case 'number':
    return value;
  case 'string':
    if (value === '' && AS2Context.instance.swfVersion < 5) {
      return 0;
    }
    return +value;
  }
}

function as2ToInteger(value) {
  var result = as2ToNumber(value);
  if (isNaN(result)) {
    return 0;
  }
  if (!isFinite(result) || result === 0) {
    return result;
  }
  return (result < 0 ? -1 : 1) * Math.abs(result)|0;
}

function as2ToInt32(value) {
  var result = as2ToNumber(value);
  return (isNaN(result) || !isFinite(result) || result === 0) ? 0 :
    (result | 0);
}

function as2ToString(value) {
  switch (as2GetType(value)) {
  case 'undefined':
    return AS2Context.instance.swfVersion >= 7 ? 'undefined' : '';
  case 'null':
    return 'null';
  case 'boolean':
    return value ? 'true' : 'false';
  case 'number':
    return value.toString();
  case 'string':
    return value;
  case 'undefined':
    return 'undefined';
  case 'movieclip':
    return value.$targetPath;
  case 'object':
    var result = value.toString !== Function.prototype.toString ?
      value.toString() : value;
    if (typeof result === 'string') {
      return result;
    }
    return typeof value === 'function' ? '[type Function]'
                                       : '[type Object]';
  }
}

function as2Compare(x, y) {
  var x2 = as2ToPrimitive(x);
  var y2 = as2ToPrimitive(y);
  if (typeof x2 === 'string' && typeof y2 === 'string') {
    return x2 < y2;
  } else {
    return as2ToNumber(x2) < as2ToNumber(y2);
  }
}

function as2InstanceOf(obj, constructor) {
  if (obj instanceof constructor) {
    return true;
  }
  // TODO interface check
  return false;
}

function as2ResolveProperty(obj, name) {
  // checking if avm2 public property is present
  var avm2PublicName = Multiname.getPublicQualifiedName(name);
  if (avm2PublicName in obj) {
    return name;
  }
  if (isNumeric(name)) {
    return null;
  }
  var lowerCaseName = avm2PublicName.toLowerCase();
  for (var i in obj) {
    if (i.toLowerCase() === lowerCaseName) {
      return i.substr(Multiname.PUBLIC_QUALIFIED_NAME_PREFIX.length);
    }
  }
  return null;
}

function as2GetPrototype(obj) {
  return obj && obj.asGetPublicProperty('prototype');
}

function isAvm2Class(obj) {
  return typeof obj === 'object' && obj !== null && 'instanceConstructor' in obj;
}

function as2CreatePrototypeProxy(obj) {
  var prototype = obj.asGetPublicProperty('prototype');
  if (typeof Proxy === 'undefined') {
    console.error('ES6 proxies are not found');
    return prototype;
  }
  return Proxy.create({
    getOwnPropertyDescriptor: function(name) {
      return Object.getOwnPropertyDescriptor(prototype, name);
    },
    getPropertyDescriptor:  function(name) {
      // ES6: return getPropertyDescriptor(prototype, name);
      for (var p = prototype; p; p = Object.getPrototypeOf(p)) {
        var desc = Object.getOwnPropertyDescriptor(p, name);
        if (desc) return desc;
      }
    },
    getOwnPropertyNames: function() {
      return Object.getOwnPropertyNames(prototype);
    },
    getPropertyNames: function() {
      // ES6: return getPropertyNames(prototype, name);
      var names = Object.getOwnPropertyNames(prototype);
      for (var p = Object.getPrototypeOf(prototype); p;
           p = Object.getPrototypeOf(p)) {
        names = names.concat(Object.getOwnPropertyNames(p));
      }
      return names;
    },
    defineProperty: function(name, desc) {
      if (desc) {
        if (typeof desc.value === 'function' && desc.value._setClass) {
          desc.value._setClass(obj);
        }
        if (typeof desc.get === 'function' && desc.get._setClass) {
          desc.get._setClass(obj);
        }
        if (typeof desc.set === 'function' && desc.set._setClass) {
          desc.set._setClass(obj);
        }
      }
      return Object.defineProperty(prototype, name, desc);
    },
    delete: function(name) {
      return delete prototype[name];
    },
    fix: function() {
      return undefined;
    }
  });
}

function executeActions(actionsData, context, scope, assets) {
  var actionTracer = ActionTracerFactory.get();

  var scopeContainer = context.initialScope.create(scope);
  var savedContext = AS2Context.instance;
  try {
    AS2Context.instance = context;
    context.defaultTarget = scope;
    context.globals.asSetPublicProperty('this', scope);
    if (assets) {
      context.addAssets(assets);
    }
    actionTracer.message('ActionScript Execution Starts');
    actionTracer.indent();
    interpretActions(actionsData, scopeContainer, null, []);
  } finally {
    context.instructionsExecuted = 0;
    context.errorsIgnored = 0;

    actionTracer.unindent();
    actionTracer.message('ActionScript Execution Stops');
    AS2Context.instance = savedContext;
  }
}

function lookupAS2Children(targetPath, defaultTarget, root) {
  var path = targetPath.split(/[\/.]/g);
  if (path[path.length - 1] === '') {
    path.pop();
  }
  var obj = defaultTarget;
  if (path[0] === '' || path[0] === '_level0' || path[0] === '_root') {
    obj = root;
    path.shift();
  }
  while (path.length > 0) {
    var prevObj = obj;
    obj = obj.$lookupChild(path[0]);
    if (!obj) {
      throw new Error(path[0] + ' (expr ' + targetPath + ') is not found in ' +
                      prevObj._target);
    }
    path.shift();
  }
  return obj;
}

function createBuiltinType(obj, args) {
  if (obj === Array) {
    // special case of array
    var result = args;
    if (args.length == 1 && typeof args[0] === 'number') {
      result = [];
      result.length = args[0];
    }
    return result;
  }
  if (obj === Boolean || obj === Number || obj === String || obj === Function) {
    return obj.apply(null, args);
  }
  if (obj === Date) {
    switch (args.length) {
      case 0:
        return new Date();
      case 1:
        return new Date(args[0]);
      default:
        return new Date(args[0], args[1],
          args.length > 2 ? args[2] : 1,
          args.length > 3 ? args[3] : 0,
          args.length > 4 ? args[4] : 0,
          args.length > 5 ? args[5] : 0,
          args.length > 6 ? args[6] : 0);
    }
  }
  if (obj === Object) {
    return {};
  }
}

var AS2_SUPER_STUB = {};

function interpretActions(actionsData, scopeContainer,
                          constantPool, registers) {
  var currentContext = AS2Context.instance;

  function setTarget(targetPath) {
    if (!targetPath) {
      currentContext.defaultTarget = scope;
      return;
    }

    try {
      currentContext.defaultTarget =
        lookupAS2Children(targetPath, defaultTarget, _global.asGetPublicProperty('_root'));
    } catch (e) {
      currentContext.defaultTarget = null;
      throw e;
    }
  }

  function defineFunction(functionName, parametersNames,
                          registersAllocation, actionsData) {
    var ownerClass;
    var fn = (function() {
      var newScope = {};
      newScope.asSetPublicProperty('this', this);
      newScope.asSetPublicProperty('arguments', arguments);
      newScope.asSetPublicProperty('super', AS2_SUPER_STUB);
      newScope.asSetPublicProperty('__class', ownerClass);
      var newScopeContainer = scopeContainer.create(newScope);
      var i;

      for (i = 0; i < arguments.length || i < parametersNames.length; i++) {
        newScope[parametersNames[i]] = arguments[i];
      }
      var registers = [];
      if (registersAllocation) {
        for (i = 0; i < registersAllocation.length; i++) {
          var registerAllocation = registersAllocation[i];
          if (!registerAllocation) {
            continue;
          }
          if (registerAllocation.type == 'param') {
            registers[i] = arguments[registerAllocation.index];
          } else { // var
            switch (registerAllocation.name) {
              case 'this':
                registers[i] = this;
                break;
              case 'arguments':
                registers[i] = arguments;
                break;
              case 'super':
                registers[i] = AS2_SUPER_STUB;
                break;
              case '_global':
                registers[i] = _global;
                break;
              case '_parent':
                registers[i] = scope.asGetPublicProperty('_parent');
                break;
              case '_root':
                registers[i] = _global.asGetPublicProperty('_root');
                break;
            }
          }
        }
      }

      var savedContext = AS2Context.instance;
      var resetCounters;
      try
      {
        // switching contexts if called outside main thread
        AS2Context.instance = currentContext;
        resetCounters = currentContext.instructionsExecuted === 0;
        currentContext.defaultTarget = scope;
        actionTracer.indent();
        currentContext.stackDepth++;
        if (currentContext.stackDepth >= MAX_AVM1_STACK_LIMIT) {
          throw new AS2CriticalError('long running script -- AVM1 recursion limit is reached');
        }
        return interpretActions(actionsData, newScopeContainer,
          constantPool, registers);
      } finally {
        if (resetCounters) {
          currentContext.instructionsExecuted = 0;
          currentContext.errorsIgnored = 0;
        }
        currentContext.stackDepth--;
        actionTracer.unindent();
        currentContext.defaultTarget = defaultTarget;
        AS2Context.instance = savedContext;
      }
    });

    ownerClass = fn;
    fn._setClass = function (class_) {
      ownerClass = class_;
    };

    fn.instanceConstructor = fn;
    fn.debugName = 'avm1 ' + (functionName || '<function>');
    if (functionName) {
      fn.name = functionName;
    }
    return fn;
  }
  function deleteProperty(propertyName) {
    for (var p = scopeContainer; p; p = p.next) {
      if (p.scope.asHasProperty(undefined, propertyName, 0)) {
        p.scope.asSetPublicProperty(propertyName, undefined); // in some cases we need to cleanup events binding
        return p.scope.asDeleteProperty(undefined, propertyName, 0);
      }
    }
    return false;
  }
  function resolveVariableName(variableName, nonStrict) {
    var obj, name, i;
    if (variableName.indexOf(':') >= 0) {
      // "/A/B:FOO references the FOO variable in the movie clip with a target path of /A/B."
      var parts = variableName.split(':');
      obj = lookupAS2Children(parts[0], defaultTarget,
                              _global.asGetPublicProperty('_root'));
      if (!obj) {
        throw new Error(parts[0] + ' is undefined');
      }
      name = parts[1];
    } else if (variableName.indexOf('.') >= 0) {
      // new object reference
      var objPath = variableName.split('.');
      name = objPath.pop();
      obj = _global;
      for (i = 0; i < objPath.length; i++) {
        obj = obj.asGetPublicProperty(objPath[i]) || obj[objPath[i]];
        if (!obj) {
          throw new Error(objPath.slice(0, i + 1) + ' is undefined');
        }
      }
    }

    if (!obj) {
      return null; // local variable
    }

    var resolvedName = as2ResolveProperty(obj, name);
    var resolved = resolvedName !== null;
    if (resolved || nonStrict) {
      return { obj: obj, name: resolvedName || name, resolved: resolved };
    }

    return null;
  }
  function getThis() {
    var _this = scope.asGetPublicProperty('this');
    if (_this) {
      return _this;
    }
    for (var p = scopeContainer; p; p = p.next) {
      resolvedName = as2ResolveProperty(p.scope, 'this');
      if (resolvedName !== null) {
        return p.scope.asGetPublicProperty(resolvedName);
      }
    }
  }
  function getVariable(variableName) {
    // fast check if variable in the current scope
    if (scope.asHasProperty(undefined, variableName, 0)) {
      return scope.asGetPublicProperty(variableName);
    }

    var target = resolveVariableName(variableName);
    if (target) {
      return target.obj.asGetPublicProperty(target.name);
    }
    var resolvedName, _this = getThis();
    for (var p = scopeContainer; p; p = p.next) {
      resolvedName = as2ResolveProperty(p.scope, variableName);
      if (resolvedName !== null) {
        return p.scope.asGetPublicProperty(resolvedName);
      }
    }
    if(_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
      return _this.asGetPublicProperty(resolvedName);
    }
    // trying movie clip children (if object is a MovieClip)
    var mc = isAS2MovieClip(defaultTarget) &&
             defaultTarget.$lookupChild(variableName);
    if (mc) {
      return mc;
    }
  }

  function setVariable(variableName, value) {
    // fast check if variable in the current scope
    if (scope.asHasProperty(undefined, variableName, 0)) {
      scope.asSetPublicProperty(variableName, value);
      return;
    }

    var target = resolveVariableName(variableName, true);
    if (target) {
      target.obj.asSetPublicProperty(target.name, value);
      return;
    }
    var resolvedName, _this = getThis();
    if(_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
      return _this.asSetPublicProperty(resolvedName, value);
    }

    for (var p = scopeContainer; p.next; p = p.next) { // excluding globals
      resolvedName = as2ResolveProperty(p.scope, variableName);
      if (resolvedName !== null) {
        return p.scope.asSetPublicProperty(resolvedName, value);
      }
    }
    (_this || scope).asSetPublicProperty(variableName, value);
  }
  function getFunction(functionName) {
    var fn = getVariable(functionName);
    if (!(fn instanceof Function)) {
{'fraction_non_alphanumeric': 0.12687836293177954, 'fraction_numerical': 0.011151690875128942, 'mean_word_length': 2.686536485097636, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2937636', 'n_tokens_mistral': 11068, 'n_tokens_neox': 10887, 'n_words': 2627}