<commit_before>/* See license.txt for terms of usage */

FBL.ns(function() { with (FBL) {

var toggleProfiling = $("fbToggleProfiling");

// ************************************************************************************************

Firebug.Profiler = extend(Firebug.Module,
{
    dispatchName: "profiler",
    showContext: function(browser, context)
    {
        this.setEnabled(context);
    },

    onPanelEnable: function(context, panelName)
    {
        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Profiler.onPanelEnable panelName: "+panelName+"\n");

        if (panelName == "net" || panelName == "script")
            this.setEnabled(context);
    },

    onPanelDisable: function(panelName)
    {
        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Profiler.onPanelDisable panelName: "+panelName+"\n");

       if (panelName == "net" || panelName == "script")
            this.setEnabled();
    },

    setEnabled: function()
    {
        // The profiler is available only if the debugger (script panel) and console are enabled.
        var debuggerEnabled = Firebug.Debugger.isAlwaysEnabled();
        var consoleEnabled = Firebug.Console.isAlwaysEnabled();
        toggleProfiling.disabled = !debuggerEnabled || !consoleEnabled;

        // Update button's tooltip.
        var tooltipText = toggleProfiling.disabled ? $STR("ProfileButton.Disabled.Tooltip")
            : $STR("ProfileButton.Enabled.Tooltip");
        toggleProfiling.setAttribute("tooltiptext", tooltipText);
    },

    toggleProfiling: function(context)
    {
        if (fbs.profiling)
            this.stopProfiling(context);
        else
            this.startProfiling(context);
    },

    startProfiling: function(context, title)
    {
        fbs.startProfiling();

        Firebug.chrome.setGlobalAttribute("cmd_toggleProfiling", "checked", "true");

        var isCustomMessage = !!title;
        if (!isCustomMessage)
            title = $STR("ProfilerStarted");

        context.profileRow = this.logProfileRow(context, title);
        context.profileRow.customMessage = isCustomMessage ;
    },

    stopProfiling: function(context, cancelReport)
    {
        var totalTime = fbs.stopProfiling();
        if (totalTime == -1)
            return;

        Firebug.chrome.setGlobalAttribute("cmd_toggleProfiling", "checked", "false");

        if (cancelReport)
            delete context.profileRow;
        else
            this.logProfileReport(context)
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    logProfileRow: function(context, title)
    {
        var row = Firebug.Console.openGroup(title, context, "profile",
            Firebug.Profiler.ProfileCaption, true, null, true);
        setClass(row, "profilerRunning");

        Firebug.Console.closeGroup(context, true);

        return row;
    },

    logProfileReport: function(context)
    {
        var calls = [];
        var totalCalls = 0;
        var totalTime = 0;

        var sourceFileMap = context.sourceFileMap;
        if (FBTrace.DBG_SOURCEFILES)
        {
            for (url in sourceFileMap)
                FBTrace.sysout("logProfileReport: "+sourceFileMap[url]+"\n");
        }

        jsd.enumerateScripts({enumerateScript: function(script)
        {
            if (script.callCount)
            {
                var sourceLink = FBL.getSourceLinkForScript(script, context);
                if (sourceLink && sourceLink.href in sourceFileMap)
                {
                    var call = new ProfileCall(script, context, script.callCount, script.totalExecutionTime,
                        script.totalOwnExecutionTime, script.minExecutionTime, script.maxExecutionTime, sourceLink);
                    calls.push(call);

                    totalCalls += script.callCount;
                    totalTime += script.totalOwnExecutionTime;

                    script.clearProfileData();
                }
            }
        }});

        for (var i = 0; i < calls.length; ++i)
            calls[i].percent = Math.round((calls[i].totalOwnTime/totalTime) * 100 * 100) / 100;

        calls.sort(function(a, b)
        {
           return a.totalOwnTime < b.totalOwnTime ? 1 : -1;
        });

        totalTime = Math.round(totalTime * 1000) / 1000;

        var groupRow = context.profileRow && context.profileRow.ownerDocument
            ? context.profileRow
            : this.logProfileRow(context, "");
        delete context.profileRow;

        removeClass(groupRow, "profilerRunning");

        if (totalCalls > 0)
        {
            var captionBox = getElementByClass(groupRow, "profileCaption");
            if (!groupRow.customMessage)
                captionBox.textContent = $STR("Profile");
            var timeBox = getElementByClass(groupRow, "profileTime");
            timeBox.textContent = $STRF("ProfileTime", [totalTime, totalCalls]);

            var groupBody = groupRow.lastChild;
            var sizer = Firebug.Profiler.ProfileTable.tag.replace({}, groupBody);
            var table = sizer.firstChild;
            var tHeader = table.lastChild;  // no rows inserted.

            var tag = Firebug.Profiler.ProfileCall.tag;
            var insert = tag.insertRows;

            for (var i = 0; i < calls.length; ++i) {
                calls[i].index = i;
                context.throttle(insert, tag, [{object: calls[i]}, tHeader]);
            }

            context.throttle(groupRow.scrollIntoView, groupRow);
        }
        else
        {
            var captionBox = getElementByClass(groupRow, "profileCaption");
            captionBox.textContent = $STR("NothingToProfile");
        }
    }
});

// ************************************************************************************************

Firebug.Profiler.ProfileTable = domplate(
{
    tag:
      DIV({class: "profileSizer" },
        TABLE({class: "profileTable", cellspacing: 0, cellpadding: 0, width: "100%"},
            TBODY({class: "profileTbody"},
                TR({class: "headerRow", onclick: "$onClick"},
                    TH({class: "headerCell alphaValue"},
                        DIV({class: "headerCellBox"},
                            $STR("Function")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("CallsHeaderTooltip")},
                            $STR("Calls")
                        )
                    ),
                    TH({class: "headerCell headerSorted"},
                        DIV({class: "headerCellBox", title: $STR("PercentTooltip")},
                            $STR("Percent")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("OwnTimeHeaderTooltip")},
                            $STR("OwnTime")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("TimeHeaderTooltip")},
                            $STR("Time")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("AvgHeaderTooltip")},
                            $STR("Avg")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("MinHeaderTooltip")},
                            $STR("Min")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("MaxHeaderTooltip")},
                            $STR("Max")
                        )
                    ),
                    TH({class: "headerCell alphaValue"},
                        DIV({class: "headerCellBox"},
                            $STR("File")
                        )
                    )
                )
            )
          )
        ),

    onClick: function(event)
    {
        var table = getAncestorByClass(event.target, "profileTable");
        var header = getAncestorByClass(event.target, "headerCell");
        if (!header)
            return;

        var numerical = !hasClass(header, "alphaValue");

        var colIndex = 0;
        for (header = header.previousSibling; header; header = header.previousSibling)
            ++colIndex;

        this.sort(table, colIndex, numerical);
    },

    sort: function(table, colIndex, numerical)
    {
        var tbody = getChildByClass(table, "profileTbody");

        var values = [];
        for (var row = tbody.childNodes[1]; row; row = row.nextSibling)
        {
            var cell = row.childNodes[colIndex];
            var value = numerical ? parseFloat(cell.textContent) : cell.textContent;
            values.push({row: row, value: value});
        }

        values.sort(function(a, b) { return a.value < b.value ? -1 : 1; });

        var headerRow = tbody.firstChild;
        var headerSorted = getChildByClass(headerRow, "headerSorted");
        removeClass(headerSorted, "headerSorted");

        var header = headerRow.childNodes[colIndex];
        setClass(header, "headerSorted");

        if (!header.sorted || header.sorted == 1)
        {
            removeClass(header, "sortedDescending");
            setClass(header, "sortedAscending");

            header.sorted = -1;

            for (var i = 0; i < values.length; ++i) {
                values[i].row.setAttribute("odd", (i % 2));
                tbody.appendChild(values[i].row);
            }
        }
        else
        {
            removeClass(header, "sortedAscending");
            setClass(header, "sortedDescending");

            header.sorted = 1;

            for (var i = values.length-1; i >= 0; --i) {
                values[i].row.setAttribute("odd", (Math.abs(i-values.length-1) % 2));
                tbody.appendChild(values[i].row);
            }
        }
    }
});

// ************************************************************************************************

Firebug.Profiler.ProfileCaption = domplate(Firebug.Rep,
{
    tag:
        SPAN({class: "profileTitle"},
            SPAN({class: "profileCaption"}, "$objects"),
            " ",
            SPAN({class: "profileTime"}, "")
        )
});

// ************************************************************************************************

Firebug.Profiler.ProfileCall = domplate(Firebug.Rep,
{
    tag:
        TR({odd: "$object|isOddRow"},
            TD(
                FirebugReps.OBJECTLINK("$object|getCallName")
            ),
            TD("$object.callCount"),
            TD("$object.percent%"),
            TD("$object.totalOwnTime|roundTime\\ms"),
            TD("$object.totalTime|roundTime\\ms"),
            TD("$object|avgTime|roundTime\\ms"),
            TD("$object.minTime|roundTime\\ms"),
            TD("$object.maxTime|roundTime\\ms"),
            TD({class: "linkCell"},
                TAG(FirebugReps.SourceLink.tag, {object: "$object|getSourceLink"})
            )
        ),

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    isOddRow: function(call)
    {
        return (call.index % 2) ? 1 : 0;
    },

    getCallName: function(call)
    {
        return cropString(getFunctionName(call.script, call.context), 60);
    },

    avgTime: function(call)
    {
        return call.totalTime / call.callCount;
    },

    getSourceLink: function(call)
    {
        return call.sourceLink;
    },

    roundTime: function(ms)
    {
        return Math.round(ms * 1000) / 1000;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    className: "profile",

    supportsObject: function(object)
    {
        return object instanceof ProfileCall;
    },

    inspectObject: function(call, context)
    {
        var sourceLink = this.getSourceLink(call);
        Firebug.chrome.select(sourceLink);
    },

    getTooltip: function(call)
    {
        try
        {
            var fn = call.script.functionObject.getWrappedValue();
            return FirebugReps.Func.getTooltip(fn, call.context);
        }
        catch (exc)
        {
            if (FBTrace.DBG_ERRORS)
                FBTrace.sysout("profiler.getTooltip FAILS ", exc);
        }
    },

    getContextMenuItems: function(call, target, context)
    {
        var fn = call.script.functionObject.getWrappedValue();
        return FirebugReps.Func.getContextMenuItems(fn, call.script, context);
    }
});

// ************************************************************************************************

function ProfileCall(script, context, callCount, totalTime, totalOwnTime, minTime, maxTime, sourceLink)
{
    this.script = script;
    this.context = context;
    this.callCount = callCount;
    this.totalTime = totalTime;
    this.totalOwnTime = totalOwnTime;
    this.minTime = minTime;
    this.maxTime = maxTime;
    this.sourceLink = sourceLink;
}

// ************************************************************************************************

Firebug.registerModule(Firebug.Profiler);
Firebug.registerRep(Firebug.Profiler.ProfileCall);

// ************************************************************************************************

}});
<commit_msg>missed one context onPanelEnable<commit_after>/* See license.txt for terms of usage */

