/* -*- indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// Input is a bunch of file names and/or names of files from which to read file names.
//
// Output is a tree of classes derived from a root class (default GCFinalizedObject),
// with an annotation about whether it has an explicit destructor or not (line
// prefixed with "*").  Each class is printed with the file and line on which the
// definition starts.
//
// Assumes names are globally unique (namespaces don't matter).  Is tricked by macro
// definitions like in the Error objects, and by the use of the bitwise not operator
// in some cases:   "exception->flags &= ~Exception::SEEN_BY_DEBUGGER;"
//
// Furtermore there will be generated destructors for classes that have substructures,
// and those destructors won't be visible here.
//
// Usage:
//
//    avmshell gcClasses.abc -- [options] file ...
//
// Options:
//
//    --base classname  Specify the base class name, default GCFinalizedObject.
//               Useful values are GCObject, GCTraceableObject, and RCObject.
//
// Example:
//
//    find . -name '*.cpp' -o -name '*.h' > allfiles.txt
//    avmshell gcClasses.abc -- @allfiles.txt
//
// Example: (for TR, though not the player)
//
//    avmshell utils/gcClasses.abc -- $(find . -name '*.h' -o -name '*.cpp')
//
// Note the list of "excluded" paths below; those could be command line arguments but
// that's for later.

import avmplus.*;

// The root class could be a command line argument.

var rootclass = "GCFinalizedObject";

// Classes defined in files whose names match these regexes will not
// be printed, but will participate in the computation.

const ignorePaths =
    [ new RegExp("^.*/shell/.*$"),
     new RegExp("^.*/extensions/ST_.*$"),
     new RegExp("^.*/extensions/JavaGlue.*$"),
     new RegExp("^.*/MMgc/GCTests.*$")];

class LineInfo
{
    function LineInfo(_derived, _base, _filename, _lineno) {
        derived = _derived;
        base = _base;
        filename = _filename;
        lineno = _lineno;
    }
    var derived;            // name of the class being defined
    var base;               // name of its base class
    var filename;           // file where we found the definition of 'derived'
    var lineno;             // line where we found the definition of 'derived'
    var baseref = null;     // reference to the LineInfo for the base class
    var subrefs = [];       // list of known subclasses
    var destructor = false; // true if we believe this has a destructor
}

main(System.argv);

function main(args) {
    if (args.length > 0 && args[0] == "--base") {
        if (args.length > 1) {
            rootclass = args[1];
            args.shift();
            args.shift();
        }
        else
            throw new Error("Missing class name to --base");
    }
    printClasses(processQueue(readFiles(args)));
}

