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

define([
    "firebug/lib/object",
    "firebug/lib/options",
    "firebug/debugger/sourceFile",
    "firebug/debugger/rdp",
    "firebug/debugger/breakpointClient",
    "firebug/debugger/gripCache",
],
function (Obj, Options, SourceFile, RDP, BreakpointClient, GripCache) {

// ********************************************************************************************* //
// Constants and Services

var Cu = Components.utils;

Cu["import"]("resource:///modules/devtools/dbg-client.jsm");
Cu["import"]("resource:///modules/devtools/dbg-server.jsm");

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

function ThreadClient(connection, actor, debuggerClient)
{
    this.connection = connection;
    this.actor = actor;
    this.debuggerClient = debuggerClient;
    this.frameCache = [];
    this.scriptCache = {};
    this.gripCache = new GripCache();
}

ThreadClient.prototype = Obj.extend(new Firebug.EventSource(),
{
    state: "paused",
    actor: null,
    pauseOnExceptions: false,

    isPaused: function()
    {
        return this.state === "paused";
    },

    assertPaused: function DebuggerClientassertPaused(command)
    {
        if (!this.isPaused())
            throw Error(command + " command sent while not paused.");
    },

    /**
     * Resume a paused thread. If the optional aLimit parameter is present, then
     * the thread will also pause when that limit is reached.
     *
     * @param function onResponse
     *        Called with the response packet.
     * @param [optional] object aLimit
     *        An object with a type property set to the appropriate limit (next,
     *        step, or finish) per the remote debugging protocol specification.
     */
    resume: function DebuggerClient_resume(onResponse, aLimit)
    {
        this.assertPaused("resume");

        // Put the client in a tentative "resuming" state so we can prevent
        // further requests that should only be sent in the paused state.
        this.state = "resuming";

        var self = this;
        var packet = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.resume,
            resumeLimit: aLimit,
            pauseOnExceptions: this.pauseOnExceptions
        };

        this.connection.request(packet, function(response)
        {
            self.state = "running";

            if (response.error)
            {
                // There was an error resuming, back to paused state.
                self.state = "paused";
            }

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Step over a function call.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    stepOver: function DebuggerClient_stepOver(onResponse)
    {
        this.resume(onResponse, { type: "next" });
    },

    /**
     * Step into a function call.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    stepIn: function DebuggerClient_stepIn(onResponse)
    {
        this.resume(onResponse, { type: "step" });
    },

    /**
     * Step out of a function call.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    stepOut: function DebuggerClient_stepOut(onResponse)
    {
        this.resume(onResponse, { type: "finish" });
    },

    /**
     * Interrupt a running thread.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    interrupt: function DebuggerClient_interrupt(onResponse)
    {
        var packet = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.interrupt
        };

        var self = this;
        this.connection.request(packet, function(response)
        {
            FBTrace.sysout("threadClient.interrupt; interrupted ", response);

            if (!response.error)
                self.state = "paused";

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Enable or disable pausing when an exception is thrown.
     *
     * @param boolean aFlag
     *        Enables pausing if true, disables otherwise.
     * @param function onResponse
     *        Called with the response packet.
     */
    pauseOnExceptions: function DebuggerClient_pauseOnExceptions(aFlag, onResponse)
    {
        this.pauseOnExceptions = aFlag;

        // If the debuggee is paused, the value of the flag will be communicated in
        // the next resumption. Otherwise we have to force a pause in order to send
        // the flag.
        if (!this.isPaused())
        {
            this.interrupt(function(response)
            {
                if (response.error)
                {
                    // Can't continue if pausing failed.
                    onResponse(response);
                    return;
                }
                this.resume(onResponse);
            }.bind(this));
        }
    },

    /**
     * Send a clientEvaluate packet to the debuggee. Response
     * will be a resume packet.
     *
     * @param string aFrame
     *        The actor ID of the frame where the evaluation should take place.
     * @param string aExpression
     *        The expression that will be evaluated in the scope of the frame
     *        above.
     * @param function onResponse
     *        Called with the response packet.
     */
    eval: function DebuggerClient_eval(aFrame, aExpression, onResponse)
    {
        this.assertPaused("eval");

        // Put the client in a tentative "resuming" state so we can prevent
        // further requests that should only be sent in the paused state.
        this.state = "resuming";

        var request = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.clientEvaluate,
            frame: aFrame,
            expression: aExpression
        };

        // Remember the callback. It'll be used to pass the result back.
        this.debuggerClient.context.evalInProgress = true;

        var self = this;
        this.connection.request(request, function(response)
        {
            self.debuggerClient.context.evalInProgress = false;

            if (response.error)
            {
                // There was an error resuming, back to paused state.
                self.state = "paused";
            }

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Detach from the thread actor.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    detach: function DebuggerClient_detach(onResponse)
    {
        var packet = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.detach
        };

        var self = this;
        this.connection.request(packet, function(response)
        {
            if (self.debuggerClient.activeThread === this)
                delete self.activeThread;

            delete self.debuggerClient.threadClients[self.actor];

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Request to set a breakpoint in the specified location.
     *
     * @param object location
     *        The source location object where the breakpoint will be set.
     * @param function onResponse
     *        Called with the thread's response.
     */
    setBreakpoint: function DebuggerClient_setBreakpoint(location, onResponse)
    {
        // A helper function that sets the breakpoint.
        var doSetBreakpoint = function _doSetBreakpoint(callback)
        {
            var packet = {
                to: this.actor,
                type: RDP.DebugProtocolTypes.setBreakpoint,
                location: location
            };

            this.connection.request(packet, function(response)
            {
                // Ignoring errors, since the user may be setting a breakpoint in a
                // dead script that will reappear on a page reload.
                if (onResponse)
                {
                    var bpClient = new BreakpointClient(this.connection, response.actor,
                        location);

                    if (callback)
                        callback(onResponse(response, bpClient));
                    else
                        onResponse(response, bpClient);
                }
            }.bind(this));
        }.bind(this);

        // If the debuggee is paused, just set the breakpoint.
        if (this.isPaused())
        {
            doSetBreakpoint();
            return;
        }

        // Otherwise, force a pause in order to set the breakpoint.
        this.interrupt(function(response)
        {
            if (response.error)
            {
                // Can't set the breakpoint if pausing failed.
                onResponse(response);
                return;
            }

            doSetBreakpoint(this.resume.bind(this));
        }.bind(this));
  },

    /**
     * Request the loaded scripts for the current thread.
     *
     * @param onResponse integer
     *        Called with the thread's response.
     */
    getScripts: function DebuggerClient_getScripts(onResponse)
    {
        var packet = { to: this.actor, type: RDP.DebugProtocolTypes.scripts };
        this.connection.request(packet, onResponse);
    },

    /**
     * A cache of source scripts. Clients can observe the scriptsadded and
     * scriptscleared event to keep up to date on changes to this cache,
     * and can fill it using the fillScripts method.
     */
    getCachedScripts: function()
    {
        return this.scriptCache;
    },

    /**
     * Ensure that source scripts have been loaded in the
     * ThreadClient's source script cache. A scriptsadded event will be
     * sent when the source script cache is updated.
     *
     * @returns true if a scriptsadded notification should be expected.
     */
    fillScripts: function DebuggerClient_fillScripts()
    {
        var self = this;
        this.getScripts(function(response)
        {
            for each (var script in response.scripts)
            {
                if (!self.scriptCache[script.url])
                    self.scriptCache[script.url] = script;
            }

            // If the cache was modified, notify listeners.
            if (response.scripts && response.scripts.length)
                self.dispatch("onScriptsAdded", [self.scriptCache]);
        });

        return true;
    },

    /**
     * Clear the thread's source script cache. A scriptscleared event
     * will be sent.
     */
    clearScripts: function DebuggerClient_clearScripts()
    {
        if (Object.keys(this.scriptCache).length > 0)
        {
            this.scriptCache = {}
            this.dispatch("scriptsCleared");
        }
    },

    /**
     * Request frames from the callstack for the current thread.
     *
     * @param start integer
     *        The number of the youngest stack frame to return (the youngest
     *        frame is 0).
     * @param count integer
     *        The maximum number of frames to return, or null to return all
     *        frames.
     * @param onResponse function
     *        Called with the thread's response.
     */
    getFrames: function DebuggerClient_getFrames(start, count, onResponse)
    {
        this.assertPaused("frames");

        var packet = { to: this.actor, type: RDP.DebugProtocolTypes.frames,
            start: start, count: count ? count : undefined };

        this.connection.request(packet, onResponse);
    },

    /**
     * An array of cached frames. Clients can observe the framesadded and
     * framescleared event to keep up to date on changes to this cache,
     * and can fill it using the fillFrames method.
     */
    getCachedFrames: function()
    {
        return this.frameCache;
    },

    /**
     * true if there are more stack frames available on the server.
     */
    getMoreFrames: function()
    {
        return this.isPaused() && (!this.frameCache || this.frameCache.length == 0
          || !this.frameCache[this.frameCache.length - 1].oldest);
    },

    /**
     * Ensure that at least total stack frames have been loaded in the
     * ThreadClient's stack frame cache. A framesadded event will be
     * sent when the stack frame cache is updated.
     *
     * @param total number
     *        The minimum number of stack frames to be included.
     *
     * @returns true if a framesadded notification should be expected.
     */
    fillFrames: function DebuggerClient_fillFrames(total)
    {
        this.assertPaused("fillFrames");

        if (this.frameCache.length >= total)
            return false;

        var numFrames = this.frameCache.length;

        var self = this;
        this.getFrames(numFrames, total - numFrames, function(response)
        {
            for each (var frame in response.frames)
                self.frameCache[frame.depth] = frame;

            // If we got as many frames as we asked for, there might be more
            // frames available.
            self.dispatch("framesadded", [self.debuggerClient.context, self.frameCache]);
        });

        return true;
    },

    /**
     * Clear the thread's stack frame cache. A framescleared event
     * will be sent.
     */
    clearFrames: function DebuggerClient_clearFrames()
    {
        if (this.frameCache.length > 0)
        {
            this.frameCache = [];
            this.dispatch(this.debuggerClient.context, "framescleared");
        }
    },

    /**
     * Return a GripClient object for the given object grip.
     *
     * @param aGrip object
     *        A pause-lifetime object grip returned by the protocol.
     */
    pauseGrip: function DebuggerClient_pauseGrip(aGrip)
    {
        if (!this.pauseGrips)
            this.pauseGrips = {};

        if (aGrip.actor in this.pauseGrips)
            return this.pauseGrips[aGrip.actor];

        var client = new GripClient(this.connection, aGrip);
        this.pauseGrips[aGrip.actor] = client;
        return client;
    },

    /**
     * Invalidate pause-lifetime grip clients and clear the list of
     * current grip clients.
     */
    clearPauseGrips: function DebuggerClient_clearPauseGrips(aPacket)
    {
        for each (var grip in this.pauseGrips)
            grip.valid = false;
        this.pauseGrips = null;
    },

    /**
     * Handle thread state change by doing necessary cleanup and notifying all
     * registered listeners.
     */
    onThreadState: function DebuggerClient_onThreadState(packet)
    {
        // Ignore thread-state changes if server side evaluation is in progress.
        if (this.debuggerClient.context.evalInProgress)
            return;

        FBTrace.sysout("threadClient.onThreadState; type: " + packet.type, packet);

        this.state = RDP.ThreadStateTypes[packet.type];
        this.clearFrames();
        this.clearPauseGrips();

        this.gripCache.clear();

        if (this.connection.eventsEnabled)
            this.dispatch(packet.type, [this.debuggerClient.context, packet]);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Objects

    getObject: function(grip, callback)
    {
        this.assertPaused("getObject");

        this.gripCache.getObject(this.connection, grip, callback);
    }
});

// ********************************************************************************************* //
// Registration

return ThreadClient;

// ********************************************************************************************* //
});
<commit_msg>Missing dep + tracing update<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/lib/object",
    "firebug/lib/options",
    "firebug/debugger/sourceFile",
    "firebug/debugger/rdp",
    "firebug/debugger/breakpointClient",
    "firebug/debugger/gripCache",
    "firebug/debugger/gripClient",
],
function (Obj, Options, SourceFile, RDP, BreakpointClient, GripCache, GripClient) {

// ********************************************************************************************* //
// Constants and Services

var Cu = Components.utils;

Cu["import"]("resource:///modules/devtools/dbg-client.jsm");
Cu["import"]("resource:///modules/devtools/dbg-server.jsm");

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

function ThreadClient(connection, actor, debuggerClient)
{
    this.connection = connection;
    this.actor = actor;
    this.debuggerClient = debuggerClient;
    this.frameCache = [];
    this.scriptCache = {};
    this.gripCache = new GripCache();
}

ThreadClient.prototype = Obj.extend(new Firebug.EventSource(),
{
    state: "paused",
    actor: null,
    pauseOnExceptions: false,

    isPaused: function()
    {
        return this.state === "paused";
    },

    assertPaused: function DebuggerClientassertPaused(command)
    {
        if (!this.isPaused())
        {
            FBTrace.sysout("threadClient.assertPaused; EXCEPTION " + this.state, this);
            throw Error(command + " command sent while not paused.");
        }
    },

    /**
     * Resume a paused thread. If the optional aLimit parameter is present, then
     * the thread will also pause when that limit is reached.
     *
     * @param function onResponse
     *        Called with the response packet.
     * @param [optional] object aLimit
     *        An object with a type property set to the appropriate limit (next,
     *        step, or finish) per the remote debugging protocol specification.
     */
    resume: function DebuggerClient_resume(onResponse, aLimit)
    {
        this.assertPaused("resume");

        // Put the client in a tentative "resuming" state so we can prevent
        // further requests that should only be sent in the paused state.
        this.state = "resuming";

        var self = this;
        var packet = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.resume,
            resumeLimit: aLimit,
            pauseOnExceptions: this.pauseOnExceptions
        };

        this.connection.request(packet, function(response)
        {
            self.state = "running";

            if (response.error)
            {
                // There was an error resuming, back to paused state.
                self.state = "paused";
            }

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Step over a function call.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    stepOver: function DebuggerClient_stepOver(onResponse)
    {
        this.resume(onResponse, { type: "next" });
    },

    /**
     * Step into a function call.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    stepIn: function DebuggerClient_stepIn(onResponse)
    {
        this.resume(onResponse, { type: "step" });
    },

    /**
     * Step out of a function call.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    stepOut: function DebuggerClient_stepOut(onResponse)
    {
        this.resume(onResponse, { type: "finish" });
    },

    /**
     * Interrupt a running thread.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    interrupt: function DebuggerClient_interrupt(onResponse)
    {
        var packet = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.interrupt
        };

        var self = this;
        this.connection.request(packet, function(response)
        {
            if (!response.error)
                self.state = "paused";

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Enable or disable pausing when an exception is thrown.
     *
     * @param boolean aFlag
     *        Enables pausing if true, disables otherwise.
     * @param function onResponse
     *        Called with the response packet.
     */
    pauseOnExceptions: function DebuggerClient_pauseOnExceptions(aFlag, onResponse)
    {
        this.pauseOnExceptions = aFlag;

        // If the debuggee is paused, the value of the flag will be communicated in
        // the next resumption. Otherwise we have to force a pause in order to send
        // the flag.
        if (!this.isPaused())
        {
            this.interrupt(function(response)
            {
                if (response.error)
                {
                    // Can't continue if pausing failed.
                    onResponse(response);
                    return;
                }
                this.resume(onResponse);
            }.bind(this));
        }
    },

    /**
     * Send a clientEvaluate packet to the debuggee. Response
     * will be a resume packet.
     *
     * @param string aFrame
     *        The actor ID of the frame where the evaluation should take place.
     * @param string aExpression
     *        The expression that will be evaluated in the scope of the frame
     *        above.
     * @param function onResponse
     *        Called with the response packet.
     */
    eval: function DebuggerClient_eval(aFrame, aExpression, onResponse)
    {
        this.assertPaused("eval");

        // Put the client in a tentative "resuming" state so we can prevent
        // further requests that should only be sent in the paused state.
        this.state = "resuming";

        var request = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.clientEvaluate,
            frame: aFrame,
            expression: aExpression
        };

        // Remember the callback. It'll be used to pass the result back.
        this.debuggerClient.context.evalInProgress = true;

        var self = this;
        this.connection.request(request, function(response)
        {
            self.debuggerClient.context.evalInProgress = false;

            if (response.error)
            {
                // There was an error resuming, back to paused state.
                self.state = "paused";
            }

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Detach from the thread actor.
     *
     * @param function onResponse
     *        Called with the response packet.
     */
    detach: function DebuggerClient_detach(onResponse)
    {
        var packet = {
            to: this.actor,
            type: RDP.DebugProtocolTypes.detach
        };

        var self = this;
        this.connection.request(packet, function(response)
        {
            if (self.debuggerClient.activeThread === this)
                delete self.activeThread;

            delete self.debuggerClient.threadClients[self.actor];

            if (onResponse)
                onResponse(response);
        });
    },

    /**
     * Request to set a breakpoint in the specified location.
     *
     * @param object location
     *        The source location object where the breakpoint will be set.
     * @param function onResponse
     *        Called with the thread's response.
     */
    setBreakpoint: function DebuggerClient_setBreakpoint(location, onResponse)
    {
        // A helper function that sets the breakpoint.
        var doSetBreakpoint = function _doSetBreakpoint(callback)
        {
            var packet = {
                to: this.actor,
                type: RDP.DebugProtocolTypes.setBreakpoint,
                location: location
            };

            this.connection.request(packet, function(response)
            {
                // Ignoring errors, since the user may be setting a breakpoint in a
                // dead script that will reappear on a page reload.
                if (onResponse)
                {
                    var bpClient = new BreakpointClient(this.connection, response.actor,
                        location);

                    if (callback)
                        callback(onResponse(response, bpClient));
                    else
                        onResponse(response, bpClient);
                }
            }.bind(this));
        }.bind(this);

        // If the debuggee is paused, just set the breakpoint.
        if (this.isPaused())
        {
            doSetBreakpoint();
            return;
        }

        // Otherwise, force a pause in order to set the breakpoint.
        this.interrupt(function(response)
        {
            if (response.error)
            {
                // Can't set the breakpoint if pausing failed.
                onResponse(response);
                return;
            }

            doSetBreakpoint(this.resume.bind(this));
        }.bind(this));
  },

    /**
     * Request the loaded scripts for the current thread.
     *
     * @param onResponse integer
     *        Called with the thread's response.
     */
    getScripts: function DebuggerClient_getScripts(onResponse)
    {
        var packet = { to: this.actor, type: RDP.DebugProtocolTypes.scripts };
        this.connection.request(packet, onResponse);
    },

    /**
     * A cache of source scripts. Clients can observe the scriptsadded and
     * scriptscleared event to keep up to date on changes to this cache,
     * and can fill it using the fillScripts method.
     */
    getCachedScripts: function()
    {
        return this.scriptCache;
    },

    /**
     * Ensure that source scripts have been loaded in the
     * ThreadClient's source script cache. A scriptsadded event will be
     * sent when the source script cache is updated.
     *
     * @returns true if a scriptsadded notification should be expected.
     */
    fillScripts: function DebuggerClient_fillScripts()
    {
        var self = this;
        this.getScripts(function(response)
        {
            for each (var script in response.scripts)
            {
                if (!self.scriptCache[script.url])
                    self.scriptCache[script.url] = script;
            }

            // If the cache was modified, notify listeners.
            if (response.scripts && response.scripts.length)
                self.dispatch("onScriptsAdded", [self.scriptCache]);
        });

        return true;
    },

    /**
     * Clear the thread's source script cache. A scriptscleared event
     * will be sent.
     */
    clearScripts: function DebuggerClient_clearScripts()
    {
        if (Object.keys(this.scriptCache).length > 0)
        {
            this.scriptCache = {}
            this.dispatch("scriptsCleared");
        }
    },

    /**
     * Request frames from the callstack for the current thread.
     *
     * @param start integer
     *        The number of the youngest stack frame to return (the youngest
     *        frame is 0).
     * @param count integer
     *        The maximum number of frames to return, or null to return all
     *        frames.
     * @param onResponse function
     *        Called with the thread's response.
     */
    getFrames: function DebuggerClient_getFrames(start, count, onResponse)
    {
        this.assertPaused("frames");

        var packet = { to: this.actor, type: RDP.DebugProtocolTypes.frames,
            start: start, count: count ? count : undefined };

        this.connection.request(packet, onResponse);
    },

    /**
     * An array of cached frames. Clients can observe the framesadded and
     * framescleared event to keep up to date on changes to this cache,
     * and can fill it using the fillFrames method.
     */
    getCachedFrames: function()
    {
        return this.frameCache;
    },

    /**
     * true if there are more stack frames available on the server.
     */
    getMoreFrames: function()
    {
        return this.isPaused() && (!this.frameCache || this.frameCache.length == 0
          || !this.frameCache[this.frameCache.length - 1].oldest);
    },

    /**
     * Ensure that at least total stack frames have been loaded in the
     * ThreadClient's stack frame cache. A framesadded event will be
     * sent when the stack frame cache is updated.
     *
     * @param total number
     *        The minimum number of stack frames to be included.
     *
     * @returns true if a framesadded notification should be expected.
     */
    fillFrames: function DebuggerClient_fillFrames(total)
    {
        this.assertPaused("fillFrames");

        if (this.frameCache.length >= total)
            return false;

        var numFrames = this.frameCache.length;

        var self = this;
        this.getFrames(numFrames, total - numFrames, function(response)
        {
            for each (var frame in response.frames)
                self.frameCache[frame.depth] = frame;

            // If we got as many frames as we asked for, there might be more
            // frames available.
            self.dispatch("framesadded", [self.debuggerClient.context, self.frameCache]);
        });

        return true;
    },

    /**
     * Clear the thread's stack frame cache. A framescleared event
     * will be sent.
     */
    clearFrames: function DebuggerClient_clearFrames()
    {
        if (this.frameCache.length > 0)
        {
            this.frameCache = [];
            this.dispatch(this.debuggerClient.context, "framescleared");
        }
    },

    /**
     * Return a GripClient object for the given object grip.
     *
     * @param aGrip object
     *        A pause-lifetime object grip returned by the protocol.
     */
    pauseGrip: function DebuggerClient_pauseGrip(aGrip)
    {
        if (!this.pauseGrips)
            this.pauseGrips = {};

        if (aGrip.actor in this.pauseGrips)
            return this.pauseGrips[aGrip.actor];

        var client = new GripClient(this.connection, aGrip);
        this.pauseGrips[aGrip.actor] = client;
        return client;
    },

    /**
     * Invalidate pause-lifetime grip clients and clear the list of
     * current grip clients.
     */
    clearPauseGrips: function DebuggerClient_clearPauseGrips(aPacket)
    {
        for each (var grip in this.pauseGrips)
            grip.valid = false;
        this.pauseGrips = null;
    },

    /**
     * Handle thread state change by doing necessary cleanup and notifying all
     * registered listeners.
     */
    onThreadState: function DebuggerClient_onThreadState(packet)
    {
        // Ignore thread-state changes if server side evaluation is in progress.
        if (this.debuggerClient.context.evalInProgress)
            return;

        FBTrace.sysout("threadClient.onThreadState; type: " + packet.type, packet);

        this.state = RDP.ThreadStateTypes[packet.type];
        this.clearFrames();
        this.clearPauseGrips();

        this.gripCache.clear();

        if (this.connection.eventsEnabled)
            this.dispatch(packet.type, [this.debuggerClient.context, packet]);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Objects

    getObject: function(grip, callback)
    {
        this.assertPaused("getObject");

        this.gripCache.getObject(this.connection, grip, callback);
    }
});

// ********************************************************************************************* //
// Registration

return ThreadClient;

// ********************************************************************************************* //
});
<|endoftext|>


<commit_before>function ddg_spice_maven(api_result) {
    if (api_result.responseHeader.status
        || api_result.response.numFound == 0) return

    Spice.render({
        data             : api_result,
        header1          : api_result.responseHeader.params.q
                            + " (Maven Central Repository)",
        source_url       : 'http://search.maven.org/#search%7Cga%7C1%7C'
                            + encodeURIComponent(api_result.responseHeader.params.q),
        source_name      : 'Maven Central Repository',
        template_normal  : 'maven',
        force_big_header : true,
        force_no_fold    : true
    });

    $("#zero_click_abstract").css({
        "margin": "4px 12px 0px 2px !important",
    });
}
<commit_msg>use strict for Maven Spice.<commit_after>function ddg_spice_maven(api_result) {
    "use strict";

    if (api_result.responseHeader.status
        || api_result.response.numFound == 0) {
        return;
    }

    Spice.render({
        data             : api_result,
        header1          : api_result.responseHeader.params.q
                            + " (Maven Central Repository)",
        source_url       : 'http://search.maven.org/#search%7Cga%7C1%7C'
                            + encodeURIComponent(api_result.responseHeader.params.q),
        source_name      : 'Maven Central Repository',
        template_normal  : 'maven',
        force_big_header : true,
        force_no_fold    : true
    });

    $("#zero_click_abstract").css({
        "margin": "4px 12px 0px 2px !important",
    });
}
<|endoftext|>


<commit_before>import { SubmissionError } from 'redux-form'

const processSubmitErrors = response => {
    let errors = {}
    if (response.hasOwnProperty('errors')) {
        for (let field in response.errors.children) {
            let value = response.errors.children[field]
            if (value.hasOwnProperty('errors'))  {
                errors[field] = value.errors[0]
            }
        }
        throw new SubmissionError(errors)

    }
    return {}
}

export default processSubmitErrors
<commit_msg>improved processSubmitErrors to render errors for every children in errors tree<commit_after>import { SubmissionError } from 'redux-form'
import _ from 'lodash' // added for empty check

const convertToReduxFormErrors = (obj) => {

    let objectWithoutChildrenAndFalseErrors = {}
    Object.keys(obj).map( (name) => {
            if(name === 'children'){
                objectWithoutChildrenAndFalseErrors = { ...objectWithoutChildrenAndFalseErrors, ...convertToReduxFormErrors(obj[name])}
            }else{
                if( obj[name].hasOwnProperty('children')){ // if children, take field from it and set them directly as own field
                    objectWithoutChildrenAndFalseErrors[name] = convertToReduxFormErrors(obj[name])
                }else{
                    if( obj[name].hasOwnProperty('errors') && !_.isEmpty(obj[name]['errors']) ){  // using lodash for empty error check, dont add them if empty
                       objectWithoutChildrenAndFalseErrors[name] = obj[name]['errors']
                    }
                }
            }
        }
    )
    return objectWithoutChildrenAndFalseErrors
}

const processSubmitErrors = (errors) => {
    if(errors.hasOwnProperty('errors')){
        errors = convertToReduxFormErrors(errors.errors)
        throw new SubmissionError(errors)
    }
    return {} // dont know why original processSubmitErrors return empty object, keep this to prevent any BC break
}

export default processSubmitErrors
<|endoftext|>


<commit_before>"use strict";

// Requires
var vscode = require("vscode");
var markdownlint = require("markdownlint");
var fs = require("fs");
var path = require("path");
var packageJson = require("./package.json");
var defaultConfig = require("./default-config.json");

// Constants
var extensionName = packageJson.name;
var markdownlintVersion = packageJson
	.dependencies
	.markdownlint
	.replace(/[^\d.]/, "");
var configFileName = ".markdownlint.json";
var markdownLanguageId = "markdown";
var markdownlintRulesMdPrefix = "https://github.com/DavidAnson/markdownlint/blob/v";
var markdownlintRulesMdPostfix = "/doc/Rules.md";
var codeActionPrefix = "Click for more information about ";
var badConfig = "Unable to read configuration file ";
var throttleDuration = 500;

// Variables
var diagnosticCollection = null;
var customConfig = null;
var throttle = {
	"document": null,
	"timeout": null
};

// Lints a Markdown document
function lint (document) {
	// Skip if not Markdown
	if (document.languageId !== markdownLanguageId) {
		return;
	}

	// Configure
	var options = {
		"strings": {
			"document": document.getText()
		},
		"config": customConfig || defaultConfig,
		"resultVersion": 1
	};
	var diagnostics = [];

	// Lint and create Diagnostics
	markdownlint
		.sync(options)
		.document
		.forEach(function forResult (result) {
			var ruleName = result.ruleName;
			var ruleDescription = result.ruleDescription;
			var message = ruleName + "/" + result.ruleAlias + ": " + ruleDescription;
			var range = document.lineAt(result.lineNumber - 1).range;
			if (result.errorRange) {
				var start = result.errorRange[0] - 1;
				var end = start + result.errorRange[1];
				range = range.with(range.start.with(undefined, start), range.end.with(undefined, end));
			}
			var diagnostic = new vscode.Diagnostic(range, message, vscode.DiagnosticSeverity.Warning);
			diagnostic.code = markdownlintRulesMdPrefix + markdownlintVersion + markdownlintRulesMdPostfix +
				"#" + ruleName.toLowerCase() + "---" + ruleDescription.toLowerCase().replace(/ /g, "-");
			diagnostics.push(diagnostic);
		});

	// Publish
	diagnosticCollection.set(document.uri, diagnostics);
}

// Implements CodeActionsProvider.provideCodeActions to open info links for rules
function provideCodeActions (document, range, codeActionContext) {
	var diagnostics = codeActionContext.diagnostics || [];
	return diagnostics.map(function forDiagnostic (diagnostic) {
		return {
			"title": codeActionPrefix + diagnostic.message.substr(0, 5),
			"command": "vscode.open",
			"arguments": [ vscode.Uri.parse(diagnostic.code) ]
		};
	});
}

// Loads custom rule configuration
function loadCustomConfig () {
	var settings = vscode.workspace.getConfiguration(packageJson.displayName);
	customConfig = settings.get("config");

	var rootPath = vscode.workspace.rootPath;
	if (rootPath) {
		var configFilePath = path.join(rootPath, configFileName);
		if (fs.existsSync(configFilePath)) {
			try {
				customConfig = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
			} catch (ex) {
				vscode.window.showWarningMessage(badConfig + "'" + configFilePath + "' (" + (ex.message || ex.toString()) + ")");
			}
		}
	}

	// Re-lint all open files
	(vscode.workspace.textDocuments || []).forEach(lint);
}

// Suppresses a pending lint for the specified document
function suppressLint (document) {
	if (throttle.timeout && (document === throttle.document)) {
		clearTimeout(throttle.timeout);
		throttle.document = null;
		throttle.timeout = null;
	}
}

// Requests a lint of the specified document
function requestLint (document) {
	suppressLint(document);
	throttle.document = document;
	throttle.timeout = setTimeout(function waitThrottleDuration () {
		// Do not use throttle.document in this function; it may have changed
		lint(document);
		suppressLint(document);
	}, throttleDuration);
}

// Handles the didChangeTextDocument event
function didChangeTextDocument (change) {
	requestLint(change.document);
}

// Handles the didCloseTextDocument event
function didCloseTextDocument (document) {
	suppressLint(document);
	diagnosticCollection.delete(document.uri);
}

function activate (context) {
	// Hook up to workspace events
	context.subscriptions.push(
		vscode.workspace.onDidOpenTextDocument(lint),
		vscode.workspace.onDidChangeTextDocument(didChangeTextDocument),
		vscode.workspace.onDidCloseTextDocument(didCloseTextDocument),
		vscode.workspace.onDidChangeConfiguration(loadCustomConfig));

	// Register CodeActionsProvider
	context.subscriptions.push(
		vscode.languages.registerCodeActionsProvider(markdownLanguageId, {
			"provideCodeActions": provideCodeActions
		}));

	// Create DiagnosticCollection
	diagnosticCollection = vscode.languages.createDiagnosticCollection(extensionName);
	context.subscriptions.push(diagnosticCollection);

	// Hook up to file system changes for custom config file
	var rootPath = vscode.workspace.rootPath;
	if (rootPath) {
		var fileSystemWatcher = vscode.workspace.createFileSystemWatcher(path.join(rootPath, configFileName));
		context.subscriptions.push(
			fileSystemWatcher,
			fileSystemWatcher.onDidCreate(loadCustomConfig),
			fileSystemWatcher.onDidChange(loadCustomConfig),
			fileSystemWatcher.onDidDelete(loadCustomConfig));
	}

	// Load custom rule config
	loadCustomConfig();
}

exports.activate = activate;
<commit_msg>Add error detail to diagnostic messages when available.<commit_after>"use strict";

// Requires
var vscode = require("vscode");
var markdownlint = require("markdownlint");
var fs = require("fs");
var path = require("path");
var packageJson = require("./package.json");
var defaultConfig = require("./default-config.json");

// Constants
var extensionName = packageJson.name;
var markdownlintVersion = packageJson
	.dependencies
	.markdownlint
	.replace(/[^\d.]/, "");
var configFileName = ".markdownlint.json";
var markdownLanguageId = "markdown";
var markdownlintRulesMdPrefix = "https://github.com/DavidAnson/markdownlint/blob/v";
var markdownlintRulesMdPostfix = "/doc/Rules.md";
var codeActionPrefix = "Click for more information about ";
var badConfig = "Unable to read configuration file ";
var throttleDuration = 500;

// Variables
var diagnosticCollection = null;
var customConfig = null;
var throttle = {
	"document": null,
	"timeout": null
};

// Lints a Markdown document
function lint (document) {
	// Skip if not Markdown
	if (document.languageId !== markdownLanguageId) {
		return;
	}

	// Configure
	var options = {
		"strings": {
			"document": document.getText()
		},
		"config": customConfig || defaultConfig,
		"resultVersion": 1
	};
	var diagnostics = [];

	// Lint and create Diagnostics
	markdownlint
		.sync(options)
		.document
		.forEach(function forResult (result) {
			var ruleName = result.ruleName;
			var ruleDescription = result.ruleDescription;
			var message = ruleName + "/" + result.ruleAlias + ": " + ruleDescription;
			if (result.errorDetail) {
				message += " [" + result.errorDetail + "]";
			}
			var range = document.lineAt(result.lineNumber - 1).range;
			if (result.errorRange) {
				var start = result.errorRange[0] - 1;
				var end = start + result.errorRange[1];
				range = range.with(range.start.with(undefined, start), range.end.with(undefined, end));
			}
			var diagnostic = new vscode.Diagnostic(range, message, vscode.DiagnosticSeverity.Warning);
			diagnostic.code = markdownlintRulesMdPrefix + markdownlintVersion + markdownlintRulesMdPostfix +
				"#" + ruleName.toLowerCase() + "---" + ruleDescription.toLowerCase().replace(/ /g, "-");
			diagnostics.push(diagnostic);
		});

	// Publish
	diagnosticCollection.set(document.uri, diagnostics);
}

// Implements CodeActionsProvider.provideCodeActions to open info links for rules
function provideCodeActions (document, range, codeActionContext) {
	var diagnostics = codeActionContext.diagnostics || [];
	return diagnostics.map(function forDiagnostic (diagnostic) {
		return {
			"title": codeActionPrefix + diagnostic.message.substr(0, 5),
			"command": "vscode.open",
			"arguments": [ vscode.Uri.parse(diagnostic.code) ]
		};
	});
}

// Loads custom rule configuration
function loadCustomConfig () {
	var settings = vscode.workspace.getConfiguration(packageJson.displayName);
	customConfig = settings.get("config");

	var rootPath = vscode.workspace.rootPath;
	if (rootPath) {
		var configFilePath = path.join(rootPath, configFileName);
		if (fs.existsSync(configFilePath)) {
			try {
				customConfig = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
			} catch (ex) {
				vscode.window.showWarningMessage(badConfig + "'" + configFilePath + "' (" + (ex.message || ex.toString()) + ")");
			}
		}
	}

	// Re-lint all open files
	(vscode.workspace.textDocuments || []).forEach(lint);
}

// Suppresses a pending lint for the specified document
function suppressLint (document) {
	if (throttle.timeout && (document === throttle.document)) {
		clearTimeout(throttle.timeout);
		throttle.document = null;
		throttle.timeout = null;
	}
}

// Requests a lint of the specified document
function requestLint (document) {
	suppressLint(document);
	throttle.document = document;
	throttle.timeout = setTimeout(function waitThrottleDuration () {
		// Do not use throttle.document in this function; it may have changed
		lint(document);
		suppressLint(document);
	}, throttleDuration);
}

// Handles the didChangeTextDocument event
function didChangeTextDocument (change) {
	requestLint(change.document);
}

// Handles the didCloseTextDocument event
function didCloseTextDocument (document) {
	suppressLint(document);
	diagnosticCollection.delete(document.uri);
}

function activate (context) {
	// Hook up to workspace events
	context.subscriptions.push(
		vscode.workspace.onDidOpenTextDocument(lint),
		vscode.workspace.onDidChangeTextDocument(didChangeTextDocument),
		vscode.workspace.onDidCloseTextDocument(didCloseTextDocument),
		vscode.workspace.onDidChangeConfiguration(loadCustomConfig));

	// Register CodeActionsProvider
	context.subscriptions.push(
		vscode.languages.registerCodeActionsProvider(markdownLanguageId, {
			"provideCodeActions": provideCodeActions
		}));

	// Create DiagnosticCollection
	diagnosticCollection = vscode.languages.createDiagnosticCollection(extensionName);
	context.subscriptions.push(diagnosticCollection);

	// Hook up to file system changes for custom config file
	var rootPath = vscode.workspace.rootPath;
	if (rootPath) {
		var fileSystemWatcher = vscode.workspace.createFileSystemWatcher(path.join(rootPath, configFileName));
		context.subscriptions.push(
			fileSystemWatcher,
			fileSystemWatcher.onDidCreate(loadCustomConfig),
			fileSystemWatcher.onDidChange(loadCustomConfig),
			fileSystemWatcher.onDidDelete(loadCustomConfig));
	}

	// Load custom rule config
	loadCustomConfig();
}

exports.activate = activate;
<|endoftext|>


<commit_before>function ddg_spice_video(api_result) {
    if(!api_result || api_result.length === 0) {
        return;
    }

    $.ajaxSetup({
        cache: true
    });

    var encodedQuery = DDG.get_query_encoded().replace(/(?:youtube|videos?)/i, '');

    // Change the "More at ..." link.
    var change_more = function(obj) {
	var more_at_link = $(".zero_click_more_at_link");
	more_at_link.attr("href", obj.search_link);
        more_at_link.find("img").attr("src", obj.image);
        more_at_link.find("span").html(obj.text);
    };

    // This are things that a provider needs when building the spice.
    var provider_data = {
	"YouTube": {
	    "search_link": "https://www.youtube.com/results?search_query=",
	    "image": "https://icons.duckduckgo.com/i/www.youtube.com.ico",
	    "text": "More at YouTube",
	    "embed": "https://www.youtube-nocookie.com/embed/",
	    "play_url": "https://www.youtube.com/watch?v=",
	    "user_url": "https://www.youtube.com/user/",
	    "embed_options": {
		"iv_load_policy": 3,
		"autoplay": 1,
		"wmode": "opaque"
	    }
	},
	"Vimeo": {
	    "search_link": "https://www.vimeo.com/search?q=",
	    "image": "https://icons.duckduckgo.com/i/www.vimeo.com.ico",
	    "text": "More at Vimeo",
	    "embed": "https://player.vimeo.com/video/",
	    "play_url": "https://vimeo.com/",
	    "user_url": "https://vimeo.com/",
	    "embed_options": {
		"api": 0,
		"autoplay": 1
	    }
	}
    };

    // Copy provider-specific data to the item.
    $.map(api_result, function(item) {
	item.provider_data = provider_data[item.provider];
    });

    Spice.render({
        data: api_result,
        source_name : 'YouTube',
        source_url : 'https://www.youtube.com/results?search_query=' + encodedQuery,
        header1 :  decodeURIComponent(encodedQuery) + " (Video)",
	spice_name: "video",
        template_frame: "carousel",
	template_options: {
	    items: api_result,
	    template_item: "video",
	    template_detail: "video_detail",
	    li_width: 120,
	    single_item_handler: function(obj) {
		// Prevent the video from playing if we only have one item.
		obj.data[0].provider_data.embed_options.autoplay = 0;
	    }
	},
        force_no_fold : 1,
	item_callback: function(i, item) {
	    var more_at_link = $(".zero_click_more_at_link").get(0);
	    change_more({
		"search_link": item.provider_data.search_link + encodedQuery,
		"image": item.provider_data.image,
		"text": item.provider_data.text
	    });
	    resizeDetail();
	}
    });

    function resizeDetail() {
	var $video = $("#spice_video");
	var width = $video.width() - 18;
	var height = Math.floor(width * 0.5625) + 30;
	$("#spice_video #video-embed").width(width);
	$("#spice_video #video-embed").height(height);

	var video_title = $("#spice_video #video-title").width();
	var video_links = $("#spice_video .links").width();

	if(width - (video_title + video_links) < 20) {
	    $("#spice_video .links").css("position", "static");
	} else {
	    $("#spice_video .links").css("position", "absolute");
	}
    }

    $(document).ready(function() {
	resizeDetail();
	$(window).resize(resizeDetail);
    });

    // Expose the function so that ddg_spice_video.itunes can use it.
    ddg_spice_video.resizeDetail = resizeDetail;
}

// This is the callback function of /itt.
ddg_spice_video.itunes = function(api_result) {
    if(!api_result || !api_result.results || api_result.results.length === 0) {
        return;
    }

    var itunes = $("#itunes");
    var artist = itunes.data("artist").toLowerCase();
    var song = itunes.data("song").toLowerCase();

    // Find the song that matches.
    for(var i = 0; i < api_result.results.length; i++) {
	if(artist === api_result.results[i].artistName.toLowerCase() ||
	   artist === api_result.results[i].trackName.toLowerCase() ||
	   song === api_result.results[i].artistName.toLowerCase() ||
	   song === api_result.results[i].trackName.toLowerCase()) {
	    itunes.attr("href", api_result.results[i].trackViewUrl);
	    itunes.toggle();
	    // We need to resize when we add in the iTunes button.
	    ddg_spice_video.resizeDetail();
	    break;
	}
    }

};

Handlebars.registerHelper("userURL", function(provider_data, uploader) {
    return provider_data.user_url + uploader;
});

Handlebars.registerHelper("checkMusic", function(category, title, options) {
    // Remove things from the title that we don't really need.
    var stripTitle = function(s) {
	// Remove things like "(Explicit)".
	s = s.replace(/\(.*\)|\[.*\]/g, "");
	// Remove things like "feat. Alicia Keys".
	s = s.replace(/\s+f(?:ea|)t\..*$/g, "");
	// Trim the ends of the string.
	return s.replace(/^\s+|\s+$/g, "");
    };

    title = stripTitle(title);
    var songData = title.split(" - ");
    var artist = songData[0];
    var song = songData[1] || artist;

    // Call iTunes.
    $.getScript("/iit/" + encodeURIComponent(title));

    // Only add links to the music if, well, we have links to the music section.
    if(category === "Music") {
	// There's no need to escape the values--Handlebars.js does this for us.
	return options.fn({
	    title: title,
	    artist: artist,
	    song: song
	});
    }
});

// We'll use this for showing the view counts.
Handlebars.registerHelper("formatViews", function(views) {
    "use strict";
    if(views) {
	return String(views).replace(/(\d)(?=(\d{3})+(\.\d+|)\b)/g, "$1,");
    }
});

Handlebars.registerHelper("embedURL", function(provider_data, id) {
    function parameters(embed_options) {
	var result = [];
	for(o in embed_options) {
	    result.push(o + "=" + embed_options[o]);
	}
	return result.join("&");
    }

    return provider_data.embed + id + "?" +
	parameters(provider_data.embed_options);

    return "";
});

Handlebars.registerHelper("playURL", function(provider_data, id) {
    return provider_data.play_url + id;
});

Handlebars.registerHelper("checkStatistics", function(viewCount, options) {
    if(viewCount === null) {
	return "";
    }
    return options.fn({viewCount: viewCount});
});
<commit_msg>Video: Do not show the single detail view for now.<commit_after>function ddg_spice_video(api_result) {
    // Do not show the single detail view for now.
    if(!api_result || api_result.length <= 1) {
        return;
    }

    $.ajaxSetup({
        cache: true
    });

    var encodedQuery = DDG.get_query_encoded().replace(/(?:youtube|videos?)/i, '');

    // Change the "More at ..." link.
    var change_more = function(obj) {
	var more_at_link = $(".zero_click_more_at_link");
	more_at_link.attr("href", obj.search_link);
        more_at_link.find("img").attr("src", obj.image);
        more_at_link.find("span").html(obj.text);
    };

    // This are things that a provider needs when building the spice.
    var provider_data = {
	"YouTube": {
	    "search_link": "https://www.youtube.com/results?search_query=",
	    "image": "https://icons.duckduckgo.com/i/www.youtube.com.ico",
	    "text": "More at YouTube",
	    "embed": "https://www.youtube-nocookie.com/embed/",
	    "play_url": "https://www.youtube.com/watch?v=",
	    "user_url": "https://www.youtube.com/user/",
	    "embed_options": {
		"iv_load_policy": 3,
		"autoplay": 1,
		"wmode": "opaque"
	    }
	},
	"Vimeo": {
	    "search_link": "https://www.vimeo.com/search?q=",
	    "image": "https://icons.duckduckgo.com/i/www.vimeo.com.ico",
	    "text": "More at Vimeo",
	    "embed": "https://player.vimeo.com/video/",
	    "play_url": "https://vimeo.com/",
	    "user_url": "https://vimeo.com/",
	    "embed_options": {
		"api": 0,
		"autoplay": 1
	    }
	}
    };

    // Copy provider-specific data to the item.
    $.map(api_result, function(item) {
	item.provider_data = provider_data[item.provider];
    });

    Spice.render({
        data: api_result,
        source_name : 'YouTube',
        source_url : 'https://www.youtube.com/results?search_query=' + encodedQuery,
        header1 :  decodeURIComponent(encodedQuery) + " (Video)",
	spice_name: "video",
        template_frame: "carousel",
	template_options: {
	    items: api_result,
	    template_item: "video",
	    template_detail: "video_detail",
	    li_width: 120,
	    single_item_handler: function(obj) {
		// Prevent the video from playing if we only have one item.
		obj.data[0].provider_data.embed_options.autoplay = 0;
	    }
	},
        force_no_fold : 1,
	item_callback: function(i, item) {
	    var more_at_link = $(".zero_click_more_at_link").get(0);
	    change_more({
		"search_link": item.provider_data.search_link + encodedQuery,
		"image": item.provider_data.image,
		"text": item.provider_data.text
	    });
	    resizeDetail();
	}
    });

    function resizeDetail() {
	var $video = $("#spice_video");
	var width = $video.width() - 18;
	var height = Math.floor(width * 0.5625) + 30;
	$("#spice_video #video-embed").width(width);
	$("#spice_video #video-embed").height(height);

	var video_title = $("#spice_video #video-title").width();
	var video_links = $("#spice_video .links").width();

	if(width - (video_title + video_links) < 20) {
	    $("#spice_video .links").css("position", "static");
	} else {
	    $("#spice_video .links").css("position", "absolute");
	}
    }

    $(document).ready(function() {
	resizeDetail();
	$(window).resize(resizeDetail);
    });

    // Expose the function so that ddg_spice_video.itunes can use it.
    ddg_spice_video.resizeDetail = resizeDetail;
}

// This is the callback function of /itt.
ddg_spice_video.itunes = function(api_result) {
    if(!api_result || !api_result.results || api_result.results.length === 0) {
        return;
    }

    var itunes = $("#itunes");
    var artist = itunes.data("artist").toLowerCase();
    var song = itunes.data("song").toLowerCase();

    // Find the song that matches.
    for(var i = 0; i < api_result.results.length; i++) {
	if(artist === api_result.results[i].artistName.toLowerCase() ||
	   artist === api_result.results[i].trackName.toLowerCase() ||
	   song === api_result.results[i].artistName.toLowerCase() ||
	   song === api_result.results[i].trackName.toLowerCase()) {
	    itunes.attr("href", api_result.results[i].trackViewUrl);
	    itunes.toggle();
	    // We need to resize when we add in the iTunes button.
	    ddg_spice_video.resizeDetail();
	    break;
	}
    }

};

Handlebars.registerHelper("userURL", function(provider_data, uploader) {
    return provider_data.user_url + uploader;
});

Handlebars.registerHelper("checkMusic", function(category, title, options) {
    // Remove things from the title that we don't really need.
    var stripTitle = function(s) {
	// Remove things like "(Explicit)".
	s = s.replace(/\(.*\)|\[.*\]/g, "");
	// Remove things like "feat. Alicia Keys".
	s = s.replace(/\s+f(?:ea|)t\..*$/g, "");
	// Trim the ends of the string.
	return s.replace(/^\s+|\s+$/g, "");
    };

    title = stripTitle(title);
    var songData = title.split(" - ");
    var artist = songData[0];
    var song = songData[1] || artist;

    // Call iTunes.
    $.getScript("/iit/" + encodeURIComponent(title));

    // Only add links to the music if, well, we have links to the music section.
    if(category === "Music") {
	// There's no need to escape the values--Handlebars.js does this for us.
	return options.fn({
	    title: title,
	    artist: artist,
	    song: song
	});
    }
});

// We'll use this for showing the view counts.
Handlebars.registerHelper("formatViews", function(views) {
    "use strict";
    if(views) {
	return String(views).replace(/(\d)(?=(\d{3})+(\.\d+|)\b)/g, "$1,");
    }
});

Handlebars.registerHelper("embedURL", function(provider_data, id) {
    function parameters(embed_options) {
	var result = [];
	for(o in embed_options) {
	    result.push(o + "=" + embed_options[o]);
	}
	return result.join("&");
    }

    return provider_data.embed + id + "?" +
	parameters(provider_data.embed_options);

    return "";
});

Handlebars.registerHelper("playURL", function(provider_data, id) {
    return provider_data.play_url + id;
});

Handlebars.registerHelper("checkStatistics", function(viewCount, options) {
    if(viewCount === null) {
	return "";
    }
    return options.fn({viewCount: viewCount});
});
<|endoftext|>


<commit_before>'use strict';

const vscode = require('vscode');
const postcss = require('postcss');
const postcssSafeParser = require('postcss-safe-parser');

const resolve = require('npm-module-path');

let autoprefixer = null;

function getSyntax(language) {
  switch (language) {
    case 'less': {
      return require('postcss-less');
    }
    case 'scss': {
      return require('postcss-scss');
    }
    default: {
      return null;
    }
  }
}

function init(document, onDidSaveStatus) {
  const workspace = vscode.workspace.rootPath ? vscode.workspace.rootPath : '';
  resolve('autoprefixer', workspace, autoprefixer)
    .then((filepath) => {
      if (!autoprefixer) {
        autoprefixer = require(filepath);
      }

      const browsers = vscode.workspace.getConfiguration('autoprefixer').browsers;

      const content = document.getText();
      const lang = document.languageId || document._languageId;
      const syntax = getSyntax(lang);
      const parser = (lang === 'css') ? postcssSafeParser : syntax;

      postcss([autoprefixer(browsers)])
        .process(content, { parser })
        .then((result) => {
          result.warnings().forEach((x) => {
            console.warn(x.toString());
          });

          const editor = vscode.editor || vscode.window.activeTextEditor;
          if (!editor) {
            throw new Error('Ooops...');
          }

          const document = editor.document;
          const lastLine = document.lineAt(document.lineCount - 1);
          const start = new vscode.Position(0, 0);
          const end = new vscode.Position(document.lineCount - 1, lastLine.text.length);
          const range = new vscode.Range(start, end);

          if (document.autoprefixer) {
            delete document.autoprefixer;
            return;
          }

          if (onDidSaveStatus) {
            const we = new vscode.WorkspaceEdit();
            we.replace(document.uri, range, result.css);
            document.autoprefixer = true;
            vscode.workspace.applyEdit(we).then(() => {
              document.save();
            });
          } else {
            editor.edit((builder) => {
              builder.replace(range, result.css);
            });
          }
        })
        .catch(console.error);
    })
    .catch((err) => {
      if (err.code === 'ENOENT') {
        return vscode.window.showErrorMessage('Failed to load autoprefixer library. Please install autoprefixer in your workspace folder using **npm install autoprefixer** or globally using **npm install -g autoprefixer** and then run command again.');
      }

      console.error(err);
    });
}

function activate(context) {
  const disposable = vscode.commands.registerTextEditorCommand('autoprefixer.execute', (textEditor) => {
    init(textEditor.document, false);
  });

  context.subscriptions.push(disposable);

  const onSave = vscode.workspace.onDidSaveTextDocument((document) => {
    const onDidSave = vscode.workspace.getConfiguration('autoprefixer').prefixOnSave;
    if (onDidSave) {
      init(document, true);
    }
  });

  context.subscriptions.push(onSave);
}

exports.activate = activate;
<commit_msg>Fix for #8<commit_after>'use strict';

const vscode = require('vscode');
const postcss = require('postcss');
const safeParser = require('postcss-safe-parser');
const lessParser = require('postcss-less');
const lessStringifier = require('postcss-less/dist/less-stringify');
const scssParser = require('postcss-scss');

const resolve = require('npm-module-path');

let autoprefixer = null;

function getPostcssOptions(language) {
  switch (language) {
    case 'less': {
      return {
        parser: lessParser,
        stringifier: lessStringifier
      };
    }
    case 'scss': {
      return {
        parser: scssParser
      };
    }
    case 'css': {
      return {
        parser: safeParser
      };
    }
    default: {
      return null;
    }
  }
}

function init(document, onDidSaveStatus) {
  const workspace = vscode.workspace.rootPath ? vscode.workspace.rootPath : '';
  resolve('autoprefixer', workspace, autoprefixer)
    .then((filepath) => {
      if (!autoprefixer) {
        autoprefixer = require(filepath);
      }

      const browsers = vscode.workspace.getConfiguration('autoprefixer').browsers;

      const content = document.getText();
      const lang = document.languageId;
      const options = getPostcssOptions(lang);

      postcss([autoprefixer(browsers)])
        .process(content, options)
        .then((result) => {
          result.warnings().forEach((x) => {
            console.warn(x.toString());
          });

          const editor = vscode.editor || vscode.window.activeTextEditor;
          if (!editor) {
            throw new Error('Ooops...');
          }

          const document = editor.document;
          const lastLine = document.lineAt(document.lineCount - 1);
          const start = new vscode.Position(0, 0);
          const end = new vscode.Position(document.lineCount - 1, lastLine.text.length);
          const range = new vscode.Range(start, end);

          if (document.autoprefixer) {
            delete document.autoprefixer;
            return;
          }

          if (onDidSaveStatus) {
            const we = new vscode.WorkspaceEdit();
            we.replace(document.uri, range, result.css);
            document.autoprefixer = true;
            vscode.workspace.applyEdit(we).then(() => {
              document.save();
            });
          } else {
            editor.edit((builder) => {
              builder.replace(range, result.css);
            });
          }
        })
        .catch(console.error);
    })
    .catch((err) => {
      if (err.code === 'ENOENT') {
        return vscode.window.showErrorMessage('Failed to load autoprefixer library. Please install autoprefixer in your workspace folder using **npm install autoprefixer** or globally using **npm install -g autoprefixer** and then run command again.');
      }

      console.error(err);
    });
}

function activate(context) {
  const disposable = vscode.commands.registerTextEditorCommand('autoprefixer.execute', (textEditor) => {
    init(textEditor.document, false);
  });

  context.subscriptions.push(disposable);

  const onSave = vscode.workspace.onDidSaveTextDocument((document) => {
    const onDidSave = vscode.workspace.getConfiguration('autoprefixer').prefixOnSave;
    if (onDidSave) {
      init(document, true);
    }
  });

  context.subscriptions.push(onSave);
}

exports.activate = activate;
<|endoftext|>


<commit_before>const _ = require('lodash');
const errors = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
const MembersSSR = require('@tryghost/members-ssr');
const db = require('../../data/db');
const MembersConfigProvider = require('./config');
const MembersCSVImporter = require('@tryghost/members-importer');
const MembersStats = require('./stats/members-stats');
const createMembersSettingsInstance = require('./settings');
const logging = require('@tryghost/logging');
const urlUtils = require('../../../shared/url-utils');
const labsService = require('../../../shared/labs');
const settingsCache = require('../../../shared/settings-cache');
const config = require('../../../shared/config');
const models = require('../../models');
const {GhostMailer} = require('../mail');
const jobsService = require('../jobs');
const VerificationTrigger = require('@tryghost/verification-trigger');
const DomainEvents = require('@tryghost/domain-events');
const {LastSeenAtUpdater} = require('@tryghost/members-events-service');
const DatabaseInfo = require('@tryghost/database-info');

const messages = {
    noLiveKeysInDevelopment: 'Cannot use live stripe keys in development. Please restart in production mode.',
    sslRequiredForStripe: 'Cannot run Ghost without SSL when Stripe is connected. Please update your url config to use "https://".',
    remoteWebhooksInDevelopment: 'Cannot use remote webhooks in development. See https://ghost.org/docs/webhooks/#stripe-webhooks for developing with Stripe.'
};

const ghostMailer = new GhostMailer();

const membersConfig = new MembersConfigProvider({
    config,
    settingsCache,
    urlUtils
});

const membersStats = new MembersStats({
    db: db,
    settingsCache: settingsCache,
    isSQLite: DatabaseInfo.isSQLite(db.knex)
});

let membersApi;
let membersSettings;
let verificationTrigger;

const membersImporter = new MembersCSVImporter({
    storagePath: config.getContentPath('data'),
    getTimezone: () => settingsCache.get('timezone'),
    getMembersApi: () => module.exports.api,
    sendEmail: ghostMailer.send.bind(ghostMailer),
    isSet: labsService.isSet.bind(labsService),
    addJob: jobsService.addJob.bind(jobsService),
    knex: db.knex,
    urlFor: urlUtils.urlFor.bind(urlUtils),
    context: {
        importer: true
    }
});

const processImport = async (options) => {
    const result = await membersImporter.process(options);

    // Check whether all imports in last 30 days > threshold
    await verificationTrigger.testImportThreshold();

    return result;
};

module.exports = {
    async init() {
        const stripeService = require('../stripe');
        const createMembersApiInstance = require('./api');
        const env = config.get('env');

        // @TODO Move to stripe service
        if (env !== 'production') {
            if (stripeService.api.configured && stripeService.api.mode === 'live') {
                throw new errors.IncorrectUsageError({
                    message: tpl(messages.noLiveKeysInDevelopment)
                });
            }
        } else {
            const siteUrl = urlUtils.getSiteUrl();
            if (!/^https/.test(siteUrl) && stripeService.api.configured) {
                throw new errors.IncorrectUsageError({
                    message: tpl(messages.sslRequiredForStripe)
                });
            }
        }
        if (!membersApi) {
            membersApi = createMembersApiInstance(membersConfig);

            membersApi.bus.on('error', function (err) {
                logging.error(err);
            });
        }

        module.exports.ssr = MembersSSR({
            cookieSecure: urlUtils.isSSL(urlUtils.getSiteUrl()),
            cookieKeys: [settingsCache.get('theme_session_secret')],
            cookieName: 'ghost-members-ssr',
            getMembersApi: () => module.exports.api
        });

        verificationTrigger = new VerificationTrigger({
            configThreshold: _.get(config.get('hostSettings'), 'emailVerification.importThreshold'),
            isVerified: () => config.get('hostSettings:emailVerification:verified') === true,
            isVerificationRequired: () => settingsCache.get('email_verification_required') === true,
            sendVerificationEmail: ({subject, message, amountImported}) => {
                const escalationAddress = config.get('hostSettings:emailVerification:escalationAddress');
                const fromAddress = config.get('user_email');

                if (escalationAddress) {
                    ghostMailer.send({
                        subject,
                        html: tpl(message, {
                            importedNumber: amountImported,
                            siteUrl: urlUtils.getSiteUrl()
                        }),
                        forceTextContent: true,
                        from: fromAddress,
                        to: escalationAddress
                    });
                }
            },
            membersStats,
            Settings: models.Settings,
            eventRepository: membersApi.events
        });

        new LastSeenAtUpdater({
            services: {
                domainEvents: DomainEvents,
                settingsCache
            },
            async getMembersApi() {
                return membersApi;
            }
        });

        (async () => {
            try {
                const collection = await models.SingleUseToken.fetchAll();
                await collection.invokeThen('destroy');
            } catch (err) {
                logging.error(err);
            }
        })();

        const membersMigrationJobName = 'members-migrations';
        if (!(await jobsService.hasExecutedSuccessfully(membersMigrationJobName))) {
            jobsService.addOneOffJob({
                name: membersMigrationJobName,
                offloaded: false,
                job: stripeService.migrations.execute.bind(stripeService.migrations)
            });

            await jobsService.awaitCompletion(membersMigrationJobName);
        }
    },
    contentGating: require('./content-gating'),

    config: membersConfig,

    get api() {
        return membersApi;
    },

    get settings() {
        if (!membersSettings) {
            membersSettings = createMembersSettingsInstance(membersConfig);
        }
        return membersSettings;
    },

    ssr: null,

    stripeConnect: require('./stripe-connect'),

    processImport: processImport,

    stats: membersStats,
    export: require('./exporter/query')
};
module.exports.middleware = require('./middleware');
<commit_msg>Disabled members migrations in test environment<commit_after>const _ = require('lodash');
const errors = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
const MembersSSR = require('@tryghost/members-ssr');
const db = require('../../data/db');
const MembersConfigProvider = require('./config');
const MembersCSVImporter = require('@tryghost/members-importer');
const MembersStats = require('./stats/members-stats');
const createMembersSettingsInstance = require('./settings');
const logging = require('@tryghost/logging');
const urlUtils = require('../../../shared/url-utils');
const labsService = require('../../../shared/labs');
const settingsCache = require('../../../shared/settings-cache');
const config = require('../../../shared/config');
const models = require('../../models');
const {GhostMailer} = require('../mail');
const jobsService = require('../jobs');
const VerificationTrigger = require('@tryghost/verification-trigger');
const DomainEvents = require('@tryghost/domain-events');
const {LastSeenAtUpdater} = require('@tryghost/members-events-service');
const DatabaseInfo = require('@tryghost/database-info');

const messages = {
    noLiveKeysInDevelopment: 'Cannot use live stripe keys in development. Please restart in production mode.',
    sslRequiredForStripe: 'Cannot run Ghost without SSL when Stripe is connected. Please update your url config to use "https://".',
    remoteWebhooksInDevelopment: 'Cannot use remote webhooks in development. See https://ghost.org/docs/webhooks/#stripe-webhooks for developing with Stripe.'
};

const ghostMailer = new GhostMailer();

const membersConfig = new MembersConfigProvider({
    config,
    settingsCache,
    urlUtils
});

const membersStats = new MembersStats({
    db: db,
    settingsCache: settingsCache,
    isSQLite: DatabaseInfo.isSQLite(db.knex)
});

let membersApi;
let membersSettings;
let verificationTrigger;

const membersImporter = new MembersCSVImporter({
    storagePath: config.getContentPath('data'),
    getTimezone: () => settingsCache.get('timezone'),
    getMembersApi: () => module.exports.api,
    sendEmail: ghostMailer.send.bind(ghostMailer),
    isSet: labsService.isSet.bind(labsService),
    addJob: jobsService.addJob.bind(jobsService),
    knex: db.knex,
    urlFor: urlUtils.urlFor.bind(urlUtils),
    context: {
        importer: true
    }
});

const processImport = async (options) => {
    const result = await membersImporter.process(options);

    // Check whether all imports in last 30 days > threshold
    await verificationTrigger.testImportThreshold();

    return result;
};

module.exports = {
    async init() {
        const stripeService = require('../stripe');
        const createMembersApiInstance = require('./api');
        const env = config.get('env');

        // @TODO Move to stripe service
        if (env !== 'production') {
            if (stripeService.api.configured && stripeService.api.mode === 'live') {
                throw new errors.IncorrectUsageError({
                    message: tpl(messages.noLiveKeysInDevelopment)
                });
            }
        } else {
            const siteUrl = urlUtils.getSiteUrl();
            if (!/^https/.test(siteUrl) && stripeService.api.configured) {
                throw new errors.IncorrectUsageError({
                    message: tpl(messages.sslRequiredForStripe)
                });
            }
        }
        if (!membersApi) {
            membersApi = createMembersApiInstance(membersConfig);

            membersApi.bus.on('error', function (err) {
                logging.error(err);
            });
        }

        module.exports.ssr = MembersSSR({
            cookieSecure: urlUtils.isSSL(urlUtils.getSiteUrl()),
            cookieKeys: [settingsCache.get('theme_session_secret')],
            cookieName: 'ghost-members-ssr',
            getMembersApi: () => module.exports.api
        });

        verificationTrigger = new VerificationTrigger({
            configThreshold: _.get(config.get('hostSettings'), 'emailVerification.importThreshold'),
            isVerified: () => config.get('hostSettings:emailVerification:verified') === true,
            isVerificationRequired: () => settingsCache.get('email_verification_required') === true,
            sendVerificationEmail: ({subject, message, amountImported}) => {
                const escalationAddress = config.get('hostSettings:emailVerification:escalationAddress');
                const fromAddress = config.get('user_email');

                if (escalationAddress) {
                    ghostMailer.send({
                        subject,
                        html: tpl(message, {
                            importedNumber: amountImported,
                            siteUrl: urlUtils.getSiteUrl()
                        }),
                        forceTextContent: true,
                        from: fromAddress,
                        to: escalationAddress
                    });
                }
            },
            membersStats,
            Settings: models.Settings,
            eventRepository: membersApi.events
        });

        new LastSeenAtUpdater({
            services: {
                domainEvents: DomainEvents,
                settingsCache
            },
            async getMembersApi() {
                return membersApi;
            }
        });

        (async () => {
            try {
                const collection = await models.SingleUseToken.fetchAll();
                await collection.invokeThen('destroy');
            } catch (err) {
                logging.error(err);
            }
        })();

        if (!env?.startsWith('testing')) {
            const membersMigrationJobName = 'members-migrations';
            if (!(await jobsService.hasExecutedSuccessfully(membersMigrationJobName))) {
                jobsService.addOneOffJob({
                    name: membersMigrationJobName,
                    offloaded: false,
                    job: stripeService.migrations.execute.bind(stripeService.migrations)
                });

                await jobsService.awaitCompletion(membersMigrationJobName);
            }
        }
    },
    contentGating: require('./content-gating'),

    config: membersConfig,

    get api() {
        return membersApi;
    },

    get settings() {
        if (!membersSettings) {
            membersSettings = createMembersSettingsInstance(membersConfig);
        }
        return membersSettings;
    },

    ssr: null,

    stripeConnect: require('./stripe-connect'),

    processImport: processImport,

    stats: membersStats,
    export: require('./exporter/query')
};
module.exports.middleware = require('./middleware');
<|endoftext|>


<commit_before>// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-

const Gio = imports.gi.Gio;
const Meta = imports.gi.Meta;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Panel = imports.ui.panel;

const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;

const Main = imports.ui.main;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;

const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names';

const WorkspaceIndicator = new Lang.Class({
    Name: 'WorkspaceIndicator.WorkspaceIndicator',
    Extends: PanelMenu.Button,

    _init: function(){
		this.parent(0.0, _("Workspace Indicator"));

		this._currentWorkspace = global.screen.get_active_workspace().index();
		this.statusLabel = new St.Label({ y_align: Clutter.ActorAlign.CENTER,
											  text: this._labelText() });

		this.actor.add_actor(this.statusLabel);

		this.workspacesItems = [];
		this._workspaceSection = new PopupMenu.PopupMenuSection();
		this.menu.addMenuItem(this._workspaceSection);

		this._screenSignals = [];
		this._screenSignals.push(global.screen.connect_after('workspace-added', Lang.bind(this,this._createWorkspacesSection)));
		this._screenSignals.push(global.screen.connect_after('workspace-removed', Lang.bind(this,this._createWorkspacesSection)));
		this._screenSignals.push(global.screen.connect_after('workspace-switched', Lang.bind(this,this._updateIndicator)));

		this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
		this._createWorkspacesSection();

		//styling
		this.statusLabel.add_style_class_name('panel-workspace-indicator');

        this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
        this._settingsChangedId = this._settings.connect('changed::' + WORKSPACE_KEY, Lang.bind(this, this._createWorkspacesSection));
    },

    destroy: function() {
		for (let i = 0; i < this._screenSignals.length; i++)
			global.screen.disconnect(this._screenSignals[i]);

		if (this._settingsChangedId) {
			this._settings.disconnect(this._settingsChangedId);
			this._settingsChangedId = 0;
		}

		this.parent();
    },

    _updateIndicator: function() {
		this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE);
		this._currentWorkspace = global.screen.get_active_workspace().index();
		this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT);

		this.statusLabel.set_text(this._labelText());
    },

	_labelText : function(index) {
        if (index == undefined) {
            index = this._currentWorkspace
        }
		let name = Meta.prefs_get_workspace_name(index);
        if (name == undefined || name == null || name.trim() == '') {
            return (this._currentWorkspace + 1).toString();
        }
        return name;
	},

    _createWorkspacesSection : function() {
		this._workspaceSection.removeAll();
		this.workspacesItems = [];
		this._currentWorkspace = global.screen.get_active_workspace().index();

		let i = 0;
		for(; i < global.screen.n_workspaces; i++) {
			this.workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i));
			this._workspaceSection.addMenuItem(this.workspacesItems[i]);
			this.workspacesItems[i].workspaceId = i;
			this.workspacesItems[i].label_actor = this.statusLabel;
			let self = this;
			this.workspacesItems[i].connect('activate', Lang.bind(this, function(actor, event) {
			this._activate(actor.workspaceId);
			}));

			if (i == this._currentWorkspace)
			this.workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT);
		}

		this.statusLabel.set_text(this._labelText());
    },

    _activate : function (index) {
		if(index >= 0 && index <  global.screen.n_workspaces) {
			let metaWorkspace = global.screen.get_workspace_by_index(index);
			metaWorkspace.activate(global.get_current_time());
		}
    },

    _onScrollEvent : function(actor, event) {
		let direction = event.get_scroll_direction();
		let diff = 0;
		if (direction == Clutter.ScrollDirection.DOWN) {
			diff = 1;
		} else if (direction == Clutter.ScrollDirection.UP) {
			diff = -1;
		} else {
			return;
		}

		let newIndex = global.screen.get_active_workspace().index() + diff;
		this._activate(newIndex);
    }
});

function init(meta) {
    Convenience.initTranslations();
}

let _indicator;

function enable() {
    _indicator = new WorkspaceIndicator;
    Main.panel.addToStatusArea('workspace-indicator', _indicator);
}

function disable() {
    _indicator.destroy();
}
<commit_msg>Spacing issues<commit_after>// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-

const Gio = imports.gi.Gio;
const Meta = imports.gi.Meta;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Panel = imports.ui.panel;

const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;

const Main = imports.ui.main;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;

const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names';

const WorkspaceIndicator = new Lang.Class({
    Name: 'WorkspaceIndicator.WorkspaceIndicator',
    Extends: PanelMenu.Button,

    _init: function(){
		this.parent(0.0, _("Workspace Indicator"));

		this._currentWorkspace = global.screen.get_active_workspace().index();
		this.statusLabel = new St.Label({ y_align: Clutter.ActorAlign.CENTER,
											  text: this._labelText() });

		this.actor.add_actor(this.statusLabel);

		this.workspacesItems = [];
		this._workspaceSection = new PopupMenu.PopupMenuSection();
		this.menu.addMenuItem(this._workspaceSection);

		this._screenSignals = [];
		this._screenSignals.push(global.screen.connect_after('workspace-added', Lang.bind(this,this._createWorkspacesSection)));
		this._screenSignals.push(global.screen.connect_after('workspace-removed', Lang.bind(this,this._createWorkspacesSection)));
		this._screenSignals.push(global.screen.connect_after('workspace-switched', Lang.bind(this,this._updateIndicator)));

		this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
		this._createWorkspacesSection();

		//styling
		this.statusLabel.add_style_class_name('panel-workspace-indicator');

        this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
        this._settingsChangedId = this._settings.connect('changed::' + WORKSPACE_KEY, Lang.bind(this, this._createWorkspacesSection));
    },

    destroy: function() {
		for (let i = 0; i < this._screenSignals.length; i++)
			global.screen.disconnect(this._screenSignals[i]);

		if (this._settingsChangedId) {
			this._settings.disconnect(this._settingsChangedId);
			this._settingsChangedId = 0;
		}

		this.parent();
    },

    _updateIndicator: function() {
		this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE);
		this._currentWorkspace = global.screen.get_active_workspace().index();
		this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT);

		this.statusLabel.set_text(this._labelText());
    },

	_labelText : function(index) {
        if (index == undefined) {
            index = this._currentWorkspace
        }
		let name = Meta.prefs_get_workspace_name(index);
        if (name == undefined || name == null || name.trim() == '') {
            return (this._currentWorkspace + 1).toString();
        }
        return name;
	},

    _createWorkspacesSection : function() {
		this._workspaceSection.removeAll();
		this.workspacesItems = [];
		this._currentWorkspace = global.screen.get_active_workspace().index();

		let i = 0;
		for(; i < global.screen.n_workspaces; i++) {
			this.workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i));
			this._workspaceSection.addMenuItem(this.workspacesItems[i]);
			this.workspacesItems[i].workspaceId = i;
			this.workspacesItems[i].label_actor = this.statusLabel;
			this.workspacesItems[i].connect('activate', Lang.bind(this, function(actor, event) {
				this._activate(actor.workspaceId);
			}));

			if (i == this._currentWorkspace)
				this.workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT);
		}

		this.statusLabel.set_text(this._labelText());
    },

    _activate : function (index) {
		if(index >= 0 && index <  global.screen.n_workspaces) {
			let metaWorkspace = global.screen.get_workspace_by_index(index);
			metaWorkspace.activate(global.get_current_time());
		}
    },

    _onScrollEvent : function(actor, event) {
		let direction = event.get_scroll_direction();
		let diff = 0;
		if (direction == Clutter.ScrollDirection.DOWN) {
			diff = 1;
		} else if (direction == Clutter.ScrollDirection.UP) {
			diff = -1;
		} else {
			return;
		}

		let newIndex = global.screen.get_active_workspace().index() + diff;
		this._activate(newIndex);
    }
});