FBL.ns(function() { with (FBL) {

var toggleProfiling = $("fbToggleProfiling");

// ************************************************************************************************

Firebug.Profiler = extend(Firebug.Module,
{
    dispatchName: "profiler",
    showContext: function(browser, context)
    {
        this.setEnabled(context);
    },

    onPanelEnable: function(panelName)
    {
        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Profiler.onPanelEnable panelName: "+panelName+"\n");

        if (panelName == "net" || panelName == "script")
            this.setEnabled();
    },

    onPanelDisable: function(panelName)
    {
        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Profiler.onPanelDisable panelName: "+panelName+"\n");

       if (panelName == "net" || panelName == "script")
            this.setEnabled();
    },

    setEnabled: function()
    {
        // The profiler is available only if the debugger (script panel) and console are enabled.
        var debuggerEnabled = Firebug.Debugger.isAlwaysEnabled();
        var consoleEnabled = Firebug.Console.isAlwaysEnabled();
        toggleProfiling.disabled = !debuggerEnabled || !consoleEnabled;

        // Update button's tooltip.
        var tooltipText = toggleProfiling.disabled ? $STR("ProfileButton.Disabled.Tooltip")
            : $STR("ProfileButton.Enabled.Tooltip");
        toggleProfiling.setAttribute("tooltiptext", tooltipText);
    },

    toggleProfiling: function(context)
    {
        if (fbs.profiling)
            this.stopProfiling(context);
        else
            this.startProfiling(context);
    },

    startProfiling: function(context, title)
    {
        fbs.startProfiling();

        Firebug.chrome.setGlobalAttribute("cmd_toggleProfiling", "checked", "true");

        var isCustomMessage = !!title;
        if (!isCustomMessage)
            title = $STR("ProfilerStarted");

        context.profileRow = this.logProfileRow(context, title);
        context.profileRow.customMessage = isCustomMessage ;
    },

    stopProfiling: function(context, cancelReport)
    {
        var totalTime = fbs.stopProfiling();
        if (totalTime == -1)
            return;

        Firebug.chrome.setGlobalAttribute("cmd_toggleProfiling", "checked", "false");

        if (cancelReport)
            delete context.profileRow;
        else
            this.logProfileReport(context)
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    logProfileRow: function(context, title)
    {
        var row = Firebug.Console.openGroup(title, context, "profile",
            Firebug.Profiler.ProfileCaption, true, null, true);
        setClass(row, "profilerRunning");

        Firebug.Console.closeGroup(context, true);

        return row;
    },

    logProfileReport: function(context)
    {
        var calls = [];
        var totalCalls = 0;
        var totalTime = 0;

        var sourceFileMap = context.sourceFileMap;
        if (FBTrace.DBG_SOURCEFILES)
        {
            for (url in sourceFileMap)
                FBTrace.sysout("logProfileReport: "+sourceFileMap[url]+"\n");
        }

        jsd.enumerateScripts({enumerateScript: function(script)
        {
            if (script.callCount)
            {
                var sourceLink = FBL.getSourceLinkForScript(script, context);
                if (sourceLink && sourceLink.href in sourceFileMap)
                {
                    var call = new ProfileCall(script, context, script.callCount, script.totalExecutionTime,
                        script.totalOwnExecutionTime, script.minExecutionTime, script.maxExecutionTime, sourceLink);
                    calls.push(call);

                    totalCalls += script.callCount;
                    totalTime += script.totalOwnExecutionTime;

                    script.clearProfileData();
                }
            }
        }});

        for (var i = 0; i < calls.length; ++i)
            calls[i].percent = Math.round((calls[i].totalOwnTime/totalTime) * 100 * 100) / 100;

        calls.sort(function(a, b)
        {
           return a.totalOwnTime < b.totalOwnTime ? 1 : -1;
        });

        totalTime = Math.round(totalTime * 1000) / 1000;

        var groupRow = context.profileRow && context.profileRow.ownerDocument
            ? context.profileRow
            : this.logProfileRow(context, "");
        delete context.profileRow;

        removeClass(groupRow, "profilerRunning");

        if (totalCalls > 0)
        {
            var captionBox = getElementByClass(groupRow, "profileCaption");
            if (!groupRow.customMessage)
                captionBox.textContent = $STR("Profile");
            var timeBox = getElementByClass(groupRow, "profileTime");
            timeBox.textContent = $STRF("ProfileTime", [totalTime, totalCalls]);

            var groupBody = groupRow.lastChild;
            var sizer = Firebug.Profiler.ProfileTable.tag.replace({}, groupBody);
            var table = sizer.firstChild;
            var tHeader = table.lastChild;  // no rows inserted.

            var tag = Firebug.Profiler.ProfileCall.tag;
            var insert = tag.insertRows;

            for (var i = 0; i < calls.length; ++i) {
                calls[i].index = i;
                context.throttle(insert, tag, [{object: calls[i]}, tHeader]);
            }

            context.throttle(groupRow.scrollIntoView, groupRow);
        }
        else
        {
            var captionBox = getElementByClass(groupRow, "profileCaption");
            captionBox.textContent = $STR("NothingToProfile");
        }
    }
});

// ************************************************************************************************

Firebug.Profiler.ProfileTable = domplate(
{
    tag:
      DIV({class: "profileSizer" },
        TABLE({class: "profileTable", cellspacing: 0, cellpadding: 0, width: "100%"},
            TBODY({class: "profileTbody"},
                TR({class: "headerRow", onclick: "$onClick"},
                    TH({class: "headerCell alphaValue"},
                        DIV({class: "headerCellBox"},
                            $STR("Function")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("CallsHeaderTooltip")},
                            $STR("Calls")
                        )
                    ),
                    TH({class: "headerCell headerSorted"},
                        DIV({class: "headerCellBox", title: $STR("PercentTooltip")},
                            $STR("Percent")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("OwnTimeHeaderTooltip")},
                            $STR("OwnTime")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("TimeHeaderTooltip")},
                            $STR("Time")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("AvgHeaderTooltip")},
                            $STR("Avg")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("MinHeaderTooltip")},
                            $STR("Min")
                        )
                    ),
                    TH({class: "headerCell"},
                        DIV({class: "headerCellBox", title: $STR("MaxHeaderTooltip")},
                            $STR("Max")
                        )
                    ),
                    TH({class: "headerCell alphaValue"},
                        DIV({class: "headerCellBox"},
                            $STR("File")
                        )
                    )
                )
            )
          )
        ),

    onClick: function(event)
    {
        var table = getAncestorByClass(event.target, "profileTable");
        var header = getAncestorByClass(event.target, "headerCell");
        if (!header)
            return;

        var numerical = !hasClass(header, "alphaValue");

        var colIndex = 0;
        for (header = header.previousSibling; header; header = header.previousSibling)
            ++colIndex;

        this.sort(table, colIndex, numerical);
    },

    sort: function(table, colIndex, numerical)
    {
        var tbody = getChildByClass(table, "profileTbody");

        var values = [];
        for (var row = tbody.childNodes[1]; row; row = row.nextSibling)
        {
            var cell = row.childNodes[colIndex];
            var value = numerical ? parseFloat(cell.textContent) : cell.textContent;
            values.push({row: row, value: value});
        }

        values.sort(function(a, b) { return a.value < b.value ? -1 : 1; });

        var headerRow = tbody.firstChild;
        var headerSorted = getChildByClass(headerRow, "headerSorted");
        removeClass(headerSorted, "headerSorted");

        var header = headerRow.childNodes[colIndex];
        setClass(header, "headerSorted");

        if (!header.sorted || header.sorted == 1)
        {
            removeClass(header, "sortedDescending");
            setClass(header, "sortedAscending");

            header.sorted = -1;

            for (var i = 0; i < values.length; ++i) {
                values[i].row.setAttribute("odd", (i % 2));
                tbody.appendChild(values[i].row);
            }
        }
        else
        {
            removeClass(header, "sortedAscending");
            setClass(header, "sortedDescending");

            header.sorted = 1;

            for (var i = values.length-1; i >= 0; --i) {
                values[i].row.setAttribute("odd", (Math.abs(i-values.length-1) % 2));
                tbody.appendChild(values[i].row);
            }
        }
    }
});

// ************************************************************************************************

Firebug.Profiler.ProfileCaption = domplate(Firebug.Rep,
{
    tag:
        SPAN({class: "profileTitle"},
            SPAN({class: "profileCaption"}, "$objects"),
            " ",
            SPAN({class: "profileTime"}, "")
        )
});

// ************************************************************************************************

Firebug.Profiler.ProfileCall = domplate(Firebug.Rep,
{
    tag:
        TR({odd: "$object|isOddRow"},
            TD(
                FirebugReps.OBJECTLINK("$object|getCallName")
            ),
            TD("$object.callCount"),
            TD("$object.percent%"),
            TD("$object.totalOwnTime|roundTime\\ms"),
            TD("$object.totalTime|roundTime\\ms"),
            TD("$object|avgTime|roundTime\\ms"),
            TD("$object.minTime|roundTime\\ms"),
            TD("$object.maxTime|roundTime\\ms"),
            TD({class: "linkCell"},
                TAG(FirebugReps.SourceLink.tag, {object: "$object|getSourceLink"})
            )
        ),

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    isOddRow: function(call)
    {
        return (call.index % 2) ? 1 : 0;
    },

    getCallName: function(call)
    {
        return cropString(getFunctionName(call.script, call.context), 60);
    },

    avgTime: function(call)
    {
        return call.totalTime / call.callCount;
    },

    getSourceLink: function(call)
    {
        return call.sourceLink;
    },

    roundTime: function(ms)
    {
        return Math.round(ms * 1000) / 1000;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    className: "profile",

    supportsObject: function(object)
    {
        return object instanceof ProfileCall;
    },

    inspectObject: function(call, context)
    {
        var sourceLink = this.getSourceLink(call);
        Firebug.chrome.select(sourceLink);
    },

    getTooltip: function(call)
    {
        try
        {
            var fn = call.script.functionObject.getWrappedValue();
            return FirebugReps.Func.getTooltip(fn, call.context);
        }
        catch (exc)
        {
            if (FBTrace.DBG_ERRORS)
                FBTrace.sysout("profiler.getTooltip FAILS ", exc);
        }
    },

    getContextMenuItems: function(call, target, context)
    {
        var fn = call.script.functionObject.getWrappedValue();
        return FirebugReps.Func.getContextMenuItems(fn, call.script, context);
    }
});

// ************************************************************************************************

function ProfileCall(script, context, callCount, totalTime, totalOwnTime, minTime, maxTime, sourceLink)
{
    this.script = script;
    this.context = context;
    this.callCount = callCount;
    this.totalTime = totalTime;
    this.totalOwnTime = totalOwnTime;
    this.minTime = minTime;
    this.maxTime = maxTime;
    this.sourceLink = sourceLink;
}

// ************************************************************************************************

Firebug.registerModule(Firebug.Profiler);
Firebug.registerRep(Firebug.Profiler.ProfileCall);

// ************************************************************************************************

}});
<|endoftext|>