function readFiles(argv) {
    var filenames_dict = {};
    var probable_destructors = {};
    var all_lines = [];
    var re1 = new RegExp("class\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*:.*(?:public|private|virtual)\\s*([A-Za-z0-9_:]+)");
    var re2 = new RegExp("class\\s+GC_(?:AS3|CPP)_EXACT(?:[A-Z_]+)?\\(([^,\\)]+)\\s*,\\s*([^,\\)]+)");
    var red = new RegExp("~\s*([A-Za-z_][A-Za-z0-9_]*)");

    compute(argv,false);
    annotateDestructors();
    return all_lines;

    function annotateDestructors() {
        for ( var i=0 ; i < all_lines.length ; i++ ) {
            var ln = all_lines[i];
            ln.destructor = probable_destructors.hasOwnProperty(ln.derived);
        }
    }

    function compute(argv) {
        for ( var i=0 ; i < argv.length ; i++ ) {
            var arg=argv[i];
            if (arg.charAt(0) == '@')
                compute(readFile(arg.substring(1)));
            else if (newFile(arg))
                filterFile(arg);
        }
    }

    function newFile(fn) {
        return File.exists(fn) && !filenames_dict.hasOwnProperty(fn);
    }

    function filterFile(fn) {
        var lines = readFile(fn);
        var ignore = false;
        var ignorelevel = 0;
        for ( var i=0 ; i < lines.length ; i++ ) {
            var l = lines[i];
            var result;
            // Faster to filter by indexOf and then do regex matching than just regex matching.
            if (l.indexOf("#") != -1) {
                // Preprocessor macro?
                // We need to know the regions commented out by #ifdef DRC_TRIVIAL_DESTRUCTOR .. #endif
                // but we must track nested regions too.
                if (l.match(/^\s*#\s*(?:ifdef|ifndef|if|elif)/)) {
                    if (l.match(/^\s*#\s*ifdef\s+DRC_TRIVIAL_DESTRUCTOR/))
                        ignore = true;
                    if (ignore)
                        ignorelevel++;
                }
                else if (l.match(/^\s*#\s*endif/)) {
                    if (ignore) {
                        --ignorelevel;
                        if (ignorelevel == 0)
                            ignore = false;
                    }
                }
            }
            if (l.indexOf("class") != -1) {
                if ((result = l.match(re1)) || (result = l.match(re2))) {
                    var derived = result[1];
                    var base = stripNamespaces(result[2]);
                    all_lines.push(new LineInfo(derived,base,fn,i+1));
                }
            }
            else if (!ignore && l.indexOf("~") != -1) {
                if (result = l.match(red)) {
                    probable_destructors[result[1]] = true;
                }
            }
        }

        filenames_dict[fn] = true;
    }

    function stripNamespaces(name) {
        var x = name.lastIndexOf(":");
        return (x >= 0) ? name.substring(x+1) : name;
    }
}

function readFile(fn) {
    try {
        return File.read(fn).split("\n");
    }
    catch (e) {
        print("Can't open file \"" + "\"\n" + e);
        return [];
    }
}

function processQueue(lines) {
    var queue = [];     // Queue of classes to process
    var classes = {};   // Map of classes processed or in queue to their LineInfo

    queue.push(rootclass);
    classes[rootclass] = new LineInfo(rootclass, "", "(internal)", 0); // synthetic

    while (queue.length > 0) {
        var cls = queue.shift();
        for ( var l=0 ; l < lines.length ; l++ ) {
            var ln = lines[l];
            if (classes.hasOwnProperty(ln.base) && !classes.hasOwnProperty(ln.derived)) {
                var basecls = classes[ln.base];
                ln.baseref = basecls;
                basecls.subrefs.push(ln);
                classes[ln.derived] = ln;
                queue.push(ln.derived);
            }
        }
    }

    return classes;
}

function printClasses(classes) {
    printCls(classes[rootclass], 0);

    function printCls(cls, indent) {
        if (!ignoreIt(cls)) {
            var d = cls.destructor ? " * " : "   ";
            print(d + padTo50(spaces(indent) + cls.derived) + " " + cls.filename + ":" + cls.lineno);
        }
        cls.subrefs.sort(function (a,b) { return strcmp(a.derived, b.derived); })
        for ( var i=0 ; i < cls.subrefs.length ; i++ ) {
            var c = cls.subrefs[i];
            printCls(c, indent+2);
        }
    }

    function ignoreIt(cls) {
        for ( var i=0 ; i < ignorePaths.length ; i++ ) {
            if (cls.filename.match(ignorePaths[i]))
                return true;
        }
        return false;
    }

    function padTo50(s) {
        return (s.length >= 50) ? s : padTo50(s + " ");
    }

    function spaces(n) {
        return (n == 0) ? "" : " " + spaces(n-1);
    }

    function strcmp(a,b) {
        if (a < b) return -1;
        if (b < a) return 1;
        return 0;
    }
}

/* -*- indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// Input is a bunch of file names and/or names of files from which to read file names.
//
// Output is a tree of classes derived from a root class (default GCFinalizedObject),
// with per-class annotations:
//
//   - a "D" if the class has an explicit Destructor
//   - a "E" if the class is Exactly traced
//
// Each class is printed with the file and line on which the definition starts.
//
// At the end some statistics are printed.
//
// Assumes names are globally unique (namespaces don't matter).  Is tricked by macro
// definitions like in the Error objects, and by the use of the bitwise not operator
// in some cases:   "exception->flags &= ~Exception::SEEN_BY_DEBUGGER;"
//
// Furtermore there will be generated destructors for classes that have substructures,
// and those destructors won't be visible here.
//
// Usage:
//
//    avmshell gcClasses.abc -- [options] file ...
//
// Options:
//
//    --base classname  Specify the base class name, default GCFinalizedObject.
//               Useful values are GCObject, GCTraceableObject, and RCObject.
//
// Example:
//
//    find . -name '*.cpp' -o -name '*.h' > allfiles.txt
//    avmshell gcClasses.abc -- @allfiles.txt
//
// Example: (for TR, though not the player)
//
//    avmshell utils/gcClasses.abc -- $(find . -name '*.h' -o -name '*.cpp')
//
// Note the list of "excluded" paths below; those could be command line arguments but
// that's for later.

import avmplus.*;

// The root class could be a command line argument.

var rootclass = "GCFinalizedObject";

// Classes defined in files whose names match these regexes will not
// be printed, but will participate in the computation.

const ignorePaths =
    [ new RegExp("^.*/shell/.*$"),
     new RegExp("^.*/extensions/ST_.*$"),
     new RegExp("^.*/extensions/JavaGlue.*$"),
     new RegExp("^.*/eval/.*$"),
     new RegExp("^.*/MMgc/GCTests.*$")];

class LineInfo
{
    function LineInfo(_derived, _base, _isExact, _filename, _lineno) {
        derived = _derived;
        base = _base;
        isExact = _isExact;
        filename = _filename;
        lineno = _lineno;
    }

    public function toString() {
        return "derived=" + derived + ", base=" + base + ", filename=" + filename + ", lineno=" + lineno + ", defcount=" + defcount;
    }

    var derived;            // name of the class being defined
    var base;               // name of its base class
    var isExact;            // true iff the class is exactly traced
    var filename;           // file where we found the definition of 'derived'
    var lineno;             // line where we found the definition of 'derived'
    var baseref = null;     // reference to the LineInfo for the base class
    var subrefs = [];       // list of known subclasses
    var destructor = false; // true if we believe this has a destructor
    var defcount = 0;       // number of definitions
    var otherlines = [];    // for in-tree lines beyond the first: locations of definition: { filename:x, lineno:n }
    var exolines = [];      // for out-of-tree lines: locations of definition: { filename:x, lineno:n }
    var external = false;   // true if there are definitions of the 'derived' name not within the tree
}

main(System.argv);

function main(args) {
    if (args.length > 0 && args[0] == "--base") {
        if (args.length > 1) {
            rootclass = args[1];
            args.shift();
            args.shift();
        }
        else
            throw new Error("Missing class name to --base");
    }
    printClasses(processQueue(readFiles(args)));
}

function readFiles(argv) {
    var filenames_dict = {};
    var probable_destructors = {};
    var probable_tracers = {};
    var all_lines = [];
    // Hack, hack, hack
    var re1 = new RegExp("class\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*:.*(?:public|private|virtual)\\s*(?:MMgc\\s*::\\s*)?([A-Za-z0-9_:]+)");
    var re2 = new RegExp("class\\s+GC_(?:MANUAL|AS3|CPP)_EXACT(?:[A-Z_]+)?\\(([^,\\)]+)\\s*,\\s*([^,\\)]+)");
    var red = new RegExp("~\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*\\(");
    var red2 = new RegExp("virtual\\s*~\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*\\(.*\\)\\s*{\\s*}");
    var rtrace = new RegExp("([A-Za-z0-9_]+)\\s*::\\s*gcTrace");

    compute(argv,false);
    annotateDestructors();
    annotateTracers();
    return all_lines;

    function annotateDestructors() {
        for ( var i=0 ; i < all_lines.length ; i++ ) {
            var ln = all_lines[i];
            ln.destructor = probable_destructors.hasOwnProperty(ln.derived);
        }
    }

    function annotateTracers() {
        for ( var i=0 ; i < all_lines.length ; i++ ) {
            var ln = all_lines[i];
            ln.isExact = ln.isExact || probable_tracers.hasOwnProperty(ln.derived);
        }
    }

    function compute(argv) {
        for ( var i=0 ; i < argv.length ; i++ ) {
            var arg=argv[i];
            if (arg.charAt(0) == '@')
                compute(readFile(arg.substring(1)));
            else if (newFile(arg))
                filterFile(arg);
        }
    }

    function newFile(fn) {
        return File.exists(fn) && !filenames_dict.hasOwnProperty(fn);
    }

    function filterFile(fn) {
        var lines = readFile(fn);
        var ignore = false;
        var ignorelevel = 0;

        for ( var i=0 ; i < lines.length ; i++ ) {
            var l = lines[i];
            var result;
            // Faster to filter by indexOf and then do regex matching than just regex matching.
            if (l.indexOf("#") != -1) {
                // Preprocessor macro?
                // We need to know the regions commented out by #ifdef DRC_TRIVIAL_DESTRUCTOR .. #endif
                // but we must track nested regions too.
                if (l.match(/^\s*#\s*(?:ifdef|ifndef|if|elif)/)) {
                    if (l.match(/^\s*#\s*ifdef\s+DRC_TRIVIAL_DESTRUCTOR/))
                        ignore = true;
                    if (ignore)
                        ignorelevel++;
                }
                else if (l.match(/^\s*#\s*endif/)) {
                    if (ignore) {
                        --ignorelevel;
                        if (ignorelevel == 0)
                            ignore = false;
                    }
                }
            }

            if (l.indexOf("class") != -1) {
                var found = 0;
                // Order matters because we want commented-out "class GC_MANUAL_EXACT( ..." to take precedence
                // over the actual definition when we build the class tree.
                if ((result = l.match(re2)) != null)
                    found = 2;
                else if ((result = l.match(re1)) != null)
                    found = 1;
                if (found) {
                    var derived = result[1];
                    var base = stripNamespaces(result[2]);
                    all_lines.push(new LineInfo(derived,base,found==2,fn,i+1));
                }
            }
            else if (!ignore && l.indexOf("~") != -1) {
                if (result = l.match(red)) {
                    if (!l.match(red2)) // filter out trivial destructors
                        probable_destructors[result[1]] = true;
                }
            }
            else if (!ignore && l.indexOf("gcTrace") != -1) {
                if (result = l.match(rtrace)) {
                    probable_tracers[result[1]] = true;
                }
            }
        }

        filenames_dict[fn] = true;
    }

    function stripNamespaces(name) {
        var x = name.lastIndexOf(":");
        return (x >= 0) ? name.substring(x+1) : name;
    }
}

function readFile(fn) {
    try {
        return File.read(fn).split("\n");
    }
    catch (e) {
        print("Can't open file \"" + "\"\n" + e);
        return [];
    }
}

function processQueue(lines) {
    var queue = [];     // Queue of classes to process
    var classes = {};   // Map of classes processed or in queue to their LineInfo

    queue.push(rootclass);
    classes[rootclass] = new LineInfo(rootclass, "", false, "(internal)", 0); // synthetic

    while (queue.length > 0) {
        var cls = queue.shift();
        for ( var l=0 ; l < lines.length ; l++ ) {
            var ln = lines[l];
            if (classes.hasOwnProperty(ln.base)) {
                if (!classes.hasOwnProperty(ln.derived)) {
                    var basecls = classes[ln.base];
                    ln.baseref = basecls;
                    basecls.subrefs.push(ln);
                    classes[ln.derived] = ln;
                    ln.defcount = 1;
                    queue.push(ln.derived);
                }
                else {
                    // Flag it as used, but it's not canonical because
                    // it's not in the classes table.
                    ln.defcount = 1;
                }
            }
        }
    }

    // Compute lines for multiple in-tree definitions, and attributes for not-within-tree definitions

    for ( var l=0 ; l < lines.length ; l++ ) {
        var ln = lines[l];
        if (ln.defcount > 0 && classes.hasOwnProperty(ln.derived)) {
            var c = classes[ln.derived];
            if (c !== ln) {
                c.defcount++;
                c.otherlines.push({filename: ln.filename, lineno: ln.lineno});
            }
        }
        if (ln.defcount == 0 && classes.hasOwnProperty(ln.derived)) {
            var c = classes[ln.derived];
            c.external = true;
            c.exolines.push({filename: ln.filename, lineno: ln.lineno});
        }
    }

    return classes;
}

function printClasses(classes) {
    var destructors = 0;
    var exacts = 0;
    var classcount = 0;

    print("Legend:");
    print("  D - at least one of the definitions has an explicit destructor");
    print("  E - at least one of the definitions is exactly traced");
    print("  M - multiple definitions in the tree (in different namespaces or nested within classes)");
    print("  # - continuation line for M with additional locations");
    print("  X - definitions of the same name exist outside the tree");
    print("  @ - continuation line for @ with locations");
    print("");

    printCls(classes[rootclass], 0);
    print("");
    print("Classes: " + classcount);
    print("Explicit destructors: " + destructors);
    print("Exactly traced: " + exacts + " (" + Math.round(exacts/classcount*100) + "%)");

    function printCls(cls, indent) {
        if (!ignoreIt(cls)) {
            classcount++;
            if (cls.destructor) destructors++;
            if (cls.isExact) exacts++;
            var d = " " + (cls.destructor ? "D" : " ") + (cls.isExact ? "E" : " ") + (cls.defcount > 1 ? "M" : " ") + (cls.external ? "X" : " ") + "  ";
            print(d + padTo50(spaces(indent) + cls.derived) + " " + cls.filename + ":" + cls.lineno);
            if (cls.defcount > 1) {
                var locs = cls.otherlines;
                for ( var l=0 ; l < locs.length ; l++ )
                    print("   #    " + padTo50("") + locs[l].filename + ":" + locs[l].lineno);
            }
            if (cls.external) {
                var locs = cls.exolines;
                for ( var l=0 ; l < locs.length ; l++ )
                    print("    @   " + padTo50("") + locs[l].filename + ":" + locs[l].lineno);
            }
        }
        cls.subrefs.sort(function (a,b) { return strcmp(a.derived, b.derived); })
        for ( var i=0 ; i < cls.subrefs.length ; i++ ) {
            var c = cls.subrefs[i];
            printCls(c, indent+2);
        }
    }

    function ignoreIt(cls) {
        for ( var i=0 ; i < ignorePaths.length ; i++ ) {
            if (cls.filename.match(ignorePaths[i]))
                return true;
        }
        return false;
    }

    function padTo50(s) {
        return (s.length >= 50) ? s : padTo50(s + " ");
    }

    function spaces(n) {
        return (n == 0) ? "" : " " + spaces(n-1);
    }

    function strcmp(a,b) {
        if (a < b) return -1;
        if (b < a) return 1;
        return 0;
    }
}

Update the gcClasses script to handle multiple definitions, out-of-tree definitions, and to filter trivial destructors and non-destructors (r=lhansen)


/*
 * Copyright 2008 Adobe Systems Inc., 2008 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.
 *
 * Contributor(s):
 *   Zwetan Kjukov <zwetan@gmail.com>.
 *   Marc Alcaraz <ekameleon@gmail.com>.
 */

package com.google.analytics
{
    import com.google.analytics.core.Buffer;
    import com.google.analytics.core.EventTracker;
    import com.google.analytics.core.GIFRequest;
    import com.google.analytics.core.IdleTimer;
    import com.google.analytics.core.ServerOperationMode;
    import com.google.analytics.core.TrackerCache;
    import com.google.analytics.core.TrackerMode;
    import com.google.analytics.core.ga_internal;
    import com.google.analytics.debug.DebugConfiguration;
    import com.google.analytics.debug.Layout;
    import com.google.analytics.events.AnalyticsEvent;
    import com.google.analytics.external.AdSenseGlobals;
    import com.google.analytics.external.HTMLDOM;
    import com.google.analytics.external.JavascriptProxy;
    import com.google.analytics.utils.Environment;
    import com.google.analytics.utils.Version;
    import com.google.analytics.v4.Bridge;
    import com.google.analytics.v4.Configuration;
    import com.google.analytics.v4.GoogleAnalyticsAPI;
    import com.google.analytics.v4.Tracker;

    import flash.display.DisplayObject;
    import flash.events.Event;
    import flash.events.EventDispatcher;

    /* force import for type in the includes */
    EventTracker;
    ServerOperationMode;

    /**
     * Dispatched after the factory has built the tracker object.
     * @eventType com.google.analytics.events.AnalyticsEvent.READY
     */
    [Event(name="ready", type="com.google.analytics.events.AnalyticsEvent")]

    /**
     * Google Analytic Tracker Code (GATC)'s code-only component.
     */
    public class GATracker implements AnalyticsTracker
    {
        private var _ready:Boolean = false;

        private var _display:DisplayObject;
        private var _eventDispatcher:EventDispatcher;
        private var _tracker:GoogleAnalyticsAPI;

        //factory
        private var _config:Configuration;
        private var _debug:DebugConfiguration;
        private var _env:Environment;
        private var _buffer:Buffer;
        private var _gifRequest:GIFRequest;
        private var _jsproxy:JavascriptProxy;
        private var _dom:HTMLDOM;
        private var _adSense:AdSenseGlobals;

        //object properties
        private var _account:String;
        private var _mode:String;
        private var _visualDebug:Boolean;

        /**
         * Indicates if the tracker is automatically build.
         */
        public static var autobuild:Boolean = true;

        /**
         * The version of the tracker.
         */
        public static var version:Version = API.version;

        /**
         * Creates a new GATracker instance.
         *
Note: the GATracker need to be instancied and added to the Stage or at least
         * being placed in a display list.

         */
        public function GATracker( display:DisplayObject, account:String,
                                   mode:String = "AS3", visualDebug:Boolean = false,
                                   config:Configuration = null, debug:DebugConfiguration = null )
        {
            _display = display;
            _eventDispatcher = new EventDispatcher( this ) ;
            _tracker = new TrackerCache();

            this.account     = account;
            this.mode        = mode;
            this.visualDebug = visualDebug;

            if( !debug )
            {
                this.debug = new DebugConfiguration();
            }

            if( !config )
            {
                this.config = new Configuration( debug );
            }

            if( autobuild )
            {
                _factory();
            }
        }

        /**
         * @private
         * Factory to build the different trackers
         */
        private function _factory():void
        {
            _jsproxy = new JavascriptProxy( debug );

            if( visualDebug )
            {
                debug.layout = new Layout( debug, _display );
                debug.active = visualDebug;
            }

            var activeTracker:GoogleAnalyticsAPI;
            var cache:TrackerCache = _tracker as TrackerCache;

            switch( mode )
            {
                case TrackerMode.BRIDGE :
                {
                    activeTracker = _bridgeFactory();
                    break;
                }

                case TrackerMode.AS3 :
                default:
                {
                    activeTracker = _trackerFactory();
                }
            }

            if( !cache.isEmpty() )
            {
                cache.tracker = activeTracker;
                cache.flush();
            }

            _tracker = activeTracker;

            _ready = true;
            dispatchEvent( new AnalyticsEvent( AnalyticsEvent.READY, this ) );
        }

        /**
        * @private
        * Factory method for returning a Tracker object.
        *
        * @return {GoogleAnalyticsAPI}
        */
        private function _trackerFactory():GoogleAnalyticsAPI
        {
            debug.info( "GATracker (AS3) v" + version +"\naccount: " + account );

            /* note:
               for unit testing and to avoid 2 different branches AIR/Flash
               here we will detect if we are in the Flash Player or AIR
               and pass the infos to the LocalInfo

               By default we will define "Flash" for our local tests
            */

            _adSense   = new AdSenseGlobals( debug );

            _dom        = new HTMLDOM( debug );
            _dom.cacheProperties();

            _env        = new Environment( "", "", "", debug, _dom );

            _buffer     = null;
            _gifRequest = null;

            /* note:
               To be able to obtain the URL of the main SWF containing the GA API
               we need to be able to access the stage property of a DisplayObject,
               here we open the internal namespace to be able to set that reference
               at instanciation-time.

               We keep the implementation internal to be able to change it if required later.
            */
            use namespace ga_internal;
            _env.url = _display.stage.loaderInfo.url;

            return new Tracker( account, config, debug, _env, _buffer, _gifRequest, _adSense, _display );
        }

        /**
        * @private
        * Factory method for returning a Bridge object.
        *
        * @return {GoogleAnalyticsAPI}
        */
        private function _bridgeFactory():GoogleAnalyticsAPI
        {
            debug.info( "GATracker (Bridge) v" + version +"\naccount: " + account );
            return new Bridge( account, _debug, _jsproxy );
        }

        /**
         * Indicates the account value of the tracking.
         */
        public function get account():String
        {
            return _account;
        }

        /**
         * @private
         */
        public function set account( value:String ):void
        {
            _account = value;
        }

        /**
         * Determinates the Configuration object of the tracker.
         */
        public function get config():Configuration
        {
            return _config;
        }

        /**
         * @private
         */
        public function set config( value:Configuration ):void
        {
            _config = value;
        }

        /**
         * Determinates the DebugConfiguration of the tracker.
         */
        public function get debug():DebugConfiguration
        {
            return _debug;
        }

        /**
         * @private
         */
        public function set debug( value:DebugConfiguration ):void
        {
            _debug = value;
        }

        /**
         * Indicates if the tracker is ready to use.
         */
        public function isReady():Boolean
        {
            return _ready;
        }

        /**
         * Indicates the mode of the tracking "AS3" or "Bridge".
         */
        public function get mode():String
        {
            return _mode;
        }

        /**
         * @private
         */
        public function set mode( value:String ):void
        {
            _mode = value ;
        }

        /**
         * Indicates if the tracker use a visual debug.
         */
        public function get visualDebug():Boolean
        {
            return _visualDebug;
        }

        /**
         * @private
         */
        public function set visualDebug( value:Boolean ):void
        {
            _visualDebug = value;
        }

        /**
         * Builds the tracker.
         */
        public function build():void
        {
            if( !isReady() )
            {
                _factory();
            }
        }

        // IEventDispatcher implementation

        /**
         * Allows the registration of event listeners on the event target.
         * @param type A string representing the event type to listen for. If eventName value is "ALL" addEventListener use addGlobalListener
         * @param listener The Function that receives a notification when an event of the specified type occurs.
         * @param useCapture Determinates if the event flow use capture or not.
         * @param priority Determines the priority level of the event listener.
         * @param useWeakReference Indicates if the listener is a weak reference.
         */
        public function addEventListener( type:String, listener:Function, useCapture:Boolean = false, priority:int = 0,
                                          useWeakReference:Boolean = false):void
        {
            _eventDispatcher.addEventListener( type, listener, useCapture, priority, useWeakReference );
        }

        /**
         * Dispatches an event into the event flow.
         * @param event The Event object that is dispatched into the event flow.
         * @return true if the Event is dispatched.
         */
        public function dispatchEvent( event:Event ):Boolean
        {
            return _eventDispatcher.dispatchEvent( event );
        }

        /**
         * Checks whether the EventDispatcher object has any listeners registered for a specific type of event.
         * This allows you to determine where altered handling of an event type has been introduced in the event flow heirarchy by an EventDispatcher object.
         */
        public function hasEventListener( type:String ):Boolean
        {
            return _eventDispatcher.hasEventListener( type );
        }

        /**
         * Removes a listener from the EventDispatcher object.
         * If there is no matching listener registered with the EventDispatcher object, then calling this method has no effect.
         * @param type Specifies the type of event.
         * @param listener The Function that receives a notification when an event of the specified type occurs.
         * @param useCapture Determinates if the event flow use capture or not.
         */
        public function removeEventListener( type:String, listener:Function, useCapture:Boolean = false ):void
        {
            _eventDispatcher.removeEventListener( type, listener, useCapture );
        }

        /**
         * Checks whether an event listener is registered with this EventDispatcher object or any of its ancestors for the specified event type.
         * This method returns true if an event listener is triggered during any phase of the event flow when an event of the specified type is dispatched to this EventDispatcher object or any of its descendants.
         * @return A value of true if a listener of the specified type will be triggered; false otherwise.
         */
        public function willTrigger( type:String ):Boolean
        {
            return _eventDispatcher.willTrigger( type );
        }

        include "common.txt"

    }
}

/*
 * Copyright 2008 Adobe Systems Inc., 2008 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.
 *
 * Contributor(s):
 *   Zwetan Kjukov <zwetan@gmail.com>.
 *   Marc Alcaraz <ekameleon@gmail.com>.
 */

package com.google.analytics
{
    import com.google.analytics.core.Buffer;
    import com.google.analytics.core.EventTracker;
    import com.google.analytics.core.GIFRequest;
    import com.google.analytics.core.ServerOperationMode;
    import com.google.analytics.core.TrackerCache;
    import com.google.analytics.core.TrackerMode;
    import com.google.analytics.core.ga_internal;
    import com.google.analytics.debug.DebugConfiguration;
    import com.google.analytics.debug.Layout;
    import com.google.analytics.events.AnalyticsEvent;
    import com.google.analytics.external.AdSenseGlobals;
    import com.google.analytics.external.HTMLDOM;
    import com.google.analytics.external.JavascriptProxy;
    import com.google.analytics.utils.Environment;
    import com.google.analytics.utils.Version;
    import com.google.analytics.v4.Bridge;
    import com.google.analytics.v4.Configuration;
    import com.google.analytics.v4.GoogleAnalyticsAPI;
    import com.google.analytics.v4.Tracker;

    import flash.display.DisplayObject;
    import flash.events.Event;
    import flash.events.EventDispatcher;

    /* force import for type in the includes */
    EventTracker;
    ServerOperationMode;

    /**
     * Dispatched after the factory has built the tracker object.
     * @eventType com.google.analytics.events.AnalyticsEvent.READY
     */
    [Event(name="ready", type="com.google.analytics.events.AnalyticsEvent")]

    /**
     * Google Analytic Tracker Code (GATC)'s code-only component.
     */
    public class GATracker implements AnalyticsTracker
    {
        private var _ready:Boolean = false;

        private var _display:DisplayObject;
        private var _eventDispatcher:EventDispatcher;
        private var _tracker:GoogleAnalyticsAPI;

        //factory
        private var _config:Configuration;
        private var _debug:DebugConfiguration;
        private var _env:Environment;
        private var _buffer:Buffer;
        private var _gifRequest:GIFRequest;
        private var _jsproxy:JavascriptProxy;
        private var _dom:HTMLDOM;
        private var _adSense:AdSenseGlobals;

        //object properties
        private var _account:String;
        private var _mode:String;
        private var _visualDebug:Boolean;

        /**
         * Indicates if the tracker is automatically build.
         */
        public static var autobuild:Boolean = true;

        /**
         * The version of the tracker.
         */
        public static var version:Version = API.version;

        /**
         * Creates a new GATracker instance.
         *
Note: the GATracker need to be instancied and added to the Stage or at least
         * being placed in a display list.

         */
        public function GATracker( display:DisplayObject, account:String,
                                   mode:String = "AS3", visualDebug:Boolean = false,
                                   config:Configuration = null, debug:DebugConfiguration = null )
        {
            _display = display;
            _eventDispatcher = new EventDispatcher( this ) ;
            _tracker = new TrackerCache();

            this.account     = account;
            this.mode        = mode;
            this.visualDebug = visualDebug;

            if( !debug )
            {
                this.debug = new DebugConfiguration();
            }

            if( !config )
            {
                this.config = new Configuration( debug );
            }

            if( autobuild )
            {
                _factory();
            }
        }

        /**
         * @private
         * Factory to build the different trackers
         */
        private function _factory():void
        {
            _jsproxy = new JavascriptProxy( debug );

            if( visualDebug )
            {
                debug.layout = new Layout( debug, _display );
                debug.active = visualDebug;
            }

            var activeTracker:GoogleAnalyticsAPI;
            var cache:TrackerCache = _tracker as TrackerCache;

            switch( mode )
            {
                case TrackerMode.BRIDGE :
                {
                    activeTracker = _bridgeFactory();
                    break;
                }

                case TrackerMode.AS3 :
                default:
                {
                    activeTracker = _trackerFactory();
                }
            }

            if( !cache.isEmpty() )
            {
                cache.tracker = activeTracker;
                cache.flush();
            }

            _tracker = activeTracker;

            _ready = true;
            dispatchEvent( new AnalyticsEvent( AnalyticsEvent.READY, this ) );
        }

        /**
        * @private
        * Factory method for returning a Tracker object.
        *
        * @return {GoogleAnalyticsAPI}
        */
        private function _trackerFactory():GoogleAnalyticsAPI
        {
            debug.info( "GATracker (AS3) v" + version +"\naccount: " + account );

            /* note:
               for unit testing and to avoid 2 different branches AIR/Flash
               here we will detect if we are in the Flash Player or AIR
               and pass the infos to the LocalInfo

               By default we will define "Flash" for our local tests
            */

            _adSense   = new AdSenseGlobals( debug );

            _dom        = new HTMLDOM( debug );
            _dom.cacheProperties();

            _env        = new Environment( "", "", "", debug, _dom );

            _buffer     = null;
            _gifRequest = null;

            /* note:
               To be able to obtain the URL of the main SWF containing the GA API
               we need to be able to access the stage property of a DisplayObject,
               here we open the internal namespace to be able to set that reference
               at instanciation-time.

               We keep the implementation internal to be able to change it if required later.
            */
            use namespace ga_internal;
            _env.url = _display.stage.loaderInfo.url;

            return new Tracker( account, config, debug, _env, _buffer, _gifRequest, _adSense, _display );
        }

        /**
        * @private
        * Factory method for returning a Bridge object.
        *
        * @return {GoogleAnalyticsAPI}
        */
        private function _bridgeFactory():GoogleAnalyticsAPI
        {
            debug.info( "GATracker (Bridge) v" + version +"\naccount: " + account );
            return new Bridge( account, _debug, _jsproxy );
        }

        /**
         * Indicates the account value of the tracking.
         */
        public function get account():String
        {
            return _account;
        }

        /**
         * @private
         */
        public function set account( value:String ):void
        {
            _account = value;
        }

        /**
         * Determinates the Configuration object of the tracker.
         */
        public function get config():Configuration
        {
            return _config;
        }

        /**
         * @private
         */
        public function set config( value:Configuration ):void
        {
            _config = value;
        }

        /**
         * Determinates the DebugConfiguration of the tracker.
         */
        public function get debug():DebugConfiguration
        {
            return _debug;
        }

        /**
         * @private
         */
        public function set debug( value:DebugConfiguration ):void
        {
            _debug = value;
        }

        /**
         * Indicates if the tracker is ready to use.
         */
        public function isReady():Boolean
        {
            return _ready;
        }

        /**
         * Indicates the mode of the tracking "AS3" or "Bridge".
         */
        public function get mode():String
        {
            return _mode;
        }

        /**
         * @private
         */
        public function set mode( value:String ):void
        {
            _mode = value ;
        }

        /**
         * Indicates if the tracker use a visual debug.
         */
        public function get visualDebug():Boolean
        {
            return _visualDebug;
        }

        /**
         * @private
         */
        public function set visualDebug( value:Boolean ):void
        {
            _visualDebug = value;
        }

        /**
         * Builds the tracker.
         */
        public function build():void
        {
            if( !isReady() )
            {
                _factory();
            }
        }

        // IEventDispatcher implementation

        /**
         * Allows the registration of event listeners on the event target.
         * @param type A string representing the event type to listen for. If eventName value is "ALL" addEventListener use addGlobalListener
         * @param listener The Function that receives a notification when an event of the specified type occurs.
         * @param useCapture Determinates if the event flow use capture or not.
         * @param priority Determines the priority level of the event listener.
         * @param useWeakReference Indicates if the listener is a weak reference.
         */
        public function addEventListener( type:String, listener:Function, useCapture:Boolean = false, priority:int = 0,
                                          useWeakReference:Boolean = false):void
        {
            _eventDispatcher.addEventListener( type, listener, useCapture, priority, useWeakReference );
        }

        /**
         * Dispatches an event into the event flow.
         * @param event The Event object that is dispatched into the event flow.
         * @return true if the Event is dispatched.
         */
        public function dispatchEvent( event:Event ):Boolean
        {
            return _eventDispatcher.dispatchEvent( event );
        }

        /**
         * Checks whether the EventDispatcher object has any listeners registered for a specific type of event.
         * This allows you to determine where altered handling of an event type has been introduced in the event flow heirarchy by an EventDispatcher object.
         */
        public function hasEventListener( type:String ):Boolean
        {
            return _eventDispatcher.hasEventListener( type );
        }

        /**
         * Removes a listener from the EventDispatcher object.
         * If there is no matching listener registered with the EventDispatcher object, then calling this method has no effect.
         * @param type Specifies the type of event.
         * @param listener The Function that receives a notification when an event of the specified type occurs.
         * @param useCapture Determinates if the event flow use capture or not.
         */
        public function removeEventListener( type:String, listener:Function, useCapture:Boolean = false ):void
        {
            _eventDispatcher.removeEventListener( type, listener, useCapture );
        }

        /**
         * Checks whether an event listener is registered with this EventDispatcher object or any of its ancestors for the specified event type.
         * This method returns true if an event listener is triggered during any phase of the event flow when an event of the specified type is dispatched to this EventDispatcher object or any of its descendants.
         * @return A value of true if a listener of the specified type will be triggered; false otherwise.
         */
        public function willTrigger( type:String ):Boolean
        {
            return _eventDispatcher.willTrigger( type );
        }

        include "common.txt"

    }
}

Fix GATracker import

Fix GATracker import


/* Vivified
 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

/*** general objects ***/

Wrap = function () {};
Wrap.prototype = {};
Wrap.prototype.toString = Native.wrap_toString;

Frame = function () extends Wrap {};
Frame.prototype = new Wrap ();
Frame.prototype.addProperty ("code", Native.frame_code_get, null);
Frame.prototype.addProperty ("name", Native.frame_name_get, null);
Frame.prototype.addProperty ("next", Native.frame_next_get, null);

/*** breakpoints ***/

Breakpoint = function () extends Native.Breakpoint {
  super ();
  Breakpoint.list.push (this);
};
Breakpoint.list = new Array ();
Breakpoint.prototype.addProperty ("active", Native.breakpoint_active_get, Native.breakpoint_active_set);

/*** information about the player ***/

Player = {};
Player.addProperty ("frame", Native.player_frame_get, null);

/*** commands available for debugging ***/

Commands = new Object ();
Commands.print = Native.print;
Commands.error = Native.error;
Commands.r = Native.run;
Commands.run = Native.run;
Commands.halt = Native.stop;
Commands.stop = Native.stop;
Commands.s = Native.step;
Commands.step = Native.step;
Commands.reset = Native.reset;
Commands.restart = function () {
  Commands.reset ();
  Commands.run ();
};
Commands.quit = Native.quit;
/* can't use "break" as a function name, it's a keyword in JS */
Commands.add = function (name) {
  if (name == undefined) {
    Commands.error ("add command requires a function name");
    return undefined;
  }
  var ret = new Breakpoint ();
  ret.onStartFrame = function (frame) {
    if (frame.name != name)
      return false;

    Commands.print ("Breakpoint: function " + name + " called");
    Commands.print ("  " + frame);
    return true;
  };
  ret.toString = function () {
    return "function call " + name;
  };
  return ret;
};
Commands.list = function () {
  var a = Breakpoint.list;
  var i;
  for (i = 0; i < a.length; i++) {
    Commands.print (i + ": " + a[i]);
  }
};
Commands.del = function (id) {
  var a = Breakpoint.list;
  if (id == undefined) {
    while (a[0])
      Commands.del (0);
  }
  var b = a[id];
  a.splice (id, 1);
  b.active = false;
};
Commands.delete = Commands.del;
Commands.where = function () {
  var frame = Player.frame;
  if (frame == undefined) {
    print ("---");
    return;
  }
  while (frame) {
    print (frame);
    frame = frame.next;
  }
};
Commands.backtrace = Commands.where;
Commands.bt = Commands.where;

add backtrace function

add backtrace function


/*
 * An exmaple app for Twitter for AS3
 *
 * copyright (c) 2015 Susisu
 */

package
{

    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.net.navigateToURL;
    import flash.net.URLRequest;

    import isle.susisu.twitter.Twitter;
    import isle.susisu.twitter.TwitterRequest;
    import isle.susisu.twitter.events.TwitterRequestEvent;
    import isle.susisu.twitter.events.TwitterErrorEvent;

    [SWF(width="480", height="360", backgroundColor="0x000000", frameRate="60")]
    public class ExampleApp extends Sprite
    {

        private var outputConsole:TextField;
        private var openBrowserButton:Sprite;
        private var pinInputField:TextField;
        private var getAccessTokenButton:Sprite;
        private var tweetInputField:TextField;
        private var tweetButton:Sprite;

        private var twitter:Twitter;

        public function ExampleApp()
        {
            // Replace <consumer key> and <consumer key secret> with your app's
            this.twitter = new Twitter("<consumer key>","<consumer key secret>");

            // Create UI
            // Output console
            this.outputConsole = new TextField();
            this.outputConsole.width = 480;
            this.outputConsole.height = 180;
            this.outputConsole.border = true;
            this.outputConsole.background = true;
            this.outputConsole.backgroundColor = 0xffffff;
            this.outputConsole.text = "";
            this.addChild(this.outputConsole);

            // "Open browser" button
            this.openBrowserButton = new Sprite();
            var openBrowserButtonText:TextField = new TextField();
            openBrowserButtonText.width = 80;
            openBrowserButtonText.height = 20;
            openBrowserButtonText.background = true;
            openBrowserButtonText.backgroundColor = 0xc0c0c0;
            openBrowserButtonText.border = true;
            openBrowserButtonText.text = "Open browser";
            this.openBrowserButton.addChild(openBrowserButtonText);
            this.openBrowserButton.y = 180;
            this.openBrowserButton.buttonMode = true;
            this.openBrowserButton.mouseChildren = false;
            this.addChild(this.openBrowserButton);
            this.openBrowserButton.addEventListener(MouseEvent.CLICK, onOpenBrowserButtonClick);

            // PIN input field
            this.pinInputField = new TextField();
            this.pinInputField.x = 80;
            this.pinInputField.y = 180;
            this.pinInputField.width = 200;
            this.pinInputField.height = 20;
            this.pinInputField.background = true;
            this.pinInputField.backgroundColor = 0xffffff;
            this.pinInputField.border = true;
            this.pinInputField.type = TextFieldType.INPUT;
            this.pinInputField.text = "Input PIN here";
            this.addChild(this.pinInputField);

            // "Get access token" button
            this.getAccessTokenButton = new Sprite();
            var getAccessTokenButtonText:TextField = new TextField();
            getAccessTokenButtonText.width = 200;
            getAccessTokenButtonText.height = 20;
            getAccessTokenButtonText.background = true;
            getAccessTokenButtonText.backgroundColor = 0xc0c0c0;
            getAccessTokenButtonText.border = true;
            getAccessTokenButtonText.text = "Get access tokens";
            this.getAccessTokenButton.addChild(getAccessTokenButtonText);
            this.getAccessTokenButton.x = 280;
            this.getAccessTokenButton.y = 180;
            this.getAccessTokenButton.buttonMode = true;
            this.getAccessTokenButton.mouseChildren = false;
            this.addChild(this.getAccessTokenButton);
            this.getAccessTokenButton.addEventListener(MouseEvent.CLICK, onGetAccessTokenButtonClick);

            // Tweet input field
            this.tweetInputField = new TextField();
            this.tweetInputField.y = 200;
            this.tweetInputField.width = 480;
            this.tweetInputField.height = 140;
            this.tweetInputField.background = true;
            this.tweetInputField.backgroundColor = 0xffffff;
            this.tweetInputField.border = true;
            this.tweetInputField.type = TextFieldType.INPUT;
            this.tweetInputField.text = "Input your tweet here"
            this.addChild(this.tweetInputField);

            // Tweet button
            this.tweetButton = new Sprite();
            var tweetButtonText:TextField = new TextField();
            tweetButtonText.width = 480;
            tweetButtonText.height = 20;
            tweetButtonText.background = true;
            tweetButtonText.backgroundColor = 0xc0c0c0;
            tweetButtonText.border = true;
            tweetButtonText.text = "Tweet";
            this.tweetButton.addChild(tweetButtonText);
            this.tweetButton.y = 340;
            this.tweetButton.buttonMode = true;
            this.tweetButton.mouseChildren = false;
            this.addChild(this.tweetButton);
            this.tweetButton.addEventListener(MouseEvent.CLICK, onTweetButtonClick);

            this.outputConsole.appendText("1. Click \"open browser\" button\n2. Authorize the app and get PIN\n3. Input PIN\n4. Get access tokens\n5. Tweet!\n");
        }

        // When the "open browser" button is clicked
        private function onOpenBrowserButtonClick(event:MouseEvent):void
        {
            var request:TwitterRequest = this.twitter.oauth_requestToken();

            request.addEventListener(TwitterRequestEvent.COMPLETE, onOAuthRequestTokenComplete);
            request.addEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthRequestTokenError);
            request.addEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthRequestTokenError);
            this.outputConsole.appendText("Please wait...\n");
        }

        // When oauth/request_token is complete
        private function onOAuthRequestTokenComplete(event:TwitterRequestEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthRequestTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthRequestTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthRequestTokenError);

            // Open the authorization page in browser
            navigateToURL(new URLRequest(this.twitter.getOAuthAuthorizeURL()));

            this.outputConsole.appendText("Borwser opened: " + this.twitter.getOAuthAuthorizeURL() + "\n");
        }

        // When oauth/request_token failed
        private function onOAuthRequestTokenError(event:TwitterErrorEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthRequestTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthRequestTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthRequestTokenError);

            this.outputConsole.appendText("Error: " + event.statusCode.toString() + "\n");
        }

        // When the "access token" button is clicked
        private function onGetAccessTokenButtonClick(event:MouseEvent):void
        {
            // Send PIN
            var request:TwitterRequest = this.twitter.oauth_accessToken(this.pinInputField.text);

            request.addEventListener(TwitterRequestEvent.COMPLETE, onOAuthAccessTokenComplete);
            request.addEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthAccessTokenError);
            request.addEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthAccessTokenError);

            this.outputConsole.appendText("Please wait...\n");
        }

        // When oauth/access_token is complete
        private function onOAuthAccessTokenComplete(event:TwitterRequestEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthAccessTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthAccessTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthAccessTokenError);

            this.pinInputField.text = "";

            // Output the access token to the console
            this.outputConsole.appendText("Access token: " + this.twitter.accessToken + "\n");
            this.outputConsole.appendText("Access token secret: " + this.twitter.accessTokenSecret + "\n");
        }

        // When oauth/access_token failed
        private function onOAuthAccessTokenError(event:TwitterErrorEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthAccessTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthAccessTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthAccessTokenError);

            this.outputConsole.appendText("Error: " + event.statusCode.toString() + "\n");
        }

        // When the tweet button is clicked
        private function onTweetButtonClick(event:MouseEvent):void
        {
            // Send tweet
            var request:TwitterRequest = this.twitter.statuses_update(this.tweetInputField.text);

            request.addEventListener(TwitterRequestEvent.COMPLETE, onStatusesUpdateComplete);
            request.addEventListener(TwitterErrorEvent.CLIENT_ERROR, onStatusesUpdateError);
            request.addEventListener(TwitterErrorEvent.SERVER_ERROR, onStatusesUpdateError);

            this.outputConsole.appendText("Please wait...\n");
        }

        // When tweet succeeded
        private function onStatusesUpdateComplete(event:TwitterRequestEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onStatusesUpdateComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onStatusesUpdateError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onStatusesUpdateError);

            this.tweetInputField.text = "";

            this.outputConsole.appendText("Tweeted!\n");
        }

        // When tweet failed
        private function onStatusesUpdateError(event:TwitterErrorEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onStatusesUpdateComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onStatusesUpdateError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onStatusesUpdateError);

            this.outputConsole.appendText("Error: " + event.statusCode.toString() + "\n");
        }

    }

}