function init(meta) {
    Convenience.initTranslations();
}

let _indicator;

function enable() {
    _indicator = new WorkspaceIndicator;
    Main.panel.addToStatusArea('workspace-indicator', _indicator);
}

function disable() {
    _indicator.destroy();
}
<|endoftext|>


<commit_before>function ConstantsProviderFactory(constants) {
  const contextConstants = (
    Array.isArray(constants) ?
      constants.reduce((allConstants, constant) => {
        allConstants[constant] = constant

        return allConstants
      }, {})
    :
      constants
  )

  function ConstantsProvider(context) {
    context.constants = contextConstants

    return context
  }

  return ConstantsProvider
}

export default ConstantsProviderFactory
<commit_msg>feat(providers): remove constants provider, premature... overkill<commit_after><|endoftext|>


<commit_before>//automations.js: Client for the zendesk API.

var util        = require('util'),
    Client      = require('./client').Client,
    defaultUser = require('./helpers').defaultUser;

var Automations = exports.Automations = function (options) {
  this.jsonAPINames = [ 'automations', 'automation' ];
  Client.call(this, options);
};

// Inherit from Client base object
util.inherits(Automations, Client);

// ######################################################## Automations
// ====================================== Listing Automations
Automations.prototype.list = function (cb) {
  this.requestAll('GET', ['automations'], cb);//all
};