<commit_before>// Hi Welcome to WFI by David Jones / RackFX, LLC
var fs = require('fs');
var wfi = {}

wfi.infoByFilename = function(filename, cb){
  var stats = fs.statSync(filename)
  var buffer = new Buffer(40);  // first 40 bytes are RIFF header
  fs.open(filename, 'r', function(status, fd) {
    if(status) return cb(status);  // error probably TODO:check this!

    // ex error -
    // { [Error: ENOENT: no such file or directory, open './test.wav'] errno: -2, code: 'ENOENT', syscall: 'open', path: './test.wav' }
    var read_result = {}

    // this a list of sequenced bytes in the 40 byte header. This builds the read_result object.
    //  Property name / Data type / Length
    var reads = [
      ['riff_head', 'string', 4],
      ['chunk_size','integer', 4],
      ['wave_identifier', 'string', 4],
      ['fmt_identifier', 'string', 4],
      ['subchunk_size','integer',4],
      ['audio_format','integer',2],
      ['num_channels','integer',2],
      ['sample_rate','integer',4],
      ['byte_rate','integer',4],
      ['block_align','integer',2],
      ['bits_per_sample','integer',2],
      //['uhm','integer',2],
      ['data_identifier','string', 4],
      //['sub_chunk2_size', 'integer', 4],

    ]
    fs.read(fd, buffer, 0, 40, 0, function(err, num) {

      var i=0;
      var pointer = 0;
      function read_wav(){
        var read = reads[i];

        i++;
        if(read[1]=='string'){
          read_result[read[0]] = buffer.toString('ascii', pointer , pointer + read[2]);
          pointer = pointer + read[2];   // pointer = pointer plus # bytes
        }
        else if(read[1]=='integer'){
          read_result[read[0]] = buffer.readIntLE(pointer, read[2])
          pointer = pointer + read[2];
        }
        if(i < reads.length) { return read_wav()}
        else { return post_process(); }

      }
      //console.log(i)
      read_wav();
    }); // end fs.read

    function post_process(){
      var error = false;
      var invalid_reasons = []

      if (read_result.riff_head != "RIFF")  invalid_reasons.push("Expected \"RIFF\" string at 0" )
      if (read_result.wave_identifier != "WAVE") invalid_reasons.push("Expected \"WAVE\" string at 4")
      if (read_result.fmt_identifier != "fmt ") invalid_reasons.push("Expected \"fmt \" string at 8")
      if (read_result.audio_format != 1) invalid_reasons.push("Unknwon format: "+read_result.audio_format)
      if ((read_result.chunk_size + 8) !== stats.size) invalid_reasons.push("chunk_size does not match file size")
      //if ((read_result.data_identifier) != "data") invalid_reasons.push("Expected data identifier at the end of the header")

      if (invalid_reasons.length > 0) error = true;

      if (error) return cb({
        error : true,
        invalid_reasons: invalid_reasons,
        header: read_result,
        stats: stats
      });

      cb(null, {
        header: read_result,
        stats: stats
      });
    }
  });
}
module.exports = wfi;
<commit_msg>err callback check<commit_after>// Hi Welcome to WFI by David Jones / RackFX, LLC
var fs = require('fs');
var wfi = {}

wfi.infoByFilename = function(filename, cb){
  var stats = fs.statSync(filename)
  var buffer = new Buffer(40);  // first 40 bytes are RIFF header
  fs.open(filename, 'r', function(err, fd) {
    if(err) return cb(err);  // error probably TODO:check this!

    // ex error -
    // { [Error: ENOENT: no such file or directory, open './test.wav'] errno: -2, code: 'ENOENT', syscall: 'open', path: './test.wav' }
    var read_result = {}

    // this a list of sequenced bytes in the 40 byte header. This builds the read_result object.
    //  Property name / Data type / Length
    var reads = [
      ['riff_head', 'string', 4],
      ['chunk_size','integer', 4],
      ['wave_identifier', 'string', 4],
      ['fmt_identifier', 'string', 4],
      ['subchunk_size','integer',4],
      ['audio_format','integer',2],
      ['num_channels','integer',2],
      ['sample_rate','integer',4],
      ['byte_rate','integer',4],
      ['block_align','integer',2],
      ['bits_per_sample','integer',2],
      //['uhm','integer',2],
      ['data_identifier','string', 4],
      //['sub_chunk2_size', 'integer', 4],

    ]
    fs.read(fd, buffer, 0, 40, 0, function(err, num) {

      var i=0;
      var pointer = 0;
      function read_wav(){
        var read = reads[i];

        i++;
        if(read[1]=='string'){
          read_result[read[0]] = buffer.toString('ascii', pointer , pointer + read[2]);
          pointer = pointer + read[2];   // pointer = pointer plus # bytes
        }
        else if(read[1]=='integer'){
          read_result[read[0]] = buffer.readIntLE(pointer, read[2])
          pointer = pointer + read[2];
        }
        if(i < reads.length) { return read_wav()}
        else { return post_process(); }

      }
      //console.log(i)
      read_wav();
    }); // end fs.read

    function post_process(){
      var error = false;
      var invalid_reasons = []

      if (read_result.riff_head != "RIFF")  invalid_reasons.push("Expected \"RIFF\" string at 0" )
      if (read_result.wave_identifier != "WAVE") invalid_reasons.push("Expected \"WAVE\" string at 4")
      if (read_result.fmt_identifier != "fmt ") invalid_reasons.push("Expected \"fmt \" string at 8")
      if (read_result.audio_format != 1) invalid_reasons.push("Unknwon format: "+read_result.audio_format)
      if ((read_result.chunk_size + 8) !== stats.size) invalid_reasons.push("chunk_size does not match file size")
      //if ((read_result.data_identifier) != "data") invalid_reasons.push("Expected data identifier at the end of the header")

      if (invalid_reasons.length > 0) error = true;

      if (error) return cb({
        error : true,
        invalid_reasons: invalid_reasons,
        header: read_result,
        stats: stats
      });

      cb(null, {
        header: read_result,
        stats: stats
      });
    }
  });
}
module.exports = wfi;
<|endoftext|>


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

/**
 * @fileoverview Class to create objects which want to handle multiple events
 * and have their listeners easily cleaned up via a dispose method.
 *
 * Example:
 *

 * function Something() {
 *   goog.events.EventHandler.call(this);
 *
 *   ... set up object ...
 *
 *   // Add event listeners
 *   this.listen(this.starEl, 'click', this.handleStar);
 *   this.listen(this.headerEl, 'click', this.expand);
 *   this.listen(this.collapseEl, 'click', this.collapse);
 *   this.listen(this.infoEl, 'mouseover', this.showHover);
 *   this.listen(this.infoEl, 'mouseout', this.hideHover);
 * }
 * goog.inherits(Something, goog.events.EventHandler);
 *
 * Something.prototype.disposeInternal = function() {
 *   Something.superClass_.disposeInternal.call(this);
 *   goog.dom.removeNode(this.container);
 * };
 *
 *
 * // Then elsewhere:
 *
 * var activeSomething = null;
 * function openSomething() {
 *   activeSomething = new Something();
 * }
 *
 * function closeSomething() {
 *   if (activeSomething) {
 *     activeSomething.dispose();  // Remove event listeners
 *     activeSomething = null;
 *   }
 * }
 *

 *
 */

goog.provide('goog.events.EventHandler');

goog.require('goog.Disposable');
goog.require('goog.events');
goog.require('goog.events.EventWrapper');
goog.require('goog.object');
goog.require('goog.structs.SimplePool');

/**
 * Super class for objects that want to easily manage a number of event
 * listeners.  It allows a short cut to listen and also provides a quick way
 * to remove all events listeners belonging to this object. It is optimized to
 * use less objects if only one event is being listened to, but if that's the
 * case, it may not be worth using the EventHandler anyway.
 * @param {Object=} opt_handler Object in whose scope to call the listeners.
 * @constructor
 * @extends {goog.Disposable}
 */
goog.events.EventHandler = function(opt_handler) {
  this.handler_ = opt_handler;
};
goog.inherits(goog.events.EventHandler, goog.Disposable);

/**
 * Initial count for the keyPool_
 * @type {number}
 */
goog.events.EventHandler.KEY_POOL_INITIAL_COUNT = 0;

/**
 * Max count for the keyPool_
 * @type {number}
 */
goog.events.EventHandler.KEY_POOL_MAX_COUNT = 100;

/**
 * SimplePool to cache the key object. This was implemented to make IE6
 * performance better and removed an object allocation in the listen method
 * when in steady state.
 * @type {goog.structs.SimplePool}
 * @private
 */
goog.events.EventHandler.keyPool_ = new goog.structs.SimplePool(
    goog.events.EventHandler.KEY_POOL_INITIAL_COUNT,
    goog.events.EventHandler.KEY_POOL_MAX_COUNT);

/**
 * Keys for events that are being listened to. This is used once there are more
 * than one event to listen to. If there is only one event to listen to, key_
 * is used.
 * @type {Object}
 * @private
 */
goog.events.EventHandler.keys_ = null;

/**
 * Keys for event that is being listened to if only one event is being listened
 * to. This is a performance optimization to avoid creating an extra object
 * if not necessary.
 * @type {?string}
 * @private
 */
goog.events.EventHandler.key_ = null;

/**
 * Listen to an event on a DOM node or EventTarget.  If the function is omitted
 * then the EventHandler's handleEvent method will be used.
 * @param {goog.events.EventTarget|EventTarget} src Event source.
 * @param {string|Array.<string>} type Event type to listen for or array of
 *     event types.
 * @param {Function|Object=} opt_fn Optional callback function to be used as the
 *    listener or an object with handleEvent function.
 * @param {boolean=} opt_capture Optional whether to use capture phase.
 * @param {Object=} opt_handler Object in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.listen = function(src, type, opt_fn,
                                                     opt_capture,
                                                     opt_handler) {
  if (goog.isArray(type)) {
    for (var i = 0; i < type.length; i++) {
      this.listen(src, type[i], opt_fn, opt_capture, opt_handler);
    }
  } else {
    var key = (/** @type {number} */
        goog.events.listen(src, type, opt_fn || this,
                           opt_capture || false,
                           opt_handler || this.handler_ || this));
    this.recordListenerKey_(key);
  }

  return this;
};