/*
 * An exmaple app for Twitter for AS3
 *
 * copyright (c) 2015 Susisu
 */

package
{

    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.net.navigateToURL;
    import flash.net.URLRequest;

    import isle.susisu.twitter.Twitter;
    import isle.susisu.twitter.TwitterRequest;
    import isle.susisu.twitter.events.TwitterRequestEvent;
    import isle.susisu.twitter.events.TwitterErrorEvent;

    [SWF(width="480", height="360", backgroundColor="0x000000", frameRate="60")]
    public class ExampleApp extends Sprite
    {

        private var outputConsole:TextField;
        private var openBrowserButton:Sprite;
        private var pinInputField:TextField;
        private var getAccessTokenButton:Sprite;
        private var tweetInputField:TextField;
        private var tweetButton:Sprite;

        private var twitter:Twitter;

        public function ExampleApp()
        {
            // Replace <consumer key> and <consumer key secret> with your app's
            this.twitter = new Twitter("<consumer key>","<consumer key secret>");

            // Create UI
            // Output console
            this.outputConsole = new TextField();
            this.outputConsole.width = 480;
            this.outputConsole.height = 180;
            this.outputConsole.border = true;
            this.outputConsole.background = true;
            this.outputConsole.backgroundColor = 0xffffff;
            this.outputConsole.text = "";
            this.addChild(this.outputConsole);

            // "Open browser" button
            this.openBrowserButton = new Sprite();
            var openBrowserButtonText:TextField = new TextField();
            openBrowserButtonText.width = 80;
            openBrowserButtonText.height = 20;
            openBrowserButtonText.background = true;
            openBrowserButtonText.backgroundColor = 0xc0c0c0;
            openBrowserButtonText.border = true;
            openBrowserButtonText.text = "Open browser";
            this.openBrowserButton.addChild(openBrowserButtonText);
            this.openBrowserButton.y = 180;
            this.openBrowserButton.buttonMode = true;
            this.openBrowserButton.mouseChildren = false;
            this.addChild(this.openBrowserButton);
            this.openBrowserButton.addEventListener(MouseEvent.CLICK, onOpenBrowserButtonClick);

            // PIN input field
            this.pinInputField = new TextField();
            this.pinInputField.x = 80;
            this.pinInputField.y = 180;
            this.pinInputField.width = 200;
            this.pinInputField.height = 20;
            this.pinInputField.background = true;
            this.pinInputField.backgroundColor = 0xffffff;
            this.pinInputField.border = true;
            this.pinInputField.type = TextFieldType.INPUT;
            this.pinInputField.text = "Input PIN here";
            this.addChild(this.pinInputField);

            // "Get access token" button
            this.getAccessTokenButton = new Sprite();
            var getAccessTokenButtonText:TextField = new TextField();
            getAccessTokenButtonText.width = 200;
            getAccessTokenButtonText.height = 20;
            getAccessTokenButtonText.background = true;
            getAccessTokenButtonText.backgroundColor = 0xc0c0c0;
            getAccessTokenButtonText.border = true;
            getAccessTokenButtonText.text = "Get access tokens";
            this.getAccessTokenButton.addChild(getAccessTokenButtonText);
            this.getAccessTokenButton.x = 280;
            this.getAccessTokenButton.y = 180;
            this.getAccessTokenButton.buttonMode = true;
            this.getAccessTokenButton.mouseChildren = false;
            this.addChild(this.getAccessTokenButton);
            this.getAccessTokenButton.addEventListener(MouseEvent.CLICK, onGetAccessTokenButtonClick);

            // Tweet input field
            this.tweetInputField = new TextField();
            this.tweetInputField.y = 200;
            this.tweetInputField.width = 480;
            this.tweetInputField.height = 140;
            this.tweetInputField.background = true;
            this.tweetInputField.backgroundColor = 0xffffff;
            this.tweetInputField.border = true;
            this.tweetInputField.type = TextFieldType.INPUT;
            this.tweetInputField.text = "Input your tweet here"
            this.addChild(this.tweetInputField);

            // Tweet button
            this.tweetButton = new Sprite();
            var tweetButtonText:TextField = new TextField();
            tweetButtonText.width = 480;
            tweetButtonText.height = 20;
            tweetButtonText.background = true;
            tweetButtonText.backgroundColor = 0xc0c0c0;
            tweetButtonText.border = true;
            tweetButtonText.text = "Tweet";
            this.tweetButton.addChild(tweetButtonText);
            this.tweetButton.y = 340;
            this.tweetButton.buttonMode = true;
            this.tweetButton.mouseChildren = false;
            this.addChild(this.tweetButton);
            this.tweetButton.addEventListener(MouseEvent.CLICK, onTweetButtonClick);

            this.outputConsole.appendText("1. Click \"open browser\" button\n2. Authorize the app and get PIN\n3. Input PIN\n4. Get access tokens\n5. Tweet!\n");
        }

        // When the "open browser" button is clicked
        private function onOpenBrowserButtonClick(event:MouseEvent):void
        {
            var request:TwitterRequest = this.twitter.oauth_requestToken();

            request.addEventListener(TwitterRequestEvent.COMPLETE, onOAuthRequestTokenComplete);
            request.addEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthRequestTokenError);
            request.addEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthRequestTokenError);
            this.outputConsole.appendText("Please wait...\n");
        }

        // When oauth/request_token is complete
        private function onOAuthRequestTokenComplete(event:TwitterRequestEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthRequestTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthRequestTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthRequestTokenError);

            // Open the authorization page in browser
            navigateToURL(new URLRequest(this.twitter.getOAuthAuthorizeURL()));

            this.outputConsole.appendText("Borwser opened: " + this.twitter.getOAuthAuthorizeURL() + "\n");
        }

        // When oauth/request_token failed
        private function onOAuthRequestTokenError(event:TwitterErrorEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthRequestTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthRequestTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthRequestTokenError);

            this.outputConsole.appendText("Error: " + event.statusCode.toString() + "\n");

            event.preventDefault();
        }

        // When the "access token" button is clicked
        private function onGetAccessTokenButtonClick(event:MouseEvent):void
        {
            // Send PIN
            var request:TwitterRequest = this.twitter.oauth_accessToken(this.pinInputField.text);

            request.addEventListener(TwitterRequestEvent.COMPLETE, onOAuthAccessTokenComplete);
            request.addEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthAccessTokenError);
            request.addEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthAccessTokenError);

            this.outputConsole.appendText("Please wait...\n");
        }

        // When oauth/access_token is complete
        private function onOAuthAccessTokenComplete(event:TwitterRequestEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthAccessTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthAccessTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthAccessTokenError);

            this.pinInputField.text = "";

            // Output the access token to the console
            this.outputConsole.appendText("Access token: " + this.twitter.accessToken + "\n");
            this.outputConsole.appendText("Access token secret: " + this.twitter.accessTokenSecret + "\n");
        }

        // When oauth/access_token failed
        private function onOAuthAccessTokenError(event:TwitterErrorEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onOAuthAccessTokenComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onOAuthAccessTokenError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onOAuthAccessTokenError);

            this.outputConsole.appendText("Error: " + event.statusCode.toString() + "\n");

            event.preventDefault();
        }

        // When the tweet button is clicked
        private function onTweetButtonClick(event:MouseEvent):void
        {
            // Send tweet
            var request:TwitterRequest = this.twitter.statuses_update(this.tweetInputField.text);

            request.addEventListener(TwitterRequestEvent.COMPLETE, onStatusesUpdateComplete);
            request.addEventListener(TwitterErrorEvent.CLIENT_ERROR, onStatusesUpdateError);
            request.addEventListener(TwitterErrorEvent.SERVER_ERROR, onStatusesUpdateError);

            this.outputConsole.appendText("Please wait...\n");
        }

        // When tweet succeeded
        private function onStatusesUpdateComplete(event:TwitterRequestEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onStatusesUpdateComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onStatusesUpdateError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onStatusesUpdateError);

            this.tweetInputField.text = "";

            this.outputConsole.appendText("Tweeted!\n");
        }

        // When tweet failed
        private function onStatusesUpdateError(event:TwitterErrorEvent):void
        {
            (event.target as TwitterRequest).removeEventListener(TwitterRequestEvent.COMPLETE, onStatusesUpdateComplete);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.CLIENT_ERROR, onStatusesUpdateError);
            (event.target as TwitterRequest).removeEventListener(TwitterErrorEvent.SERVER_ERROR, onStatusesUpdateError);

            this.outputConsole.appendText("Error: " + event.statusCode.toString() + "\n");

            event.preventDefault();
        }

    }

}