Automations.prototype.listActive = function (automationID, cb) {
  this.requestAll('GET', ['automations', 'active'],  cb);//all?
};

// ====================================== Viewing Automations
Automations.prototype.show = function (automationID, cb) {
  this.request('GET', ['automations', automationID], cb);
};

// ====================================== Creating Automations
Automations.prototype.create = function (automation, cb) {
  this.request('POST', ['automations'], automation,  cb);
};

// ====================================== Updating Automations
Automations.prototype.update = function (automationID, automation, cb) {
  this.request('PUT', ['automations', automationID], automation,  cb);
};

// ====================================== Deleting Automations
Automations.prototype.delete = function (automationID, cb) {
  this.request('DELETE', ['automations', automationID],  cb);
};

// ====================================== Reorder Audits
Automations.prototype.reorder = function (automationIDs, cb) {
  this.requestAll('PUT', ['automations', 'reorder'], {automation_ids: automationIDs}, cb);
};

<commit_msg>Fix return values of `automations.*`<commit_after>//automations.js: Client for the zendesk API.

var util        = require('util'),
    Client      = require('./client').Client,
    defaultUser = require('./helpers').defaultUser;

var Automations = exports.Automations = function (options) {
  this.jsonAPINames = [ 'automations', 'automation' ];
  Client.call(this, options);
};

