traceMessages = function (pObj) {
  arguments.callee.init(pObj);
  arguments.callee.execute(pObj);
  arguments.callee.exit();
}
//
o = traceMessages;
//
o.init = function (pObj) {
  this.arrFoundedObjects = new Array();
  //
  this.setFounded(pObj);
}
//
o.exit = function () {
  delete this.arrFoundedObject;
}
//
o.execute = function (pObj) {
  ASSetPropFlags(pObj, ['__proto__', 'prototype'], 0, 1);
  for (var p in pObj) {
    //
    var strType = typeof(pObj[p]);
    var obj = pObj[p];
    //
    if (!this.isContainer(obj)) continue;
    if (!pObj.hasOwnProperty(p)) continue;
    if (p == '__func__') continue;
    if (this.isFounded(obj)) continue;
    if (p == 'traceMessages') continue;
    //
    if (strType == 'object' || strType == 'movieclip') {
      this.setFounded(obj);
      arguments.callee.call(this, obj); // recursion
      continue;
    }
    //
    this.setFounded(obj);
    arguments.callee.call(this, obj); // recursion
    //
    var tmp = obj;
    pObj[p] = function () {
      trace('[call] ' + arguments.callee.__name__ +
        ' (called by ' + arguments.caller.__name__ + ')');
      return arguments.callee.__func__.apply(this, arguments);
    }
    pObj[p].__name__ = p;
    pObj[p].__func__ = tmp;
    pObj[p].__func__.__name__ = p;
  }
  ASSetPropFlags(pObj, ['__proto__', 'prototype'], 1, 0);
}
//
o.setFounded = function (pObj) {
  this.arrFoundedObjects.push(pObj);
}
//
o.isFounded = function (pObj) {
  for (var p in this.arrFoundedObjects) {
    if (this.arrFoundedObjects[p] == pObj) {
      return true;
    }
  }
  return false;
}
//
o.isContainer = function (pObj) {
  var strType = typeof(pObj);
  return (strType == 'object' || strType == 'function' || strType == 'movieclip');
}
//
delete o;


// test
traceMessages(_root);