Fix missing preventDefault() for error events


package goplayer
{
  import flash.display.DisplayObject
  import flash.display.DisplayObjectContainer
  import flash.display.Sprite
  import flash.text.TextField
  import flash.events.MouseEvent
  import flash.utils.getQualifiedClassName
  import flash.utils.describeType

  public class SkinPlayerView extends ResizableSprite
    implements PlayerVideoUpdateListener
  {
    private const overlay : Background
      = new Background(0x000000, 0.5)
    private const bufferingIndicator : BufferingIndicator
      = new BufferingIndicator

    private var skin : WrappedSkin
    private var video : PlayerVideo
    private var player : Player

    public function SkinPlayerView
      (skin : WrappedSkin, video : PlayerVideo, player : Player)
    {
      this.skin = skin
      this.video = video
      this.player = player

      onclick(skin.playButton, handlePlayButtonClicked)
      onclick(skin.pauseButton, handlePauseButtonClicked)

      onclick(skin.enableFullscreenButton, handleEnableFullscreenButtonClicked)
      onclick(skin.muteButton, handleMuteButtonClicked)
      onclick(skin.unmuteButton, handleUnmuteButtonClicked)

      addChild(video)
      addChild(overlay)
      addChild(bufferingIndicator)
      addChild(skin.root)

      video.addUpdateListener(this)
    }

    private function handlePlayButtonClicked() : void
    {
      if (player.started)
        player.paused = false
      else
        player.start()
    }

    private function handlePauseButtonClicked() : void
    { player.paused = true }

    private function handleMuteButtonClicked() : void
    { player.mute() }

    private function handleUnmuteButtonClicked() : void
    { player.unmute() }

    private function handleEnableFullscreenButtonClicked() : void
    { video.toggleFullscreen() }

    override public function set dimensions(value : Dimensions) : void
    { video.normalDimensions = value }

    public function handlePlayerVideoUpdated() : void
    {
      setDimensions(skin.root, video.dimensions)

      skin.bufferRatio = player.bufferRatio
      skin.playheadRatio = player.playheadRatio

      video.visible = !player.finished

      skin.playButton.visible = playButtonVisible
      skin.pauseButton.visible = !playButtonVisible

      skin.muteButton.visible = !player.muted
      skin.unmuteButton.visible = player.muted

      skin.leftTimeField.text = leftTimeLabel
      skin.rightTimeField.text = rightTimeLabel

      setBounds(overlay, video.videoPosition, video.videoDimensions)

      overlay.visible = player.buffering

      setPosition(bufferingIndicator, video.videoDimensions.halved.asPosition)

      bufferingIndicator.size = video.videoDimensions.innerSquare.width / 3
      bufferingIndicator.ratio = player.bufferFillRatio
      bufferingIndicator.visible = player.buffering

      if (bufferingIndicator.visible)
        bufferingIndicator.update()
    }

    private function get leftTimeLabel() : String
    { return player.playheadPosition.mss }

    private function get rightTimeLabel() : String
    { return player.streamLength.minus(player.playheadPosition).mss }

    private function get playButtonVisible() : Boolean
    { return !player.started || player.paused || player.finished }

    private function get videoWidth() : Number
    { return video.videoDimensions.width }

    private function get videoLeft() : Number
    { return video.videoPosition.x }

    private function get videoBottom() : Number
    { return video.videoPosition.plus(video.videoDimensions).y }
  }
}