// Inherit from Client base object
util.inherits(Automations, Client);

// ######################################################## Automations
// ====================================== Listing Automations
Automations.prototype.list = function (cb) {
  return this.requestAll('GET', ['automations'], cb);//all
};

Automations.prototype.listActive = function (automationID, cb) {
  return this.requestAll('GET', ['automations', 'active'],  cb);//all?
};

// ====================================== Viewing Automations
Automations.prototype.show = function (automationID, cb) {
  return this.request('GET', ['automations', automationID], cb);
};

// ====================================== Creating Automations
Automations.prototype.create = function (automation, cb) {
  return this.request('POST', ['automations'], automation,  cb);
};

// ====================================== Updating Automations
Automations.prototype.update = function (automationID, automation, cb) {
  return this.request('PUT', ['automations', automationID], automation,  cb);
};

// ====================================== Deleting Automations
Automations.prototype.delete = function (automationID, cb) {
  return this.request('DELETE', ['automations', automationID],  cb);
};

// ====================================== Reorder Audits
Automations.prototype.reorder = function (automationIDs, cb) {
  return this.requestAll('PUT', ['automations', 'reorder'], {automation_ids: automationIDs}, cb);
};

<|endoftext|>


<commit_before>/*
    Agora Forum Software
    Copyright (C) 2018 Gregory Sartucci
    License: AGPL-3.0, Check file LICENSE
*/