/**
 * Listen to an event on a DOM node or EventTarget.  If the function is omitted
 * then the EventHandler's handleEvent method will be used. After the event has
 * fired the event listener is removed from the target. If an array of event
 * types is provided, each event type will be listened to once.
 * @param {goog.events.EventTarget|EventTarget} src Event source.
 * @param {string|Array.<string>} type Event type to listen for or array of
 *     event types.
 * @param {Function|Object=} opt_fn Optional callback function to be used as the
 *    listener or an object with handleEvent function.
 * @param {boolean=} opt_capture Optional whether to use capture phase.
 * @param {Object=} opt_handler Object in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.listenOnce = function(src, type, opt_fn,
                                                         opt_capture,
                                                         opt_handler) {
  if (goog.isArray(type)) {
    for (var i = 0; i < type.length; i++) {
      this.listenOnce(src, type[i], opt_fn, opt_capture, opt_handler);
    }
  } else {
    var key = (/** @type {number} */
        goog.events.listenOnce(src, type, opt_fn || this,
                               opt_capture || false,
                               opt_handler || this.handler_ || this));
    this.recordListenerKey_(key);
  }

  return this;
};

/**
 * Adds an event listener with a specific event wrapper on a DOM Node or an
 * object that has implemented {@link goog.events.EventTarget}. A listener can
 * only be added once to an object.
 *
 * @param {EventTarget|goog.events.EventTarget} src The node to listen to
 *     events on.
 * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
 * @param {Function|Object} listener Callback method, or an object with a
 *     handleEvent function.
 * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
 *     false).
 * @param {Object=} opt_handler Element in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.listenWithWrapper = function(src, wrapper,
    listener, opt_capt, opt_handler) {
  wrapper.listen(src, listener, opt_capt, opt_handler || this.handler_, this);
  return this;
};

/**
 * Record the key returned for the listener so that it can be user later
 * to remove the listener.
 * @param {number} key Unique key for the listener.
 * @private
 */
goog.events.EventHandler.prototype.recordListenerKey_ = function(key) {
  if (this.keys_) {
    // already have multiple keys
    this.keys_[key] = true;
  } else if (this.key_) {
    // going from one key to multiple - must now use object as map
    this.keys_ = goog.events.EventHandler.keyPool_.getObject();
    this.keys_[this.key_] = true;
    this.key_ = null;
    this.keys_[key] = true;
  } else {
    // first key - can use single key
    this.key_ = key;
  }
};

/**
 * Unlistens on an event.
 * @param {goog.events.EventTarget|EventTarget} src Event source.
 * @param {string|Array.<string>} type Event type to listen for.
 * @param {Function|Object=} opt_fn Optional callback function to be used as the
 *    listener or an object with handleEvent function.
 * @param {boolean=} opt_capture Optional whether to use capture phase.
 * @param {Object=} opt_handler Object in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn,
                                                       opt_capture,
                                                       opt_handler) {
  if (this.key_ || this.keys_) {
    if (goog.isArray(type)) {
      for (var i = 0; i < type.length; i++) {
        this.unlisten(src, type[i], opt_fn, opt_capture, opt_handler);
      }
    } else {
      var listener = goog.events.getListener(src, type, opt_fn || this,
          opt_capture || false, opt_handler || this.handler_ || this);

      if (listener) {
        var key = listener.key;
        goog.events.unlistenByKey(key);

        if (this.keys_) {
          goog.object.remove(this.keys_, key);
        } else if (this.key_ == key) {
          this.key_ = null;
        }
      }
    }
  }

  return this;
};

/**
 * Removes an event listener which was added with listenWithWrapper().
 *
 * @param {EventTarget|goog.events.EventTarget} src The target to stop
 *     listening to events on.
 * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
 * @param {Function|Object} listener The listener function to remove.
 * @param {boolean=} opt_capt In DOM-compliant browsers, this determines
 *     whether the listener is fired during the capture or bubble phase of the
 *     event.
 * @param {Object=} opt_handler Element in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.unlistenWithWrapper = function(src, wrapper,
    listener, opt_capt, opt_handler) {
  wrapper.unlisten(src, listener, opt_capt, opt_handler || this.handler_, this);
  return this;
};

/**
 * Unlistens to all events.
 */
goog.events.EventHandler.prototype.removeAll = function() {
  if (this.keys_) {
    for (var key in this.keys_) {
      goog.events.unlistenByKey((/** @type {number} */ key));
      // Clean the keys before returning object to the pool.
      delete this.keys_[key];
    }
    goog.events.EventHandler.keyPool_.releaseObject(this.keys_);
    this.keys_ = null;

  } else if (this.key_) {
    goog.events.unlistenByKey(this.key_);
  }
};

/**
 * Disposes of this EventHandler and remove all listeners that it registered.
 */
goog.events.EventHandler.prototype.disposeInternal = function() {
  goog.events.EventHandler.superClass_.disposeInternal.call(this);
  this.removeAll();
};

/**
 * Default event handler
 * @param {goog.events.Event} e Event object.
 */
goog.events.EventHandler.prototype.handleEvent = function(e) {
  throw Error('EventHandler.handleEvent not implemented');
};
<commit_msg><commit_after>// Copyright 2005 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Class to create objects which want to handle multiple events
 * and have their listeners easily cleaned up via a dispose method.
 *
 * Example:
 *

 * function Something() {
 *   goog.events.EventHandler.call(this);
 *
 *   ... set up object ...
 *
 *   // Add event listeners
 *   this.listen(this.starEl, 'click', this.handleStar);
 *   this.listen(this.headerEl, 'click', this.expand);
 *   this.listen(this.collapseEl, 'click', this.collapse);
 *   this.listen(this.infoEl, 'mouseover', this.showHover);
 *   this.listen(this.infoEl, 'mouseout', this.hideHover);
 * }
 * goog.inherits(Something, goog.events.EventHandler);
 *
 * Something.prototype.disposeInternal = function() {
 *   Something.superClass_.disposeInternal.call(this);
 *   goog.dom.removeNode(this.container);
 * };
 *
 *
 * // Then elsewhere:
 *
 * var activeSomething = null;
 * function openSomething() {
 *   activeSomething = new Something();
 * }
 *
 * function closeSomething() {
 *   if (activeSomething) {
 *     activeSomething.dispose();  // Remove event listeners
 *     activeSomething = null;
 *   }
 * }
 *

 *
 */

goog.provide('goog.events.EventHandler');

goog.require('goog.Disposable');
goog.require('goog.events');
goog.require('goog.events.EventWrapper');
goog.require('goog.object');
goog.require('goog.structs.SimplePool');

/**
 * Super class for objects that want to easily manage a number of event
 * listeners.  It allows a short cut to listen and also provides a quick way
 * to remove all events listeners belonging to this object. It is optimized to
 * use less objects if only one event is being listened to, but if that's the
 * case, it may not be worth using the EventHandler anyway.
 * @param {Object=} opt_handler Object in whose scope to call the listeners.
 * @constructor
 * @extends {goog.Disposable}
 */
goog.events.EventHandler = function(opt_handler) {
  this.handler_ = opt_handler;
};
goog.inherits(goog.events.EventHandler, goog.Disposable);

/**
 * Initial count for the keyPool_
 * @type {number}
 */
goog.events.EventHandler.KEY_POOL_INITIAL_COUNT = 0;

/**
 * Max count for the keyPool_
 * @type {number}
 */
goog.events.EventHandler.KEY_POOL_MAX_COUNT = 100;

/**
 * SimplePool to cache the key object. This was implemented to make IE6
 * performance better and removed an object allocation in the listen method
 * when in steady state.
 * @type {goog.structs.SimplePool}
 * @private
 */
goog.events.EventHandler.keyPool_ = new goog.structs.SimplePool(
    goog.events.EventHandler.KEY_POOL_INITIAL_COUNT,
    goog.events.EventHandler.KEY_POOL_MAX_COUNT);

/**
 * Keys for events that are being listened to. This is used once there are more
 * than one event to listen to. If there is only one event to listen to, key_
 * is used.
 * @type {Object}
 * @private
 */
goog.events.EventHandler.keys_ = null;

/**
 * Keys for event that is being listened to if only one event is being listened
 * to. This is a performance optimization to avoid creating an extra object
 * if not necessary.
 * @type {?string}
 * @private
 */
goog.events.EventHandler.key_ = null;

/**
 * Utility array used to unify the cases of listening for an array of types
 * and listening for a single event, without using recursion or allocating
 * an array each time.
 * @type {Array.<string>}
 * @private
 */
goog.events.EventHandler.typeArray_ = [];

/**
 * Listen to an event on a DOM node or EventTarget.  If the function is omitted
 * then the EventHandler's handleEvent method will be used.
 * @param {goog.events.EventTarget|EventTarget} src Event source.
 * @param {string|Array.<string>} type Event type to listen for or array of
 *     event types.
 * @param {Function|Object=} opt_fn Optional callback function to be used as the
 *    listener or an object with handleEvent function.
 * @param {boolean=} opt_capture Optional whether to use capture phase.
 * @param {Object=} opt_handler Object in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.listen = function(src, type, opt_fn,
                                                     opt_capture,
                                                     opt_handler) {
  if (!goog.isArray(type)) {
    goog.events.EventHandler.typeArray_[0] = /** @type {string} */(type);
    type = goog.events.EventHandler.typeArray_;
  }
  for (var i = 0; i < type.length; i++) {
    var key = (/** @type {number} */
        goog.events.listen(src, type[i], opt_fn || this,
                           opt_capture || false,
                           opt_handler || this.handler_ || this));
    this.recordListenerKey_(key);
  }

  return this;
};

/**
 * Listen to an event on a DOM node or EventTarget.  If the function is omitted
 * then the EventHandler's handleEvent method will be used. After the event has
 * fired the event listener is removed from the target. If an array of event
 * types is provided, each event type will be listened to once.
 * @param {goog.events.EventTarget|EventTarget} src Event source.
 * @param {string|Array.<string>} type Event type to listen for or array of
 *     event types.
 * @param {Function|Object=} opt_fn Optional callback function to be used as the
 *    listener or an object with handleEvent function.
 * @param {boolean=} opt_capture Optional whether to use capture phase.
 * @param {Object=} opt_handler Object in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.listenOnce = function(src, type, opt_fn,
                                                         opt_capture,
                                                         opt_handler) {
  if (goog.isArray(type)) {
    for (var i = 0; i < type.length; i++) {
      this.listenOnce(src, type[i], opt_fn, opt_capture, opt_handler);
    }
  } else {
    var key = (/** @type {number} */
        goog.events.listenOnce(src, type, opt_fn || this,
                               opt_capture || false,
                               opt_handler || this.handler_ || this));
    this.recordListenerKey_(key);
  }

  return this;
};