package goplayer
{
  import flash.display.DisplayObject
  import flash.display.DisplayObjectContainer
  import flash.display.Sprite
  import flash.text.TextField
  import flash.events.MouseEvent
  import flash.utils.getQualifiedClassName
  import flash.utils.describeType

  public class SkinPlayerView extends ResizableSprite
    implements PlayerVideoUpdateListener
  {
    private const overlay : Background
      = new Background(0x000000, 0.5)
    private const bufferingIndicator : BufferingIndicator
      = new BufferingIndicator

    private var skin : WrappedSkin
    private var video : PlayerVideo
    private var player : Player

    public function SkinPlayerView
      (skin : WrappedSkin, video : PlayerVideo, player : Player)
    {
      this.skin = skin
      this.video = video
      this.player = player

      onclick(skin.playButton, handlePlayButtonClicked)
      onclick(skin.pauseButton, handlePauseButtonClicked)

      onclick(skin.enableFullscreenButton, handleEnableFullscreenButtonClicked)
      onclick(skin.muteButton, handleMuteButtonClicked)
      onclick(skin.unmuteButton, handleUnmuteButtonClicked)

      addChild(video)
      addChild(overlay)
      addChild(bufferingIndicator)
      addChild(skin.root)

      skin.root.visible = false

      video.addUpdateListener(this)
    }

    private function handlePlayButtonClicked() : void
    {
      if (player.started)
        player.paused = false
      else
        player.start()
    }

    private function handlePauseButtonClicked() : void
    { player.paused = true }

    private function handleMuteButtonClicked() : void
    { player.mute() }

    private function handleUnmuteButtonClicked() : void
    { player.unmute() }

    private function handleEnableFullscreenButtonClicked() : void
    { video.toggleFullscreen() }

    override public function set dimensions(value : Dimensions) : void
    { video.normalDimensions = value }

    public function handlePlayerVideoUpdated() : void
    {
      setDimensions(skin.root, video.dimensions)

      skin.root.visible = true

      skin.bufferRatio = player.bufferRatio
      skin.playheadRatio = player.playheadRatio

      video.visible = !player.finished

      skin.playButton.visible = playButtonVisible
      skin.pauseButton.visible = !playButtonVisible

      skin.muteButton.visible = !player.muted
      skin.unmuteButton.visible = player.muted

      skin.leftTimeField.text = leftTimeLabel
      skin.rightTimeField.text = rightTimeLabel

      setBounds(overlay, video.videoPosition, video.videoDimensions)

      overlay.visible = player.buffering

      setPosition(bufferingIndicator, video.videoDimensions.halved.asPosition)

      bufferingIndicator.size = video.videoDimensions.innerSquare.width / 3
      bufferingIndicator.ratio = player.bufferFillRatio
      bufferingIndicator.visible = player.buffering

      if (bufferingIndicator.visible)
        bufferingIndicator.update()
    }

    private function get leftTimeLabel() : String
    { return player.playheadPosition.mss }

    private function get rightTimeLabel() : String
    { return player.streamLength.minus(player.playheadPosition).mss }

    private function get playButtonVisible() : Boolean
    { return !player.started || player.paused || player.finished }

    private function get videoWidth() : Number
    { return video.videoDimensions.width }

    private function get videoLeft() : Number
    { return video.videoPosition.x }

    private function get videoBottom() : Number
    { return video.videoPosition.plus(video.videoDimensions).y }
  }
}

Hide the skin while it is being initialized.