this.Actors = new Mongo.Collection('actors');

this.Actors.before.insert(function(userId, actor) {
    if (!activityPubActorTypes.includes(actor.type))
        throw new Meteor.Error('Not an Actor', 'Cannot insert document into Actor Collection: Not an Actor.');

    if (!activityPubSchemas.validate("Actor.json", actor))
        throw new Meteor.Error('Invalid Actor', 'Cannot insert Actor: Schema not valid:' + activityPubSchemas.errorsText());

    if (Actors.findOne({id: actor.id}))
        throw new Meteor.Error('Duplicate Actor', 'Cannot insert Actor: Actor with that id already present.');
});

this.Actors.after.insert(function(userId, actor) {
    if (actor.local) {
        Inboxes.insert({
            id: actor.inbox,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });

        Outboxes.insert({
            id: actor.outbox,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });

        FollowingLists.insert({
            id: actor.following,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });

        FollowerLists.insert({
            id: actor.followers,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });
    }
});

this.Actors.before.findOne(function(userId, selector, options) {
    if ((!options || !options.noRecursion) && selector.id && !Actors.findOne({id: selector.id}, {noRecursion: true}))
        try {
            Meteor.call('getActivityJSONFromUrl', selector.id);
        } catch(exception) {

        }
});

if (Meteor.isServer) {
    Meteor.startup(function() {
        Actors._ensureIndex({id: 1});
        Actors._ensureIndex({preferredUsername: 1});
    });
}
<commit_msg>remove validation against ActivityPub Schema, add more detail to error message<commit_after>/*
    Agora Forum Software
    Copyright (C) 2018 Gregory Sartucci
    License: AGPL-3.0, Check file LICENSE
*/