/**
 * Adds an event listener with a specific event wrapper on a DOM Node or an
 * object that has implemented {@link goog.events.EventTarget}. A listener can
 * only be added once to an object.
 *
 * @param {EventTarget|goog.events.EventTarget} src The node to listen to
 *     events on.
 * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
 * @param {Function|Object} listener Callback method, or an object with a
 *     handleEvent function.
 * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
 *     false).
 * @param {Object=} opt_handler Element in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.listenWithWrapper = function(src, wrapper,
    listener, opt_capt, opt_handler) {
  wrapper.listen(src, listener, opt_capt, opt_handler || this.handler_, this);
  return this;
};

/**
 * Record the key returned for the listener so that it can be user later
 * to remove the listener.
 * @param {number} key Unique key for the listener.
 * @private
 */
goog.events.EventHandler.prototype.recordListenerKey_ = function(key) {
  if (this.keys_) {
    // already have multiple keys
    this.keys_[key] = true;
  } else if (this.key_) {
    // going from one key to multiple - must now use object as map
    this.keys_ = goog.events.EventHandler.keyPool_.getObject();
    this.keys_[this.key_] = true;
    this.key_ = null;
    this.keys_[key] = true;
  } else {
    // first key - can use single key
    this.key_ = key;
  }
};

/**
 * Unlistens on an event.
 * @param {goog.events.EventTarget|EventTarget} src Event source.
 * @param {string|Array.<string>} type Event type to listen for.
 * @param {Function|Object=} opt_fn Optional callback function to be used as the
 *    listener or an object with handleEvent function.
 * @param {boolean=} opt_capture Optional whether to use capture phase.
 * @param {Object=} opt_handler Object in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn,
                                                       opt_capture,
                                                       opt_handler) {
  if (this.key_ || this.keys_) {
    if (goog.isArray(type)) {
      for (var i = 0; i < type.length; i++) {
        this.unlisten(src, type[i], opt_fn, opt_capture, opt_handler);
      }
    } else {
      var listener = goog.events.getListener(src, type, opt_fn || this,
          opt_capture || false, opt_handler || this.handler_ || this);

      if (listener) {
        var key = listener.key;
        goog.events.unlistenByKey(key);

        if (this.keys_) {
          goog.object.remove(this.keys_, key);
        } else if (this.key_ == key) {
          this.key_ = null;
        }
      }
    }
  }

  return this;
};

/**
 * Removes an event listener which was added with listenWithWrapper().
 *
 * @param {EventTarget|goog.events.EventTarget} src The target to stop
 *     listening to events on.
 * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
 * @param {Function|Object} listener The listener function to remove.
 * @param {boolean=} opt_capt In DOM-compliant browsers, this determines
 *     whether the listener is fired during the capture or bubble phase of the
 *     event.
 * @param {Object=} opt_handler Element in whose scope to call the listener.
 * @return {goog.events.EventHandler} This object, allowing for chaining of
 *     calls.
 */
goog.events.EventHandler.prototype.unlistenWithWrapper = function(src, wrapper,
    listener, opt_capt, opt_handler) {
  wrapper.unlisten(src, listener, opt_capt, opt_handler || this.handler_, this);
  return this;
};

/**
 * Unlistens to all events.
 */
goog.events.EventHandler.prototype.removeAll = function() {
  if (this.keys_) {
    for (var key in this.keys_) {
      goog.events.unlistenByKey((/** @type {number} */ key));
      // Clean the keys before returning object to the pool.
      delete this.keys_[key];
    }
    goog.events.EventHandler.keyPool_.releaseObject(this.keys_);
    this.keys_ = null;

  } else if (this.key_) {
    goog.events.unlistenByKey(this.key_);
  }
};

/**
 * Disposes of this EventHandler and remove all listeners that it registered.
 */
goog.events.EventHandler.prototype.disposeInternal = function() {
  goog.events.EventHandler.superClass_.disposeInternal.call(this);
  this.removeAll();
};

/**
 * Default event handler
 * @param {goog.events.Event} e Event object.
 */
goog.events.EventHandler.prototype.handleEvent = function(e) {
  throw Error('EventHandler.handleEvent not implemented');
};
<|endoftext|>


<commit_before>var hrtime = require('browser-process-hrtime')
var winston = require('winston')
var winstonWrapper = require('winston-meta-wrapper')
var NanoTimer = require('nanotimer')
var Clock = require('./clock.js')
var constants = require('./constants.js')
var utils = require('./utils.js')

var Chicago = function (options) {
  if (!options) {
    options = {}
  }
  if (!options.logger) {
    options.logger = winston
  }
  this._log = winstonWrapper(options.logger)
  this._log.addMeta({
    module: 'curvecp-chicago'
  })
  /* Clock instance */
  this.clock = new Clock([0, 0])
  this._refresh_clock()
  /* Smoothed Round Trip Time (SRTT) in nanoseconds */
  this.rtt_average = 0
  /* RTTVAR  in nanoseconds */
  this.rtt_deviation = 0
  this.rtt_highwater = 0
  this.rtt_lowwater = 0
  /* RTO in nanoseconds */
  this.rtt_timeout = constants.SECOND
  this.seen_recent_high = false
  this.seen_recent_low = false
  this.seen_older_high = false
  this.seen_older_low = false
  this.rtt_phase = 0
  /* Sending rate (nanosecond interval between blocks) */
  this.nsecperblock = constants.SECOND
  /* Clock instance */
  this.lastblocktime
  /* Clock instance */
  this.lastspeedadjustment = this.clock
  /* Clock instance */
  this.lastedge = new Clock([0, 0])
  /* Clock instance */
  this.lastdoubling = new Clock([0, 0])
  /* Clock instance */
  this.lastpanic = new Clock([0, 0])
  this.timer = new NanoTimer()
  this._set_timeout()
  this.timer_disabled = false
}

/* TIMER */

Chicago.prototype.set_timeout = function (func) {
  this.timeout_callback = func
}

Chicago.prototype.disable_timer = function () {
  this.timer_disabled = true
}

Chicago.prototype.enable_timer = function () {
  if (this.timer_disabled) {
    this.timer_disabled = false
    this._set_timeout()
  }
}

Chicago.prototype._timeout_callback = function () {
  if (this.timeout_callback) {
    this.timeout_callback()
  }
  if (!this.timer_disabled) {
    this._set_timeout()
  }
}

Chicago.prototype._set_timeout = function () {
  this._log.debug('_set_timeout ' + this.nsecperblock)
  this.timer.setTimeout(this._timeout_callback.bind(this), [], this.nsecperblock.toString() + 'n')
}

/* CLOCK */

Chicago.prototype._refresh_clock = function () {
  this.clock = new Clock(hrtime())
}

Chicago.prototype.get_clock = function () {
  this._refresh_clock()
  return this.clock.clone()
}

/* SEND BLOCK */

Chicago.prototype.send_block = function () {
  this._refresh_clock()
  this.lastblocktime = this.clock.clone()
}

/* RETRANSMISSION */

Chicago.prototype.block_is_timed_out = function (transmissionTime) {
  this._refresh_clock()
  var clock = transmissionTime.clone()
  clock.add(this.rtt_timeout)
  var compareResult = clock.compare(this.clock)
  if (compareResult === -1) {
    return true
  } else {
    return false
  }
}

Chicago.prototype.retransmission = function () {
  this._refresh_clock()
  var clock = this.lastpanic.clone()
  clock.add(4 * this.rtt_timeout)
  var compareResult = this.clock.compare(clock)
  if (compareResult === 1) {
    this._halve_transmission_rate()
  }
}

Chicago.prototype._halve_transmission_rate = function () {
  this.nsecperblock = utils.safeIntegerMultiplication(this.nsecperblock, 2)
  this.lastpanic = this.clock.clone()
  this.lastedge = this.clock.clone()
}

/* MESSAGE ACKNOWLEDGEMENT */

Chicago.prototype.acknowledgement = function (originalBlocktime) {
  this._refresh_clock()
  var rtt = this._initialize_rtt(originalBlocktime)
  this._jacobson_retransmission_timeout(rtt)
  this._compensate_delayed_acks()
  this._track_watermarks(rtt)
  this._check_for_watermarks()
  if (this._adjustment_cycle_has_completed()) {
    this._reinitialize_lastspeedadjustment()
    this._apply_additive_increase()
    this._phase_events()
    this._update_seen_watermarks()
  }
  this._apply_rate_doubling()
}

Chicago.prototype._initialize_rtt = function (originalBlocktime) {
  var rtt = this.clock.subtract(originalBlocktime)
  if (!this.rtt_average) {
    this.nsecperblock = rtt
    this.rtt_average = rtt
    this.rtt_deviation = rtt / 2
    this.rtt_highwater = rtt
    this.rtt_lowwater = rtt
  }
  return rtt
}

Chicago.prototype._jacobson_retransmission_timeout = function (rtt) {
  /* Jacobon's retransmission timeout calculation */
  var rttDelta = rtt - this.rtt_average
  this.rtt_average = utils.safeIntegerAddition(this.rtt_average, rttDelta / 8)
  if (rttDelta < 0) {
    rttDelta = -rttDelta
  }
  rttDelta -= this.rtt_deviation
  this.rtt_deviation = utils.safeIntegerAddition(this.rtt_deviation, rttDelta / 4)
  this.rtt_timeout = utils.safeIntegerAddition(this.rtt_average, utils.safeIntegerMultiplication(this.rtt_deviation, 4))
}

Chicago.prototype._compensate_delayed_acks = function () {
  /* adjust for delayed acks with anti-spiking */
  this.rtt_timeout = utils.safeIntegerAddition(this.rtt_timeout, 8 * this.nsecperblock)
}

Chicago.prototype._track_watermarks = function (rtt) {
  /* Adjust high watermark of congestion cycle */
  var rttDelta = rtt - this.rtt_highwater
  this.rtt_highwater = utils.safeIntegerAddition(this.rtt_highwater, rttDelta / 1024)
  /* Adjust low watermark of congestion cycle */
  rttDelta = rtt - this.rtt_lowwater
  if (rttDelta > 0) {
    this.rtt_lowwater = utils.safeIntegerAddition(this.rtt_lowwater, rttDelta / 8192)
  } else {
    this.rtt_lowwater = utils.safeIntegerAddition(this.rtt_lowwater, rttDelta / 256)
  }
}

Chicago.prototype._check_for_watermarks = function () {
  if (this.rtt_average > utils.safeIntegerAddition(this.rtt_highwater, 5 * constants.MILLISECOND)) {
    this.rtt_seenrecenthigh = true
  } else if (this.rtt_average < this.rtt_lowwater) {
    this.rtt_seenrecentlow = true
  }
}

// Start new adjustment cycle (at least 16 tranmsission periods have elapsed)
Chicago.prototype._adjustment_cycle_has_completed = function () {
  var cycle = utils.safeIntegerMultiplication(this.nsecperblock, 16)
  var endOfCycle = new Clock([this.lastspeedadjustment.seconds, this.lastspeedadjustment.nanoseconds])
  endOfCycle.add(cycle)
  var result = this.clock.compare(endOfCycle)
  return result >= 0
}