this.Actors = new Mongo.Collection('actors');

this.Actors.before.insert(function(userId, actor) {
    if (!activityPubActorTypes.includes(actor.type))
        throw new Meteor.Error('Not an Actor', 'Cannot insert document into Actor Collection: Not an Actor.');

    //if (!activityPubSchemas.validate("Actor.json", actor))
    //    throw new Meteor.Error('Invalid Actor', 'Cannot insert Actor: Schema not valid:' + activityPubSchemas.errorsText());

    if (Actors.findOne({id: actor.id}))
        throw new Meteor.Error('Duplicate Actor', 'Cannot insert Actor: Actor with that id already present: ' + actor.id);
});

this.Actors.after.insert(function(userId, actor) {
    if (actor.local) {
        Inboxes.insert({
            id: actor.inbox,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });

        Outboxes.insert({
            id: actor.outbox,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });

        FollowingLists.insert({
            id: actor.following,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });

        FollowerLists.insert({
            id: actor.followers,
            type: "OrderedCollection",
            totalItems: 0,
            orderedItems: []
        });
    }
});

this.Actors.before.findOne(function(userId, selector, options) {
    if ((!options || !options.noRecursion) && selector.id && !Actors.findOne({id: selector.id}, {noRecursion: true}))
        try {
            Meteor.call('getActivityJSONFromUrl', selector.id);
        } catch(exception) {

        }
});

if (Meteor.isServer) {
    Meteor.startup(function() {
        Actors._ensureIndex({id: 1});
        Actors._ensureIndex({preferredUsername: 1});
    });
}
<|endoftext|>