Chicago.prototype._reinitialize_lastspeedadjustment = function () {
  this._log.debug('_reinitialize_lastspeedadjustment ' + this.nsecperblock)
  if (this.clock.subtract(this.lastspeedadjustment) > 10 * constants.SECOND) {
    this.nsecperblock = constants.SECOND /* slow restart */
    this.nsecperblock = utils.safeIntegerAddition(this.nsecperblock, utils.randommod(this.nsecperblock / 8))
  }
  this.lastspeedadjustment = this.clock.clone()
}

Chicago.prototype._apply_additive_increase = function () {
  this._log.debug('_apply_additive_increase ' + this.nsecperblock)
  if (this.nsecperblock >= 131072) {
    /* additive increase: adjust 1/N by a constant c */
    /* rtt-fair additive increase: adjust 1/N by a constant c every nanosecond */
    /* approximation: adjust 1/N by cN every N nanoseconds */
    /* i.e., N <- 1/(1/N + cN) = N/(1 + cN^2) every N nanoseconds */
    if (this.nsecperblock < 16777216) {
      /* N/(1+cN^2) approx N - cN^3 */
      var u = this.nsecperblock / 131072
      var u3 = utils.safeIntegerMultiplication(utils.safeIntegerMultiplication(u, u), u)
      this.nsecperblock = this.nsecperblock - u3
    } else {
      var d = this.nsecperblock
      this.nsecperblock = d / (1 + ((d * d) / 2251799813685248.0))
    }
  }
}

Chicago.prototype._phase_events = function () {
  this._log.debug('_phase_events ' + this.nsecperblock)
  if (this.rtt_phase === 0) {
    if (this.rtt_seenolderhigh) {
      this.rtt_phase = 1
      this.lastedge = this.clock
      this.nsecperblock = utils.safeIntegerAddition(this.nsecperblock, utils.randommod(this.nsecperblock / 4))
    }
  } else {
    if (this.rtt_seenolderlow) {
      this.rtt_phase = 0
    }
  }
}

Chicago.prototype._update_seen_watermarks = function () {
  this.rtt_seenolderhigh = this.rtt_seenrecenthigh
  this.rtt_seenolderlow = this.rtt_seenrecentlow
  this.rtt_seenrecenthigh = false
  this.rtt_seenrecentlow = false
}

Chicago.prototype._apply_rate_doubling = function () {
  this._log.debug('_apply_rate_doubling ' + this.nsecperblock)
  var compareClock
  var result
  while (true) {
    var n4 = utils.safeIntegerMultiplication(this.nsecperblock, 4)
    if (this.clock.subtract(this.lastedge) < 60 * constants.SECOND) {
      var rto64 = utils.safeIntegerMultiplication(this.rtt_timeout, 64)
      compareClock = this.lastdoubling.clone()
      compareClock.add(n4)
      compareClock.add(rto64)
      compareClock.add(5 * constants.SECOND)
      result = this.clock.compare(compareClock)
      if (result === -1) {
        break
      }
    } else {
      var rto2 = utils.safeIntegerMultiplication(this.rtt_timeout, 2)
      compareClock = this.lastdoubling.clone()
      compareClock.add(n4)
      compareClock.add(rto2)
      result = this.clock.compare(compareClock)
      if (result === -1) {
        break
      }
    }
    if (this.nsecperblock <= 65535) {
      break
    }
    this.nsecperblock = this.nsecperblock / 2
    this.lastdoubling = this.clock.clone()
    if (this.lastedge) {
      this.lastedge = this.clock.clone()
    }
  }
}

module.exports = Chicago
<commit_msg>support process.hrtime and setImmediate in browser<commit_after>var hrtime = require('browser-process-hrtime')
process.hrtime = hrtime
global.setImmediate = require('async.util.setimmediate')
var winston = require('winston')
var winstonWrapper = require('winston-meta-wrapper')
var NanoTimer = require('nanotimer')
var Clock = require('./clock.js')
var constants = require('./constants.js')
var utils = require('./utils.js')

var Chicago = function (options) {
  if (!options) {
    options = {}
  }
  if (!options.logger) {
    options.logger = winston
  }
  this._log = winstonWrapper(options.logger)
  this._log.addMeta({
    module: 'curvecp-chicago'
  })
  /* Clock instance */
  this.clock = new Clock([0, 0])
  this._refresh_clock()
  /* Smoothed Round Trip Time (SRTT) in nanoseconds */
  this.rtt_average = 0
  /* RTTVAR  in nanoseconds */
  this.rtt_deviation = 0
  this.rtt_highwater = 0
  this.rtt_lowwater = 0
  /* RTO in nanoseconds */
  this.rtt_timeout = constants.SECOND
  this.seen_recent_high = false
  this.seen_recent_low = false
  this.seen_older_high = false
  this.seen_older_low = false
  this.rtt_phase = 0
  /* Sending rate (nanosecond interval between blocks) */
  this.nsecperblock = constants.SECOND
  /* Clock instance */
  this.lastblocktime
  /* Clock instance */
  this.lastspeedadjustment = this.clock
  /* Clock instance */
  this.lastedge = new Clock([0, 0])
  /* Clock instance */
  this.lastdoubling = new Clock([0, 0])
  /* Clock instance */
  this.lastpanic = new Clock([0, 0])
  this.timer = new NanoTimer()
  this._set_timeout()
  this.timer_disabled = false
}

/* TIMER */

Chicago.prototype.set_timeout = function (func) {
  this.timeout_callback = func
}

Chicago.prototype.disable_timer = function () {
  this.timer_disabled = true
}

Chicago.prototype.enable_timer = function () {
  if (this.timer_disabled) {
    this.timer_disabled = false
    this._set_timeout()
  }
}

Chicago.prototype._timeout_callback = function () {
  if (this.timeout_callback) {
    this.timeout_callback()
  }
  if (!this.timer_disabled) {
    this._set_timeout()
  }
}

Chicago.prototype._set_timeout = function () {
  this._log.debug('_set_timeout ' + this.nsecperblock)
  this.timer.setTimeout(this._timeout_callback.bind(this), [], this.nsecperblock.toString() + 'n')
}

/* CLOCK */

Chicago.prototype._refresh_clock = function () {
  this.clock = new Clock(hrtime())
}

Chicago.prototype.get_clock = function () {
  this._refresh_clock()
  return this.clock.clone()
}

/* SEND BLOCK */

Chicago.prototype.send_block = function () {
  this._refresh_clock()
  this.lastblocktime = this.clock.clone()
}

/* RETRANSMISSION */

Chicago.prototype.block_is_timed_out = function (transmissionTime) {
  this._refresh_clock()
  var clock = transmissionTime.clone()
  clock.add(this.rtt_timeout)
  var compareResult = clock.compare(this.clock)
  if (compareResult === -1) {
    return true
  } else {
    return false
  }
}

Chicago.prototype.retransmission = function () {
  this._refresh_clock()
  var clock = this.lastpanic.clone()
  clock.add(4 * this.rtt_timeout)
  var compareResult = this.clock.compare(clock)
  if (compareResult === 1) {
    this._halve_transmission_rate()
  }
}

Chicago.prototype._halve_transmission_rate = function () {
  this.nsecperblock = utils.safeIntegerMultiplication(this.nsecperblock, 2)
  this.lastpanic = this.clock.clone()
  this.lastedge = this.clock.clone()
}

/* MESSAGE ACKNOWLEDGEMENT */

Chicago.prototype.acknowledgement = function (originalBlocktime) {
  this._refresh_clock()
  var rtt = this._initialize_rtt(originalBlocktime)
  this._jacobson_retransmission_timeout(rtt)
  this._compensate_delayed_acks()
  this._track_watermarks(rtt)
  this._check_for_watermarks()
  if (this._adjustment_cycle_has_completed()) {
    this._reinitialize_lastspeedadjustment()
    this._apply_additive_increase()
    this._phase_events()
    this._update_seen_watermarks()
  }
  this._apply_rate_doubling()
}

Chicago.prototype._initialize_rtt = function (originalBlocktime) {
  var rtt = this.clock.subtract(originalBlocktime)
  if (!this.rtt_average) {
    this.nsecperblock = rtt
    this.rtt_average = rtt
    this.rtt_deviation = rtt / 2
    this.rtt_highwater = rtt
    this.rtt_lowwater = rtt
  }
  return rtt
}

Chicago.prototype._jacobson_retransmission_timeout = function (rtt) {
  /* Jacobon's retransmission timeout calculation */
  var rttDelta = rtt - this.rtt_average
  this.rtt_average = utils.safeIntegerAddition(this.rtt_average, rttDelta / 8)
  if (rttDelta < 0) {
    rttDelta = -rttDelta
  }
  rttDelta -= this.rtt_deviation
  this.rtt_deviation = utils.safeIntegerAddition(this.rtt_deviation, rttDelta / 4)
  this.rtt_timeout = utils.safeIntegerAddition(this.rtt_average, utils.safeIntegerMultiplication(this.rtt_deviation, 4))
}

Chicago.prototype._compensate_delayed_acks = function () {
  /* adjust for delayed acks with anti-spiking */
  this.rtt_timeout = utils.safeIntegerAddition(this.rtt_timeout, 8 * this.nsecperblock)
}

Chicago.prototype._track_watermarks = function (rtt) {
  /* Adjust high watermark of congestion cycle */
  var rttDelta = rtt - this.rtt_highwater
  this.rtt_highwater = utils.safeIntegerAddition(this.rtt_highwater, rttDelta / 1024)
  /* Adjust low watermark of congestion cycle */
  rttDelta = rtt - this.rtt_lowwater
  if (rttDelta > 0) {
    this.rtt_lowwater = utils.safeIntegerAddition(this.rtt_lowwater, rttDelta / 8192)
  } else {
    this.rtt_lowwater = utils.safeIntegerAddition(this.rtt_lowwater, rttDelta / 256)
  }
}

Chicago.prototype._check_for_watermarks = function () {
  if (this.rtt_average > utils.safeIntegerAddition(this.rtt_highwater, 5 * constants.MILLISECOND)) {
    this.rtt_seenrecenthigh = true
  } else if (this.rtt_average < this.rtt_lowwater) {
    this.rtt_seenrecentlow = true
  }
}

// Start new adjustment cycle (at least 16 tranmsission periods have elapsed)
Chicago.prototype._adjustment_cycle_has_completed = function () {
  var cycle = utils.safeIntegerMultiplication(this.nsecperblock, 16)
  var endOfCycle = new Clock([this.lastspeedadjustment.seconds, this.lastspeedadjustment.nanoseconds])
  endOfCycle.add(cycle)
  var result = this.clock.compare(endOfCycle)
  return result >= 0
}

Chicago.prototype._reinitialize_lastspeedadjustment = function () {
  this._log.debug('_reinitialize_lastspeedadjustment ' + this.nsecperblock)
  if (this.clock.subtract(this.lastspeedadjustment) > 10 * constants.SECOND) {
    this.nsecperblock = constants.SECOND /* slow restart */
    this.nsecperblock = utils.safeIntegerAddition(this.nsecperblock, utils.randommod(this.nsecperblock / 8))
  }
  this.lastspeedadjustment = this.clock.clone()
}

Chicago.prototype._apply_additive_increase = function () {
  this._log.debug('_apply_additive_increase ' + this.nsecperblock)
  if (this.nsecperblock >= 131072) {
    /* additive increase: adjust 1/N by a constant c */
    /* rtt-fair additive increase: adjust 1/N by a constant c every nanosecond */
    /* approximation: adjust 1/N by cN every N nanoseconds */
    /* i.e., N <- 1/(1/N + cN) = N/(1 + cN^2) every N nanoseconds */
    if (this.nsecperblock < 16777216) {
      /* N/(1+cN^2) approx N - cN^3 */
      var u = this.nsecperblock / 131072
      var u3 = utils.safeIntegerMultiplication(utils.safeIntegerMultiplication(u, u), u)
      this.nsecperblock = this.nsecperblock - u3
    } else {
      var d = this.nsecperblock
      this.nsecperblock = d / (1 + ((d * d) / 2251799813685248.0))
    }
  }
}

Chicago.prototype._phase_events = function () {
  this._log.debug('_phase_events ' + this.nsecperblock)
  if (this.rtt_phase === 0) {
    if (this.rtt_seenolderhigh) {
      this.rtt_phase = 1
      this.lastedge = this.clock
      this.nsecperblock = utils.safeIntegerAddition(this.nsecperblock, utils.randommod(this.nsecperblock / 4))
    }
  } else {
    if (this.rtt_seenolderlow) {
      this.rtt_phase = 0
    }
  }
}

Chicago.prototype._update_seen_watermarks = function () {
  this.rtt_seenolderhigh = this.rtt_seenrecenthigh
  this.rtt_seenolderlow = this.rtt_seenrecentlow
  this.rtt_seenrecenthigh = false
  this.rtt_seenrecentlow = false
}

Chicago.prototype._apply_rate_doubling = function () {
  this._log.debug('_apply_rate_doubling ' + this.nsecperblock)
  var compareClock
  var result
  while (true) {
    var n4 = utils.safeIntegerMultiplication(this.nsecperblock, 4)
    if (this.clock.subtract(this.lastedge) < 60 * constants.SECOND) {
      var rto64 = utils.safeIntegerMultiplication(this.rtt_timeout, 64)
      compareClock = this.lastdoubling.clone()
      compareClock.add(n4)
      compareClock.add(rto64)
      compareClock.add(5 * constants.SECOND)
      result = this.clock.compare(compareClock)
      if (result === -1) {
        break
      }
    } else {
      var rto2 = utils.safeIntegerMultiplication(this.rtt_timeout, 2)
      compareClock = this.lastdoubling.clone()
      compareClock.add(n4)
      compareClock.add(rto2)
      result = this.clock.compare(compareClock)
      if (result === -1) {
        break
      }
    }
    if (this.nsecperblock <= 65535) {
      break
    }
    this.nsecperblock = this.nsecperblock / 2
    this.lastdoubling = this.clock.clone()
    if (this.lastedge) {
      this.lastedge = this.clock.clone()
    }
  }
}

module.exports = Chicago
<|endoftext|>


<commit_before>var queryMethod = require("./helpers").queryMethod
var EventProxy = require('./event-proxy')
var StateMachine = require('./state-machine')
var QueryAdapter = require('./query-adapter')

module.exports = Transaction

require('util').inherits(Transaction, EventProxy)

function Transaction () {
	this.handleError = _handleError.bind(this)

	StateMachine.call(this, 'pending', {
		'query': {
			'pending':     queueQuery,
			'opening':     queueQuery,
			'dequeueing':  queueQuery,
			'open':        doQuery,
			'rolled back': rejectQuery,
			'committed':   rejectQuery,
			'errored':     rejectQuery,
		},
		// Allow rollback to be called repeatedly
		'rollback': {
			'rolled back': function () {}
		}
	}, {
		'pending':      [ 'opening' ],
		'opening':      [ 'dequeueing' ],
		'dequeueing':   [ 'open', 'rolled back', 'committed' ],
		'open':         [ 'open', 'rolled back', 'committed' ],
		'errored':      [ 'rolled back' ],
	}, this.handleError)

	this._queue = []
	this.query = queueQuery
	this.log = false
}

function _handleError (err, callback) {
	var propagate = callback || this.emit.bind(this, 'error')
	var rolledBack = this.state() == 'rolled back'
	this.state('errored')
	if (!rolledBack) this.rollback(function (rollbackErr) {
		if (rollbackErr) {
			err = new Error('Failed to rollback transaction: ' + rollbackErr
			                + '\nError causing rollback: ' + err)
		}
		propagate(err)
	})
	else process.nextTick(propagate.bind(this, err))
}

Transaction.prototype.begin = function (conn, callback) {
	if (!this.state('opening', callback)) return this
	var self = this
	if (this.log) this.log('starting transaction')
	conn.query('begin', function (err) {
		if (err) return self.handleError(err, callback)
		self._connection = conn
		conn.on('error', self.handleError)
		var removeErrorListener = conn.removeListener.bind(conn, 'error', self.handleError)
		self.once('rollback', removeErrorListener)
		self.once('commit', removeErrorListener)
		self._runQueue(callback)
	})
	return this
}

Transaction.prototype._runQueue = function (callback) {
	if (!this.state('dequeueing', callback)) return
	var i = 0
	  , self = this
		, next
	;(next = (function () {
		var conn = this._connection
		var args = this._queue[i++]
		if (args) {
			this.log && this.log(args[0])
			var qa = conn.query.apply(conn, args)
			qa.listeners('end').unshift(next)
			// If no callback was given, the Transaction handles any errors
			if (!args[2]) qa.on('error', self.handleError)
		} else {
			// The queue is empty, queries can now go directly to the connection.
			this._queue = null
			if (this.state('open', callback) && callback) callback(null, this)
		}
	}).bind(this))()
}

var queueQuery = queryMethod(function (stmt, params, callback) {
	var qa = new QueryAdapter()
	this._queue.push([stmt, params, callback, qa])
	return qa
})

var doQuery = queryMethod(function (stmt, params, callback) {
	var qa = this._connection.query(stmt, params, callback)
	if (!callback) qa.on('error', this.handleError)
	return qa
})

var rejectQuery = queryMethod(function (stmt, params, callback) {
	var self = this
	  , qa = new QueryAdapter
	  , msg = "Cannot perform query in '" + this.state() + "' state. Query: " + stmt
	  , err = new Error(msg)
	process.nextTick(function () {
		if (callback) callback(err)
		else qa.emit('error', err)
	})
	return qa
})

Transaction.prototype.commit = sqlTransition('committed', 'commit')
Transaction.prototype.rollback = sqlTransition('rolled back', 'rollback')

function sqlTransition (newState, stmt) {
	return function (callback) {
		var self = this
		if (this.state(newState, callback)) {
			this._connection.query(stmt, callback)
		}
		return this
	}
}
<commit_msg>fixing transaction bugs<commit_after>var queryMethod = require("./helpers").queryMethod
var EventProxy = require('./event-proxy')
var StateMachine = require('./state-machine')
var QueryAdapter = require('./query-adapter')

module.exports = Transaction

require('util').inherits(Transaction, EventProxy)

function Transaction () {
	this.handleError = _handleError.bind(this)

	StateMachine.call(this, 'pending', {
		'query': {
			'pending':     queueQuery,
			'opening':     queueQuery,
			'dequeueing':  queueQuery,
			'open':        doQuery,
			'rolled back': rejectQuery,
			'committed':   rejectQuery,
			'errored':     rejectQuery,
		},
		// Allow rollback to be called repeatedly
		'rollback': {
			'rolled back': function () {}
		}
	}, {
		'pending':    [ 'opening' ],
		'opening':    [ 'dequeueing' ],
		'dequeueing': [ 'open', 'rolled back', 'committed' ],
		'open':       [ 'open', 'rolled back', 'committed' ],
		'errored':    [ 'rolled back' ],
	}, this.handleError)

	this._queue = []
	this.log = false
}

function _handleError (err, callback) {
	var propagate = callback || this.emit.bind(this, 'error')
	var rolledBack = this.state() == 'rolled back'
	this.state('errored')
	if (!rolledBack) this.rollback(function (rollbackErr) {
		if (rollbackErr) {
			err = new Error('Failed to rollback transaction: ' + rollbackErr
			                + '\nError causing rollback: ' + err)
		}
		propagate(err)
	})
	else process.nextTick(propagate.bind(this, err))
}

Transaction.prototype.begin = function (conn, callback) {
	if (!this.state('opening', callback)) return this
	var self = this
	if (this.log) this.log('starting transaction')
	conn.query('begin', function (err) {
		if (err) return self.handleError(err, callback)
		self._connection = conn
		conn.on('error', self.handleError)
		var removeErrorListener = conn.removeListener.bind(conn, 'error', self.handleError)
		self.once('rolled back', removeErrorListener)
		self.once('committed', removeErrorListener)
		self._runQueue(callback)
	})
	return this
}

Transaction.prototype._runQueue = function (callback) {
	if (!this.state('dequeueing', callback)) return
	var next = function () {
		var state = this.state()
		if (state == 'errored' || state == 'rolled back') return
		var conn = this._connection
		var args = this._queue.shift()
		var handleError = this.handleError
		if (args) {
			this.log && this.log(args[0])
			var queryCb = args[2]
			if (queryCb) {
				args[2] = function (err, res) {
					if (err) handleError(err, queryCb)
					else if (queryCb) queryCb(err, res)
				}
			}
			var qa = conn.query.apply(conn, args)
			qa.listeners('end').unshift(next)
			if (!queryCb) qa.once('error', function (err) {
				qa.listeners('error').length || handleError(err)
			})
		} else {
			// The queue is empty, queries can now go directly to the connection.
			this._queue = null
			if (this.state('open', callback) && callback) callback(null, this)
		}
	}.bind(this)
	next()
}

var queueQuery = queryMethod(function (stmt, params, callback) {
	var qa = new QueryAdapter()
	this._queue.push([stmt, params, callback, qa])
	return qa
})

var doQuery = queryMethod(function (stmt, params, callback) {
	var qa = this._connection.query(stmt, params, callback)
	if (!callback) qa.on('error', this.handleError)
	return qa
})

var rejectQuery = queryMethod(function (stmt, params, callback) {
	var self = this
	  , qa = new QueryAdapter
	  , msg = "Cannot perform query in '" + this.state() + "' state. Query: " + stmt
	  , err = new Error(msg)
	process.nextTick(function () {
		if (callback) callback(err)
		else qa.emit('error', err)
	})
	return qa
})

Transaction.prototype.commit = sqlTransition('committed', 'commit')
Transaction.prototype.rollback = sqlTransition('rolled back', 'rollback')

function sqlTransition (newState, stmt) {
	return function (callback) {
		var self = this
		if (this.state(newState, callback)) {
			this._connection.query(stmt, callback)
		}
		return this
	}
}
<|endoftext|>


<commit_before>
export const BOARD_SIZE = 7;
export const FINISH_SIZE = 4;

export default class Board {
  constructor () {
    this.initiate();
  }

  initiate () {
    this.pieces = { };

    for (let row = 0; row < BOARD_SIZE; row++) {
      for (let col = 0; col < BOARD_SIZE; col++) {
        this.pieces[`${row}${col}`] = 0;
      }
    }
  }

  getValueAt (row, col) {
    return this.pieces[`${row}${col}`];
  }

  playAtColWithValue (col, value) {
    for (let row = 0; row < BOARD_SIZE; row++) {
      const pos = `${row}${col}`;

      if (this.pieces[pos] === 0) {
        this.pieces[pos] = value;
        break;
      }
    }

    this.gameIsFinished(value);
  }

  gameIsFinishedHorizontally (x, y, value) {
    const result = [];

    for (let col = y; col < BOARD_SIZE; col++) {
      const pos = `${x}${col}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }
    }

    return null;
  }

  gameIsFinishedVertically (x, y, value) {
    const result = [];

    for (let row = x; row < BOARD_SIZE; row++) {
      const pos = `${row}${y}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }
    }

    return null;
  }

  gameIsFinishedDiagonallyAsc (x, y, value) {
    const result = [];
    let row = x;
    let col = y;

    while (row < BOARD_SIZE || col < BOARD_SIZE) {
      const pos = `${row}${col}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }

      row++;
      col++;
    }

    return null;
  }

  gameIsFinishedDiagonallyDesc (x, y, value) {
    const result = [];
    let row = x;
    let col = y;

    while (row >= 0 || col >= 0) {
      const pos = `${row}${col}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }

      row--;
      col--;
    }

    return null;
  }

  gameIsFinished (value) {
    let result = null;

    for (let row = 0; row < BOARD_SIZE; row++) {
      if (result) {
        break;
      }

      for (let col = 0; col < BOARD_SIZE; col++) {
        result = this.gameIsFinishedHorizontally(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`horizontally; ${result} = ${value}`);
          break;
        }

        result = this.gameIsFinishedVertically(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`vertically; ${result} = ${value}`);
          break;
        }

        result = this.gameIsFinishedDiagonallyAsc(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`diagonally1; ${result} = ${value}`);
          break;
        }

        result = this.gameIsFinishedDiagonallyDesc(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`diagonally2; ${result} = ${value}`);
          break;
        }
      }
    }
  }

  getPieces () {
    return this.pieces;
  }
}
<commit_msg>Add piece size<commit_after>
export const BOARD_SIZE = 7;
export const FINISH_SIZE = 4;
export const PIECE_SIZE = 80;

export default class Board {
  constructor () {
    this.initiate();
  }

  initiate () {
    this.pieces = { };

    for (let row = 0; row < BOARD_SIZE; row++) {
      for (let col = 0; col < BOARD_SIZE; col++) {
        this.pieces[`${row}${col}`] = 0;
      }
    }
  }

  getValueAt (row, col) {
    return this.pieces[`${row}${col}`];
  }

  playAtColWithValue (col, value) {
    for (let row = 0; row < BOARD_SIZE; row++) {
      const pos = `${row}${col}`;

      if (this.pieces[pos] === 0) {
        this.pieces[pos] = value;
        break;
      }
    }

    this.gameIsFinished(value);
  }

  gameIsFinishedHorizontally (x, y, value) {
    const result = [];

    for (let col = y; col < BOARD_SIZE; col++) {
      const pos = `${x}${col}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }
    }

    return null;
  }

  gameIsFinishedVertically (x, y, value) {
    const result = [];

    for (let row = x; row < BOARD_SIZE; row++) {
      const pos = `${row}${y}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }
    }

    return null;
  }

  gameIsFinishedDiagonallyAsc (x, y, value) {
    const result = [];
    let row = x;
    let col = y;

    while (row < BOARD_SIZE || col < BOARD_SIZE) {
      const pos = `${row}${col}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }

      row++;
      col++;
    }

    return null;
  }

  gameIsFinishedDiagonallyDesc (x, y, value) {
    const result = [];
    let row = x;
    let col = y;

    while (row >= 0 || col >= 0) {
      const pos = `${row}${col}`;

      if (this.pieces[pos] !== value) {
        return null;
      }

      result.push(pos);

      if (result.length === FINISH_SIZE) {
        return result;
      }

      row--;
      col--;
    }

    return null;
  }

  gameIsFinished (value) {
    let result = null;

    for (let row = 0; row < BOARD_SIZE; row++) {
      if (result) {
        break;
      }

      for (let col = 0; col < BOARD_SIZE; col++) {
        result = this.gameIsFinishedHorizontally(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`horizontally; ${result} = ${value}`);
          break;
        }

        result = this.gameIsFinishedVertically(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`vertically; ${result} = ${value}`);
          break;
        }

        result = this.gameIsFinishedDiagonallyAsc(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`diagonally1; ${result} = ${value}`);
          break;
        }

        result = this.gameIsFinishedDiagonallyDesc(row, col, value);
        if (result) {
          console.log(this.pieces);
          console.log(`diagonally2; ${result} = ${value}`);
          break;
        }
      }
    }
  }

  getPieces () {
    return this.pieces;
  }
}
<|endoftext|>


<commit_before>
// App.Glyph + name & mixins:
App.DynamicGlyph = function(properties) {
  properties = properties || {};
  App.Glyph.call(this, properties);   //<- sets ch, fg, bg
  this.name        = properties.name || '';
  this.mixins      = {};
  this.mixinGroups = {};
  var mixins = properties.mixins || [];
  for (var i=0; i<mixins.length; i++) {
    for (var key in mixins[i]) {
      if (key!='init' && key!='name' && !this.hasOwnProperty(key)) {
        this[key] = mixins[i][key];
      }
    }
    this.mixins[mixins[i].name]       = true;
    this.mixinGroups[mixins[i].group] = true;
    if (mixins[i].init) {
      mixins[i].init.call(this, properties);
    }
  }
};

App.DynamicGlyph.extend(App.Glyph);

App.DynamicGlyph.prototype.hasMixin = function(mixin) {
  if (typeof mixin === 'object') {
    return this.mixins[mixin.name] || this.mixinGroups[mixin.name];
  } else {
    return this.mixins[mixin] || this.mixinGroups[mixin];
  }
};

App.DynamicGlyph.prototype.describe = function() {
  return this.name;
};

App.DynamicGlyph.prototype.describeOne = function(shouldCapitalize) {
  var prefixes = shouldCapitalize ? ['A','An'] : ['a','an'];
  var desc     = this.describe();
  var first    = desc.charAt(0).toLowerCase();
  var prefix   = 'aeiou'.indexOf(first)<0 ? prefixes[0] : prefixes[1];
  return prefix +" "+ desc;
};
<commit_msg>added DynamicGlyph#describeThe() function<commit_after>
// App.Glyph + name & mixins:
App.DynamicGlyph = function(properties) {
  properties = properties || {};
  App.Glyph.call(this, properties);   //<- sets ch, fg, bg
  this.name        = properties.name || '';
  this.mixins      = {};
  this.mixinGroups = {};
  var mixins = properties.mixins || [];
  for (var i=0; i<mixins.length; i++) {
    for (var key in mixins[i]) {
      if (key!='init' && key!='name' && !this.hasOwnProperty(key)) {
        this[key] = mixins[i][key];
      }
    }
    this.mixins[mixins[i].name]       = true;
    this.mixinGroups[mixins[i].group] = true;
    if (mixins[i].init) {
      mixins[i].init.call(this, properties);
    }
  }
};

App.DynamicGlyph.extend(App.Glyph);

App.DynamicGlyph.prototype.hasMixin = function(mixin) {
  if (typeof mixin === 'object') {
    return this.mixins[mixin.name] || this.mixinGroups[mixin.name];
  } else {
    return this.mixins[mixin] || this.mixinGroups[mixin];
  }
};

App.DynamicGlyph.prototype.describe = function() {
  return this.name;
};

App.DynamicGlyph.prototype.describeOne = function(shouldCapitalize) {
  var prefixes = shouldCapitalize ? ['A','An'] : ['a','an'];
  var desc     = this.describe();
  var first    = desc.charAt(0).toLowerCase();
  var prefix   = 'aeiou'.indexOf(first)<0 ? prefixes[0] : prefixes[1];
  return prefix +" "+ desc;
};

App.DynamicGlyph.prototype.describeThe = function(shouldCapitalize) {
  var prefix = shouldCapitalize ? 'The' : 'the';
  return prefix +' '+ this.describe();
};
<|endoftext|>


<commit_before>/*
Copyright 2012 Adobe Systems 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.
*/

"use strict";

var parseCSV = function(file, cb) {

	var fs     = require('fs')
	, filename = file
	, csv      = require('csv')
	;

	var header = [];
	var values = [];
	var json   = {};

	csv()
	.from.stream(fs.createReadStream(file))
	.on('record', function(row,index){
		if (index === 0)
			header.push(row);
		else
			values.push(row);
	})
	.on('end', function(count){
		header[0].forEach(function (h, idx) {
			json[h] = values[0][idx];
		});
		cb(json);
	})
	.on('error', function(error){
		console.log(error.message);
	});
};

module.exports = parseCSV;<commit_msg>On Win7, there are blank row generated in between the key & value rows in the result csv file. Fixed it by checking each row while we processing the csv, and skip the row if it's blank.<commit_after>/*
Copyright 2012 Adobe Systems 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.
*/

"use strict";

var parseCSV = function(file, cb) {

	var fs     = require('fs')
	, filename = file
	, csv      = require('csv')
	;

	var header = [];
	var values = [];
	var json   = {};

	csv()
	.from.stream(fs.createReadStream(file))
    .transform(function(row, index){
        //in case there are blank lines in between key & value on Win7
        if (row[0] == ""){
            return null;
        }else{
            return row;
        }
    })
	.on('record', function(row,index){
		if (index === 0)
			header.push(row);
		else
			values.push(row);
	})
	.on('end', function(count){
		header[0].forEach(function (h, idx) {
			json[h] = values[0][idx];
		});
		cb(json);
	})
	.on('error', function(error){
		console.log(error.message);
	});
};

module.exports = parseCSV;<|endoftext|>