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

define([
    "firebug/lib/object",
    "firebug/firebug",
    "firebug/chrome/firefox",
    "firebug/lib/locale",
    "firebug/lib/domplate",
    "firebug/lib/xpcom",
    "firebug/lib/url",
    "firebug/lib/dom"
],
function(Obj, Firebug, Firefox, Locale, Domplate, Xpcom, Url, Dom) {

// ************************************************************************************************
// Constants

const Cc = Components.classes;
const Ci = Components.interfaces;

const prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
const prompts = Xpcom.CCSV("@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService");

/**
 * @module Implements Panel activation logic. A Firebug panel can support activation in order
 * to avoid performance penalties in cases when panel's features are not necessary at the moment.
 * Such panel must be derived from {@link Firebug.ActivablePanel} and appropriate activable
 * module from {@link Firebug.ActivableModule}
 */
Firebug.PanelActivation = Obj.extend(Firebug.Module,
/** @lends Firebug.PanelActivation */
{
    dispatchName: "panelActivation",

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

    initialize: function()
    {
        prefs.addObserver(Firebug.Options.getPrefDomain(), this, false);
        Firebug.connection.addListener(this);
    },

    initializeUI: function()
    {
        // The "off" option is removed so make sure to convert previous value
        // into "none" if necessary.
        if (Firebug.allPagesActivation == "off")
            Firebug.allPagesActivation = "none";

        // Update option menu item.
        this.updateAllPagesActivation();
    },

    shutdown: function()
    {
        prefs.removeObserver(Firebug.Options.getPrefDomain(), this, false);
        Firebug.connection.removeListener(this);
    },

    showPanel: function(browser, panel)
    {
        if (FBTrace.DBG_ACTIVATION)
            FBTrace.sysout("PanelActivation.showPanel; " + (panel ? panel.name : "null panel"));

        // Panel toolbar is not displayed for disabled panels.
        var chrome = Firebug.chrome;
        Dom.collapse(chrome.$("fbToolbar"), !panel);
    },

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

    activatePanelTypes: function(panelTypes)
    {
        for (var i=0; i<panelTypes.length; i++)
        {
            var panelType = panelTypes[i];
            if (!this.isPanelActivable(panelType))
                continue;

            if (this.isPanelEnabled(panelType))
                panelType.prototype.onActivationChanged(true);
        }
    },

    deactivatePanelTypes: function(panelTypes)
    {
        for (var i=0; i<panelTypes.length; i++)
        {
            var panelType = panelTypes[i];
            if (!this.isPanelActivable(panelType))
                continue;

            if (this.isPanelEnabled(panelType))
                panelType.prototype.onActivationChanged(false);
        }
    },

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

    isPanelActivable: function(panelType)
    {
        return panelType.prototype.activable ? true : false;
    },

    isPanelEnabled: function(panelType)
    {
        if (typeof(panelType) == "string")
            panelType = Firebug.getPanelType("script");

        if (!this.isPanelActivable(panelType))
            return true;

        // Panel "class" object is used to decide whether a panel is disabled
        // or not (i.e.: isEnabled is a static method of Firebug.Panel)
        return panelType ? panelType.prototype.isEnabled() : false;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Enable & disable methods.

    enablePanel: function(panelType)
    {
        this.setPanelState(panelType, true);
    },

    disablePanel: function(panelType)
    {
        this.setPanelState(panelType, false);
    },

    enableAllPanels: function()
    {
        for (var i = 0; i < Firebug.panelTypes.length; ++i)
        {
            var panelType = Firebug.panelTypes[i];
            this.setPanelState(panelType, true);
        }
    },

    disableAllPanels: function()
    {
        for (var i = 0; i < Firebug.panelTypes.length; ++i)
        {
            var panelType = Firebug.panelTypes[i];
            this.setPanelState(panelType, false);
        }
    },

    setPanelState: function(panelType, enable)
    {
        if (panelType && panelType.prototype.setEnabled)
            panelType.prototype.setEnabled(enable);

        this.updateTab(panelType);
    },

    updateTab: function(panelType)
    {
        var panelName = panelType.prototype.name;
        var panelBar = Firebug.chrome.$("fbPanelBar1");
        var tab = panelBar.updateTab(panelType);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Observer activation changes (preference)

    /**
     * Observer for activation preferences changes.
     */
    observe: function(subject, topic, data)
    {
        if (topic != "nsPref:changed")
            return;

        if (data.indexOf(".enableSites") == -1)
            return;

        var parts = data.split(".");
        if (parts.length != 4)
            return;

        try
        {
            var panelName = parts[2];
            var enable = Firebug.Options.get(panelName + ".enableSites");

            var panelType = Firebug.getPanelType(panelName, enable);
            if (panelType)
                this.onActivationChanged(panelType, enable);
        }
        catch (e)
        {
            if (FBTrace.DBG_ACTIVATION || FBTrace.DBG_ERRORS)
                FBTrace.sysout("PanelActivation.observe; EXCEPTION " + e, e);
        }
    },

    onActivationChanged: function(panelType, enable)
    {
        if (!enable)
        {
            // Iterate all contexts and destroy all instances of the specified panel.
            var self = this;
            Firebug.connection.eachContext(function(context) {
                context.destroyPanel(panelType, context.persistedState);
            });
        }

        panelType.prototype.onActivationChanged(enable);

        Firebug.chrome.$("fbPanelBar1").updateTab(panelType);
        Firebug.chrome.syncPanel();
    },

    // respond to event
    onClearAnnotations: function()
    {
        Firebug.closeFirebug(true);  // and we turn off as it now cannot be enabled
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // UI commands

    clearAnnotations: function(force)
    {
        if (!force)
        {
            var check = {value: false};
            var flags = prompts.BUTTON_POS_0 * prompts.BUTTON_TITLE_YES +
            prompts.BUTTON_POS_1 * prompts.BUTTON_TITLE_NO;

            if (!prompts.confirmEx(Firebug.chrome.window, Locale.$STR("Firebug"),
                Locale.$STR("annotations.confirm.clear"), flags, "", "", "", null, check) == 0)
            {
                return;
            }
        }

        Firebug.connection.clearAnnotations();
    },

    toggleAll: function(state)
    {
        if (FBTrace.DBG_ACTIVATION)
            FBTrace.sysout("Firebug.toggleAll("+state+") with allPagesActivation: " +
                Firebug.allPagesActivation);

        if (state == "on")
        {
            if (Firebug.allPagesActivation == state) // then we were armed
                Firebug.allPagesActivation = "none";
            else
                this.allOn();
        }
        else
        {
            Firebug.allPagesActivation = "none";
        }

        Firebug.Options.set("allPagesActivation", Firebug.allPagesActivation);
        this.updateAllPagesActivation();
    },

    updateOption: function(name, value)
    {
        if (name == "allPagesActivation")
            this.updateAllPagesActivation();
    },

    updateAllPagesActivation: function()
    {
        // don't show Off button if we are always on
        var allOn = Firebug.allPagesActivation == "on";
        Firebug.chrome.disableOff(allOn);

        Firebug.StartButton.resetTooltip();
    },

    allOn: function()
    {
        Firebug.allPagesActivation = "on";  // In future we always create contexts,
        Firebug.toggleBar(true);  // and we turn on for the current page
    }
});

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

/**
 * @domplate This template renders default content for disabled panels.
 */
with (Domplate) {
Firebug.DisabledPanelBox = domplate(Firebug.Rep,
/** @lends Firebug.DisabledPanelBox */
{
    tag:
        DIV({"class": "disabledPanelBox"},
            H1({"class": "disabledPanelHead"},
                SPAN("$pageTitle")
            ),
            P({"class": "disabledPanelDescription", style: "margin-top: 15px;"},
                Locale.$STR("moduleManager.desc3"),
                SPAN(" "),
                SPAN({"class": "descImage descImage-$panelName"})
            ),
            A({"class": "objectLink", onclick: "$onEnable"},
                Locale.$STR("moduleManager.Enable")
            )
            /* need something here that pushes down any thing appended to the panel */
        ),

    onEnable: function(event)
    {
        var view = event.target.ownerDocument.defaultView;
        var isMainPanel = (view.name == "fbPanelBar1-browser");
        var panelBar = Firebug.chrome.$(isMainPanel ? "fbPanelBar1" : "fbPanelBar2");

        var panelType = panelBar.selectedTab.panelType;
        if (panelType.prototype.setEnabled)
        {
            panelType.prototype.setEnabled(true);
            panelBar.updateTab(panelType);
        }
        else
        {
            if (FBTrace.DBG_ERRORS)
                FBTrace.sysout("panelActivation.onEnable; panel is not activable: " +
                    Firebug.getPanelTitle(panelType));
        }
    },

    /**
     * Show default content saying that this panel type (specified by name) is disabled.
     * The parent node is specified in panel.html file.
     */
    show: function(browser, panelName)
    {
        if (!panelName)
            return;

        var panel = Firebug.getPanelType(panelName);
        var panelTitle = Firebug.getPanelTitle(panel);
        var args = {
            pageTitle: Locale.$STRF("moduleManager.title", [panelTitle]),
            panelName: panelName
        };

        var parentNode = this.getParentNode(browser);
        this.tag.replace(args, parentNode, this);
        parentNode.removeAttribute("collapsed");
    },

    /**
     * Hide currently displayed default content.
     */
    hide: function(browser)
    {
        var parentNode = this.getParentNode(browser);

        // xxxHonza: I am seeing null parentNode when Firebug initializes
        // Could it be because the panel.html can sometimes take more time to load?
        if (!parentNode)
            return;

        Dom.clearNode(parentNode);
        parentNode.setAttribute("collapsed", true);
    },

    getParentNode: function(browser)
    {
        var doc = browser.contentDocument;
        return doc.documentElement.querySelector(".disabledPanelNode");
    },
});
};

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

Firebug.registerModule(Firebug.PanelActivation);

return Firebug.PanelActivation;

// ************************************************************************************************
});
<commit_msg>Fix comments<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/lib/object",
    "firebug/firebug",
    "firebug/chrome/firefox",
    "firebug/lib/locale",
    "firebug/lib/domplate",
    "firebug/lib/xpcom",
    "firebug/lib/url",
    "firebug/lib/dom"
],
function(Obj, Firebug, Firefox, Locale, Domplate, Xpcom, Url, Dom) {

// ********************************************************************************************* //
// Constants

const Cc = Components.classes;
const Ci = Components.interfaces;

const prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
const prompts = Xpcom.CCSV("@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService");

/**
 * @module Implements Panel activation logic. A Firebug panel can support activation in order
 * to avoid performance penalties in cases when panel's features are not necessary at the moment.
 * Such panel must be derived from {@link Firebug.ActivablePanel} and appropriate activable
 * module from {@link Firebug.ActivableModule}
 */
Firebug.PanelActivation = Obj.extend(Firebug.Module,
/** @lends Firebug.PanelActivation */
{
    dispatchName: "panelActivation",

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

    initialize: function()
    {
        prefs.addObserver(Firebug.Options.getPrefDomain(), this, false);
        Firebug.connection.addListener(this);
    },

    initializeUI: function()
    {
        // The "off" option is removed so make sure to convert previous value
        // into "none" if necessary.
        if (Firebug.allPagesActivation == "off")
            Firebug.allPagesActivation = "none";

        // Update option menu item.
        this.updateAllPagesActivation();
    },

    shutdown: function()
    {
        prefs.removeObserver(Firebug.Options.getPrefDomain(), this, false);
        Firebug.connection.removeListener(this);
    },

    showPanel: function(browser, panel)
    {
        if (FBTrace.DBG_ACTIVATION)
            FBTrace.sysout("PanelActivation.showPanel; " + (panel ? panel.name : "null panel"));

        // Panel toolbar is not displayed for disabled panels.
        var chrome = Firebug.chrome;
        Dom.collapse(chrome.$("fbToolbar"), !panel);
    },

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

    activatePanelTypes: function(panelTypes)
    {
        for (var i=0; i<panelTypes.length; i++)
        {
            var panelType = panelTypes[i];
            if (!this.isPanelActivable(panelType))
                continue;

            if (this.isPanelEnabled(panelType))
                panelType.prototype.onActivationChanged(true);
        }
    },

    deactivatePanelTypes: function(panelTypes)
    {
        for (var i=0; i<panelTypes.length; i++)
        {
            var panelType = panelTypes[i];
            if (!this.isPanelActivable(panelType))
                continue;

            if (this.isPanelEnabled(panelType))
                panelType.prototype.onActivationChanged(false);
        }
    },

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

    isPanelActivable: function(panelType)
    {
        return panelType.prototype.activable ? true : false;
    },

    isPanelEnabled: function(panelType)
    {
        if (typeof(panelType) == "string")
            panelType = Firebug.getPanelType("script");

        if (!this.isPanelActivable(panelType))
            return true;

        // Panel "class" object is used to decide whether a panel is disabled
        // or not (i.e.: isEnabled is a static method of Firebug.Panel)
        return panelType ? panelType.prototype.isEnabled() : false;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Enable & disable methods.

    enablePanel: function(panelType)
    {
        this.setPanelState(panelType, true);
    },

    disablePanel: function(panelType)
    {
        this.setPanelState(panelType, false);
    },

    enableAllPanels: function()
    {
        for (var i = 0; i < Firebug.panelTypes.length; ++i)
        {
            var panelType = Firebug.panelTypes[i];
            this.setPanelState(panelType, true);
        }
    },

    disableAllPanels: function()
    {
        for (var i = 0; i < Firebug.panelTypes.length; ++i)
        {
            var panelType = Firebug.panelTypes[i];
            this.setPanelState(panelType, false);
        }
    },

    setPanelState: function(panelType, enable)
    {
        if (panelType && panelType.prototype.setEnabled)
            panelType.prototype.setEnabled(enable);

        this.updateTab(panelType);
    },

    updateTab: function(panelType)
    {
        var panelName = panelType.prototype.name;
        var panelBar = Firebug.chrome.$("fbPanelBar1");
        var tab = panelBar.updateTab(panelType);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Observer activation changes (preference)

    /**
     * Observer for activation preferences changes.
     */
    observe: function(subject, topic, data)
    {
        if (topic != "nsPref:changed")
            return;

        if (data.indexOf(".enableSites") == -1)
            return;

        var parts = data.split(".");
        if (parts.length != 4)
            return;

        try
        {
            var panelName = parts[2];
            var enable = Firebug.Options.get(panelName + ".enableSites");

            var panelType = Firebug.getPanelType(panelName, enable);
            if (panelType)
                this.onActivationChanged(panelType, enable);
        }
        catch (e)
        {
            if (FBTrace.DBG_ACTIVATION || FBTrace.DBG_ERRORS)
                FBTrace.sysout("PanelActivation.observe; EXCEPTION " + e, e);
        }
    },

    onActivationChanged: function(panelType, enable)
    {
        if (!enable)
        {
            // Iterate all contexts and destroy all instances of the specified panel.
            var self = this;
            Firebug.connection.eachContext(function(context) {
                context.destroyPanel(panelType, context.persistedState);
            });
        }

        panelType.prototype.onActivationChanged(enable);

        Firebug.chrome.$("fbPanelBar1").updateTab(panelType);
        Firebug.chrome.syncPanel();
    },

    // respond to event
    onClearAnnotations: function()
    {
        Firebug.closeFirebug(true);  // and we turn off as it now cannot be enabled
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // UI commands

    clearAnnotations: function(force)
    {
        if (!force)
        {
            var check = {value: false};
            var flags = prompts.BUTTON_POS_0 * prompts.BUTTON_TITLE_YES +
            prompts.BUTTON_POS_1 * prompts.BUTTON_TITLE_NO;

            if (!prompts.confirmEx(Firebug.chrome.window, Locale.$STR("Firebug"),
                Locale.$STR("annotations.confirm.clear"), flags, "", "", "", null, check) == 0)
            {
                return;
            }
        }

        Firebug.connection.clearAnnotations();
    },

    toggleAll: function(state)
    {
        if (FBTrace.DBG_ACTIVATION)
            FBTrace.sysout("Firebug.toggleAll("+state+") with allPagesActivation: " +
                Firebug.allPagesActivation);

        if (state == "on")
        {
            if (Firebug.allPagesActivation == state) // then we were armed
                Firebug.allPagesActivation = "none";
            else
                this.allOn();
        }
        else
        {
            Firebug.allPagesActivation = "none";
        }

        Firebug.Options.set("allPagesActivation", Firebug.allPagesActivation);
        this.updateAllPagesActivation();
    },

    updateOption: function(name, value)
    {
        if (name == "allPagesActivation")
            this.updateAllPagesActivation();
    },

    updateAllPagesActivation: function()
    {
        // don't show Off button if we are always on
        var allOn = Firebug.allPagesActivation == "on";
        Firebug.chrome.disableOff(allOn);

        Firebug.StartButton.resetTooltip();
    },

    allOn: function()
    {
        Firebug.allPagesActivation = "on";  // In future we always create contexts,
        Firebug.toggleBar(true);  // and we turn on for the current page
    }
});

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

/**
 * @domplate This template renders default content for disabled panels.
 */
with (Domplate) {
Firebug.DisabledPanelBox = domplate(Firebug.Rep,
/** @lends Firebug.DisabledPanelBox */
{
    tag:
        DIV({"class": "disabledPanelBox"},
            H1({"class": "disabledPanelHead"},
                SPAN("$pageTitle")
            ),
            P({"class": "disabledPanelDescription", style: "margin-top: 15px;"},
                Locale.$STR("moduleManager.desc3"),
                SPAN(" "),
                SPAN({"class": "descImage descImage-$panelName"})
            ),
            A({"class": "objectLink", onclick: "$onEnable"},
                Locale.$STR("moduleManager.Enable")
            )
            /* need something here that pushes down any thing appended to the panel */
        ),

    onEnable: function(event)
    {
        var view = event.target.ownerDocument.defaultView;
        var isMainPanel = (view.name == "fbPanelBar1-browser");
        var panelBar = Firebug.chrome.$(isMainPanel ? "fbPanelBar1" : "fbPanelBar2");

        var panelType = panelBar.selectedTab.panelType;
        if (panelType.prototype.setEnabled)
        {
            panelType.prototype.setEnabled(true);
            panelBar.updateTab(panelType);
        }
        else
        {
            if (FBTrace.DBG_ERRORS)
                FBTrace.sysout("panelActivation.onEnable; panel is not activable: " +
                    Firebug.getPanelTitle(panelType));
        }
    },

    /**
     * Show default content saying that this panel type (specified by name) is disabled.
     * The parent node is specified in panel.html file.
     */
    show: function(browser, panelName)
    {
        if (!panelName)
            return;

        var panel = Firebug.getPanelType(panelName);
        var panelTitle = Firebug.getPanelTitle(panel);
        var args = {
            pageTitle: Locale.$STRF("moduleManager.title", [panelTitle]),
            panelName: panelName
        };

        var parentNode = this.getParentNode(browser);
        this.tag.replace(args, parentNode, this);
        parentNode.removeAttribute("collapsed");
    },

    /**
     * Hide currently displayed default content.
     */
    hide: function(browser)
    {
        var parentNode = this.getParentNode(browser);

        // xxxHonza: I am seeing null parentNode when Firebug initializes
        // Could it be because the panel.html can sometimes take more time to load?
        if (!parentNode)
            return;

        Dom.clearNode(parentNode);
        parentNode.setAttribute("collapsed", true);
    },

    getParentNode: function(browser)
    {
        var doc = browser.contentDocument;
        return doc.documentElement.querySelector(".disabledPanelNode");
    },
});
};

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

Firebug.registerModule(Firebug.PanelActivation);

return Firebug.PanelActivation;

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


<commit_before>var events = require("../../../client/pointer.coffee"),
    fetchValue = require("../../../core/fetch/value.coffee"),
    print      = require("../../../core/console/print.coffee"),
    rtl        = require("../../../client/rtl.coffee"),
    textWrap   = require("../../../textwrap/textwrap.coffee")
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Draws appropriate titles
//------------------------------------------------------------------------------
module.exports = function(vars) {

  var total_key = vars.size.value ? vars.size.value
    : vars.color.type === "number" ? vars.color.value : false

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // If there is no data or the title bar is not needed,
  // set the total value to 'null'
  //----------------------------------------------------------------------------
  if (!vars.data.viz || !vars.title.total.value || vars.small) {
    var total = false
  }
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Otherwise, let's calculate it!
  //----------------------------------------------------------------------------
  else if (total_key) {

    if ( vars.dev.value ) {
      print.time("calculating total value")
    }

    if (vars.focus.value.length) {
      var total = vars.data.viz.filter(function(d){
        return d[vars.id.value] == vars.focus.value[0]
      })
      total = d3.sum(total,function(d){
        return fetchValue(vars,d,total_key)
      })
    }
    else {
      var total = d3.sum(vars.data.pool,function(d){
        return fetchValue(vars,d,total_key)
      })
    }

    if (total === 0) {
      total = false
    }

    if (typeof total === "number") {

      var pct = ""

      if (vars.data.mute.length || vars.data.solo.length || vars.focus.value.length) {

        var overall_total = d3.sum(vars.data.value, function(d){
          if (vars.time.solo.value.length > 0) {
            var match = vars.time.solo.value.indexOf(fetchValue(vars,d,vars.time.value)) >= 0
          }
          else if (vars.time.mute.value.length > 0) {
            var match = vars.time.solo.value.indexOf(fetchValue(vars,d,vars.time.value)) < 0
          }
          else {
            var match = true
          }
          if (match) {
            return fetchValue(vars,d,total_key)
          }
        })

        if (overall_total > total) {

          var pct = (total/overall_total)*100,
              ot = vars.format.value(overall_total,vars.size.value, vars)

          var pct = " ("+vars.format.value(pct,"share")+"% of "+ot+", vars)"

        }
      }

      total = vars.format.value(total,vars.size.value, vars)
      var obj = vars.title.total.value
        , prefix = obj.prefix || vars.format.value(vars.format.locale.value.ui.total)+": "
      total = prefix + total
      obj.suffix ? total = total + obj.suffix : null
      total += pct

    }

    if ( vars.dev.value ) {
      print.timeEnd("calculating total value")
    }

  }
  else {
    var total = false
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Initialize titles and detect footer
  //----------------------------------------------------------------------------
  var title_data = []

  if (vars.footer.value) {
    title_data.push({
      "link": vars.footer.link,
      "style": vars.footer,
      "type": "footer",
      "value": vars.footer.value
    })
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // If not in "small" mode, detect titles available
  //----------------------------------------------------------------------------
  if (!vars.small) {

    if (vars.title.value) {
      title_data.push({
        "link": vars.title.link,
        "style": vars.title,
        "type": "title",
        "value": vars.title.value
      })
    }
    if (vars.title.sub.value) {
      title_data.push({
        "link": vars.title.sub.link,
        "style": vars.title.sub,
        "type": "sub",
        "value": vars.title.sub.value
      })
    }
    if (vars.title.total.value && total) {
      title_data.push({
        "link": vars.title.total.link,
        "style": vars.title.total,
        "type": "total",
        "value": total
      })
    }

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Title positioning
  //----------------------------------------------------------------------------
  function position(title) {

    title
      .style("text-anchor",function(t){

        var align = t.style.font.align

        if (align == "center") {
          return "middle"
        }
        else if ((align == "left" && !rtl) || (align == "right" && rtl)) {
          return "start"
        }
        else if ((align == "left" && rtl) || (align == "right" && !rtl)) {
          return "end"
        }

      })
      .attr("x",function(t){

        var align = t.style.font.align

        if (align == "center") {
          return vars.width.value/2
        }
        else if ((align == "left" && !rtl) || (align == "right" && rtl)) {
          return vars.padding
        }
        else if ((align == "left" && rtl) || (align == "right" && !rtl)) {
          return vars.width.value-vars.padding
        }

      })
      .attr("y",0)

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Enter Titles
  //----------------------------------------------------------------------------
  function style(title) {

    title
      .attr("font-size",function(t){
        return t.style.font.size
      })
      .attr("fill",function(t){
        return t.link ? vars.links.font.color : t.style.font.color
      })
      .attr("font-family",function(t){
        return t.link ? vars.links.font.family.value : t.style.font.family.value
      })
      .attr("font-weight",function(t){
        return t.link ? vars.links.font.weight : t.style.font.weight
      })
      .style("text-decoration",function(t){
        return t.link ? vars.links.font.decoration.value : t.style.font.decoration.value
      })
      .style("text-transform",function(t){
        return t.link ? vars.links.font.transform.value : t.style.font.transform.value
      })

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Enter Titles
  //----------------------------------------------------------------------------
  if ( vars.dev.value ) print.time("drawing titles")
  var titles = vars.svg.selectAll("g.d3plus_title")
    .data(title_data,function(t){
      return t.type
    })

  var titleWidth = vars.title.width || vars.width.value

  titles.enter().append("g")
    .attr("class","d3plus_title")
    .attr("opacity",0)
    .attr("transform",function(t){
      var y = t.style.position == "top" ? 0 : vars.height.value
      return "translate(0,"+y+")"
    })
    .append("text")
      .call(position)
      .call(style)

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Wrap text and calculate positions, then transition style and opacity
  //----------------------------------------------------------------------------
  titles
    .each(function(d){

      textWrap()
        .container( d3.select(this).select("text") )
        .height( vars.height.value / 8 )
        .size(false)
        .text( d.value )
        .width( titleWidth )
        .draw()

      d.y = vars.margin[d.style.position]
      vars.margin[d.style.position] += this.getBBox().height + d.style.padding*2

    })
    .on(events.over,function(t){
      if (t.link) {
        d3.select(this)
          .transition().duration(vars.timing.mouseevents)
          .style("cursor","pointer")
          .select("text")
            .attr("fill",vars.links.hover.color)
            .attr("font-family",vars.links.hover.family.value)
            .attr("font-weight",vars.links.hover.weight)
            .style("text-decoration",vars.links.hover.decoration.value)
            .style("text-transform",vars.links.hover.transform.value)
      }
    })
    .on(events.out,function(t){
      if (t.link) {
        d3.select(this)
          .transition().duration(vars.timing.mouseevents)
          .style("cursor","auto")
          .select("text")
            .call(style)
      }
    })
    .on(events.click,function(t){
      if (t.link) {
        var target = t.link.charAt(0) != "/" ? "_blank" : "_self"
        window.open(t.link,target)
      }
    })
    .transition().duration(vars.draw.timing)
      .attr("opacity",1)
      .attr("transform",function(t){
        var pos = t.style.position,
            y = pos == "top" ? 0+t.y : vars.height.value-t.y
        if (pos == "bottom") {
          y -= this.getBBox().height+t.style.padding
        }
        else {
          y += t.style.padding
        }
        return "translate(0,"+y+")"
      })
      .select("text")
        .call(position)
        .call(style)

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Exit unused titles
  //----------------------------------------------------------------------------
  titles.exit().transition().duration(vars.draw.timing)
    .attr("opacity",0)
    .remove()

  if ( vars.margin.top > 0 ) {
    vars.margin.top += vars.title.padding
  }

  if ( vars.margin.bottom > 0 ) {
    vars.margin.bottom += vars.title.padding
  }

  var min = vars.title.height
  if (min && vars.margin[vars.title.position] < min) {
    vars.margin[vars.title.position] = min
  }

  if ( vars.dev.value ) print.timeEnd("drawing titles")

}
<commit_msg>fixed textwrap in titles<commit_after>var events = require("../../../client/pointer.coffee"),
    fetchValue = require("../../../core/fetch/value.coffee"),
    print      = require("../../../core/console/print.coffee"),
    rtl        = require("../../../client/rtl.coffee"),
    textWrap   = require("../../../textwrap/textwrap.coffee")
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Draws appropriate titles
//------------------------------------------------------------------------------
module.exports = function(vars) {

  var total_key = vars.size.value ? vars.size.value
    : vars.color.type === "number" ? vars.color.value : false

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // If there is no data or the title bar is not needed,
  // set the total value to 'null'
  //----------------------------------------------------------------------------
  if (!vars.data.viz || !vars.title.total.value || vars.small) {
    var total = false
  }
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Otherwise, let's calculate it!
  //----------------------------------------------------------------------------
  else if (total_key) {

    if ( vars.dev.value ) {
      print.time("calculating total value")
    }

    if (vars.focus.value.length) {
      var total = vars.data.viz.filter(function(d){
        return d[vars.id.value] == vars.focus.value[0]
      })
      total = d3.sum(total,function(d){
        return fetchValue(vars,d,total_key)
      })
    }
    else {
      var total = d3.sum(vars.data.pool,function(d){
        return fetchValue(vars,d,total_key)
      })
    }

    if (total === 0) {
      total = false
    }

    if (typeof total === "number") {

      var pct = ""

      if (vars.data.mute.length || vars.data.solo.length || vars.focus.value.length) {

        var overall_total = d3.sum(vars.data.value, function(d){
          if (vars.time.solo.value.length > 0) {
            var match = vars.time.solo.value.indexOf(fetchValue(vars,d,vars.time.value)) >= 0
          }
          else if (vars.time.mute.value.length > 0) {
            var match = vars.time.solo.value.indexOf(fetchValue(vars,d,vars.time.value)) < 0
          }
          else {
            var match = true
          }
          if (match) {
            return fetchValue(vars,d,total_key)
          }
        })

        if (overall_total > total) {

          var pct = (total/overall_total)*100,
              ot = vars.format.value(overall_total,vars.size.value, vars)

          var pct = " ("+vars.format.value(pct,"share")+"% of "+ot+", vars)"

        }
      }

      total = vars.format.value(total,vars.size.value, vars)
      var obj = vars.title.total.value
        , prefix = obj.prefix || vars.format.value(vars.format.locale.value.ui.total)+": "
      total = prefix + total
      obj.suffix ? total = total + obj.suffix : null
      total += pct

    }

    if ( vars.dev.value ) {
      print.timeEnd("calculating total value")
    }

  }
  else {
    var total = false
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Initialize titles and detect footer
  //----------------------------------------------------------------------------
  var title_data = []

  if (vars.footer.value) {
    title_data.push({
      "link": vars.footer.link,
      "style": vars.footer,
      "type": "footer",
      "value": vars.footer.value
    })
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // If not in "small" mode, detect titles available
  //----------------------------------------------------------------------------
  if (!vars.small) {

    if (vars.title.value) {
      title_data.push({
        "link": vars.title.link,
        "style": vars.title,
        "type": "title",
        "value": vars.title.value
      })
    }
    if (vars.title.sub.value) {
      title_data.push({
        "link": vars.title.sub.link,
        "style": vars.title.sub,
        "type": "sub",
        "value": vars.title.sub.value
      })
    }
    if (vars.title.total.value && total) {
      title_data.push({
        "link": vars.title.total.link,
        "style": vars.title.total,
        "type": "total",
        "value": total
      })
    }

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Enter Titles
  //----------------------------------------------------------------------------
  function style(title) {

    title
      .attr("font-size",function(t){
        return t.style.font.size
      })
      .attr("fill",function(t){
        return t.link ? vars.links.font.color : t.style.font.color
      })
      .attr("font-family",function(t){
        return t.link ? vars.links.font.family.value : t.style.font.family.value
      })
      .attr("font-weight",function(t){
        return t.link ? vars.links.font.weight : t.style.font.weight
      })
      .style("text-decoration",function(t){
        return t.link ? vars.links.font.decoration.value : t.style.font.decoration.value
      })
      .style("text-transform",function(t){
        return t.link ? vars.links.font.transform.value : t.style.font.transform.value
      })

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Enter Titles
  //----------------------------------------------------------------------------
  if ( vars.dev.value ) print.time("drawing titles")
  var titles = vars.svg.selectAll("g.d3plus_title")
    .data(title_data,function(t){
      return t.type
    })

  var titleWidth = vars.title.width || vars.width.value

  titles.enter().append("g")
    .attr("class","d3plus_title")
    .attr("opacity",0)
    .attr("transform",function(t){
      var y = t.style.position == "top" ? 0 : vars.height.value
      return "translate(0,"+y+")"
    })
    .append("text")
      .call(style)

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Wrap text and calculate positions, then transition style and opacity
  //----------------------------------------------------------------------------
  titles
    .each(function(d){

      var container = d3.select(this).select("text").call(style);

      var align = d.style.font.align

      if (align == "center") {
        align = "middle"
      }
      else if ((align == "left" && !rtl) || (align == "right" && rtl)) {
        align = "start"
      }
      else if ((align == "left" && rtl) || (align == "right" && !rtl)) {
        align = "end"
      }

      textWrap()
        .align(align)
        .container(container)
        .height(vars.height.value / 8)
        .size(false)
        .text(d.value)
        .width(titleWidth)
        .draw()

      d.y = vars.margin[d.style.position]
      vars.margin[d.style.position] += this.getBBox().height + d.style.padding*2

    })
    .on(events.over,function(t){
      if (t.link) {
        d3.select(this)
          .transition().duration(vars.timing.mouseevents)
          .style("cursor","pointer")
          .select("text")
            .attr("fill",vars.links.hover.color)
            .attr("font-family",vars.links.hover.family.value)
            .attr("font-weight",vars.links.hover.weight)
            .style("text-decoration",vars.links.hover.decoration.value)
            .style("text-transform",vars.links.hover.transform.value)
      }
    })
    .on(events.out,function(t){
      if (t.link) {
        d3.select(this)
          .transition().duration(vars.timing.mouseevents)
          .style("cursor","auto")
          .select("text")
            .call(style)
      }
    })
    .on(events.click,function(t){
      if (t.link) {
        var target = t.link.charAt(0) != "/" ? "_blank" : "_self"
        window.open(t.link,target)
      }
    })
    .transition().duration(vars.draw.timing)
      .attr("opacity",1)
      .attr("transform",function(t){
        var pos = t.style.position,
            y = pos == "top" ? 0+t.y : vars.height.value-t.y
        if (pos == "bottom") {
          y -= this.getBBox().height+t.style.padding
        }
        else {
          y += t.style.padding
        }
        return "translate(0,"+y+")"
      })

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Exit unused titles
  //----------------------------------------------------------------------------
  titles.exit().transition().duration(vars.draw.timing)
    .attr("opacity",0)
    .remove()

  if ( vars.margin.top > 0 ) {
    vars.margin.top += vars.title.padding
  }

  if ( vars.margin.bottom > 0 ) {
    vars.margin.bottom += vars.title.padding
  }

  var min = vars.title.height
  if (min && vars.margin[vars.title.position] < min) {
    vars.margin[vars.title.position] = min
  }

  if ( vars.dev.value ) print.timeEnd("drawing titles")

}
<|endoftext|>


<commit_before>var Overprint = {
	Char: {
		NULL: ' ',
		SPACE: ' '
	},
	Color: {
		BLACK: '#000',
		WHITE: '#fff'
	}
};

Overprint.Char.AMPERSAND = '&';
Overprint.Char.DOT = '.';
Overprint.Char.FULL_STOP = '.';
Overprint.Char.PLUS = '+';
Overprint.Char.MINUS = '-';
Overprint.Char.HASH = '#';
Overprint.Char.DOLLAR = '$';
Overprint.Char.PERCENT = '%';
Overprint.Char.CARET = '^';
Overprint.Char.ASTERISK = '*';
Overprint.Char.TILDE = '~';
Overprint.Char.LEFT_PARENS = '(';
Overprint.Char.RIGHT_PARENS = ')';
Overprint.Char.LEFT_BRACKET = '[';
Overprint.Char.RIGHT_BRACKET = ']';
Overprint.Char.AT = '@';

Overprint.Glyph = function(character, color, bgColor) {
	return {
		char: character || Overprint.Char.NULL,
		color: color || Overprint.Color.WHITE,
		bgColor: bgColor || Overprint.Color.BLACK
	}
}

Overprint.Font = function(family, weight, size) {
	return {
		family: family || 'monospace',
		weight: weight || 'normal',
		size: size || 16,
		toCSS: function() {
			return this.weight + ' '+ this.size +'px ' + this.family;
		}
	}
}

Overprint.Terminal = function(width, height, canvas, font, isResponsive, forceSquare) {
	this._width = width;
	this._height = height;
	this._canvas = canvas;
	this._font = font || Overprint.Font();
	this._responsive = isResponsive ? true : false;
	this._squared = forceSquare ? true : false;

	this._context = this._canvas.getContext('2d');

	this._ratio = window.devicePixelRatio || 1;

	this._context.font = this._font.toCSS();

	this.resetLayout();

	var cell = this._emptyCell = Overprint.Glyph();
	this._display = new Overprint.DisplayState(width, height, cell);
}

Overprint.Terminal.prototype.resetLayout = function() {
	if (this._responsive) {
		// Calculates the dimensions of the containing element first
		if (!this._canvas.style.width) this._canvas.style.width = 640;
		if (!this._canvas.style.height) this._canvas.style.height = 480;

		var elementWidth = parseInt(this._canvas.style.width, 10)  * this._ratio;
		var elementHeight = parseInt(this._canvas.style.height, 10) * this._ratio;

		// Calculates cell width and height based on the containing element
		this._cellWidth = Math.floor(elementWidth / this._width);
		this._cellHeight = Math.floor(elementHeight / this._height);

		this._canvas.width = elementWidth;
		this._canvas.height = elementHeight;

	} else {
		// Measure text width from canvas context
		var textMeasure = this._context.measureText("M");

		// Canvas measure text with direct multiple of font size
		var textWidth = Math.ceil(textMeasure.width);
		var textHeight = this._font.size;

		// Force square aspect ratio
		if (this._squared) {
			textWidth = textHeight = Math.max(textWidth, textHeight);
		}

		var glyphWidth = textWidth;
		var glyphHeight = textHeight;

		this._cellWidth = glyphWidth * this._ratio;
		this._cellHeight = glyphHeight * this._ratio;

		var drawWidth = glyphWidth * this._width;
		var drawHeight = glyphHeight * this._height;

		this._canvas.width = drawWidth * this._ratio;
		this._canvas.height = drawHeight * this._ratio;

		this._canvas.style.width = drawWidth;
		this._canvas.style.height = drawHeight;
	}

	this._font.size = this._font.size * this._ratio;
	this._context.font = this._font.toCSS();
	this._context.textAlign = 'center';
	this._context.textBaseline = 'middle';
}

Overprint.Terminal.prototype.clear = function(glyph) {
	var bgGlyph = glyph ? glyph : this._emptyCell;
	for (var col=0; col<this._width; col++) {
		for (var row=0; row<this._height; row++) {
			this._display.setCell(col, row, bgGlyph);
		}
	}
}

Overprint.Terminal.prototype.fill = function(glyph) {
	this.clear(glyph);
}

Overprint.Terminal.prototype.writeGlyph = function(x, y, glyph) {
	this._display.setCell(x, y, glyph);
}

Overprint.Terminal.prototype.writeText = function(x, y, text) {
	var cursorPosition = 0;
	var endPosition = this._width - x;

	while (cursorPosition <= endPosition) {
		var textGlyph = Overprint.Glyph(text[cursorPosition]);
		this._display.setCell(cursorPosition + x, y, textGlyph);
		cursorPosition++;
	}
}

Overprint.Terminal.prototype.render = function() {
	this._display.render(function(x, y, glyph){
		var cellWidth = this._cellWidth;
		var cellHeight = this._cellHeight;

		this._context.fillStyle = glyph.bgColor;
		this._context.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);

		if (glyph.char == Overprint.Char.NULL) return;

		this._context.fillStyle = glyph.color;

		var xPos = (x * cellWidth) + cellWidth / 2;
		var yPos = (y * cellHeight) + cellHeight / 2;
		this._context.fillText(glyph.char, xPos, yPos);
	}.bind(this));
}

Overprint.Hexgrid = function(width, height, canvas) {
	this._width = width;
	this._height = height;
	this._canvas = canvas;

	this._context = this._canvas.getContext('2d');

	this._ratio = window.devicePixelRatio || 1;

	this.resetLayout();

	var cell = this._emptyCell = Overprint.Glyph();
	this._display = new Overprint.DisplayState(width, height, cell);
}

Overprint.Hexgrid.prototype.resetLayout = function() {
	if (!this._canvas.style.width) this._canvas.style.width = 640;
	if (!this._canvas.style.height) this._canvas.style.height = 480;

	var elementWidth = parseInt(this._canvas.style.width, 10) * this._ratio;
	var elementHeight = parseInt(this._canvas.style.height, 10) * this._ratio;

	this._canvas.width = elementWidth;
	this._canvas.height = elementHeight;

	// TODO: support a hex grid coordinate system
	//this._cellWidth = elementWidth / this._width / 2;
	//this._cellHeight = elementHeight / this._height / 2;
	this._cellWidth = 16;
	this._cellHeight = 16;
}

Overprint.Hexgrid.prototype.writeCell = function(x, y, glyph) {
	this._display.setCell(x, y, glyph);
}

Overprint.Hexgrid.prototype.render = function() {
	this._display.render(function(x, y, glyph){
		var cellWidth = this._cellWidth;
		var cellHeight = this._cellHeight;

		var sideLength = (cellWidth > cellHeight) ? cellWidth : cellHeight;

		var widthRadius = sideLength * Math.cos(60 * Math.PI / 180) + sideLength * 0.5;
		var heightRadius = sideLength * Math.sin(60 * Math.PI / 180);
		var halfSize = sideLength * 0.5;

		// See: http://stackoverflow.com/questions/195262/can-i-turn-off-antialiasing-on-an-html-canvas-element

		//this._context.save();
		this._context.fillStyle = glyph.bgColor;

		this._context.imageSmoothingEnabled = true;

		//this._context.lineJoin = 'round';

		this._context.beginPath();

		centerX = x * (sideLength * 0.5 + widthRadius) + widthRadius;
		centerY = y * heightRadius * 2 + heightRadius * (x % 2 ? 2 : 1);

		this._context.moveTo(centerX - halfSize, centerY - heightRadius);
		this._context.lineTo(centerX + halfSize, centerY - heightRadius);
		this._context.lineTo(centerX + widthRadius, centerY);
		this._context.lineTo(centerX + halfSize, centerY + heightRadius);
		this._context.lineTo(centerX - halfSize, centerY + heightRadius);
		this._context.lineTo(centerX - widthRadius, centerY);
		this._context.lineTo(centerX - halfSize, centerY - heightRadius);
		this._context.fill();

		this._context.strokeStyle = '#fff';
		this._context.strokeSize = 0.1;
		this._context.stroke();

		this._context.closePath();
		//this._context.restore();

	}.bind(this));
}

Overprint.Hexgrid.prototype.clear = function(glyph) {
	var bgGlyph = glyph ? glyph : Overprint.Glyph();
	for (var col=0; col<this._width; col++) {
		for (var row=0; row<this._height; row++) {
			this._display.setCell(col, row, bgGlyph);
		}
	}
}

Overprint.Trigrid = function(width, height, canvas) {
	this._width = width;
	this._height = height;
	this._canvas = canvas;

	this._context = this._canvas.getContext('2d');

	this.resetLayout();

	var cell = this._emptyCell = Overprint.Glyph();
	this._display = new Overprint.DisplayState(width, height, cell);
}

Overprint.Trigrid.prototype.resetLayout = function() {
	if (!this._canvas.style.width) this._canvas.style.width = 640;
	if (!this._canvas.style.height) this._canvas.style.height = 480;

	var elementWidth = parseInt(this._canvas.style.width, 10);
	var elementHeight = parseInt(this._canvas.style.height, 10);

	this._canvas.width = elementWidth;
	this._canvas.height = elementHeight;

	this._cellWidth = elementWidth / this._width;
	this._cellHeight = elementHeight / this._height;
}

// TODO: +api work out the best value obj structure to pass here instead of glyph
Overprint.Trigrid.prototype.writeCell = function(x, y, glyph) {
	this._display.setCell(x, y, glyph);
}

Overprint.Trigrid.prototype.render = function() {
	this._display.render(function(x, y, glyph){
		var cellWidth = this._cellWidth;
		var cellHeight = this._cellHeight;

		var sideLength = (cellWidth > cellHeight) ? cellWidth : cellHeight;

		var widthRadius = sideLength * Math.cos(60 * Math.PI / 180) + sideLength * 0.5;
		var heightRadius = sideLength * Math.sin(60 * Math.PI / 180);
		var halfSize = sideLength * 0.5;

		// See: http://stackoverflow.com/questions/195262/can-i-turn-off-antialiasing-on-an-html-canvas-element
		this._context.fillStyle = glyph.bgColor;

		this._context.imageSmoothingEnabled = true;

		this._context.beginPath();

		var verticalOrientationUp = (y % 2 === 0) ? true : false

		// Calculate the tip vertex based on the row orientation
		var tipX = x * sideLength + (verticalOrientationUp ? halfSize : 0);
		var tipY = y * sideLength;

		// Draw a triangle with an up or down orientation
		// TODO: introduce a specialised coordinate system for this type of grid
		if (verticalOrientationUp) {
			this._context.moveTo(tipX, tipY);
			this._context.lineTo(tipX + halfSize, tipY + sideLength);
			this._context.lineTo(tipX - halfSize, tipY + sideLength);
		} else {
			this._context.moveTo(tipX, tipY);
			this._context.lineTo(tipX + sideLength, tipY);
			this._context.lineTo(tipX + halfSize, tipY + sideLength);
		}

		this._context.fill();

		this._context.strokeStyle = '#fff';
		this._context.strokeSize = 0.1;
		this._context.stroke();

		this._context.closePath();
		//this._context.restore();
	}.bind(this));
}

Overprint.DisplayState = function(width, height, cell) {
	function fillArray2D(width, height, fill) {
		var list = new Array(width);
		for (var col=0; col<width; col++) {
			list[col] = new Array(height);
			for (var row=0; row<height; row++) {
				list[col][row] = fill;
			}
		}
		return list;
	}

	this._width = width;
	this._height = height;
	this._emptyCell = cell;

	this._renderedCells = fillArray2D(width, height, cell);
	this._updatedCells = fillArray2D(width, height, cell);
}

Overprint.DisplayState.prototype.setCell = function(x, y, cell) {
	if (x < 0) return;
	if (x >= this._width) return;
	if (y < 0) return;
	if (y >= this._height) return;

	if (!cell) cell = this._emptyCell;

	if (this._renderedCells[x][y] !== cell) {
		this._updatedCells[x][y] = cell;
	} else {
		this._updatedCells[x][y] = null;
	}
}

Overprint.DisplayState.prototype.render = function(callback) {
	for (var col=0; col<this._width; col++) {
		for (var row=0; row<this._height; row++) {
			var cell = this._updatedCells[col][row];

			if (cell == null) continue;

			callback(col, row, cell);

			this._renderedCells[col][row] = cell;
			this._updatedCells[col][row] = null;
		}
	}
}
<commit_msg>Add dirty flag to display state<commit_after>var Overprint = {
	Char: {
		NULL: ' ',
		SPACE: ' '
	},
	Color: {
		BLACK: '#000',
		WHITE: '#fff'
	}
};

Overprint.Char.AMPERSAND = '&';
Overprint.Char.DOT = '.';
Overprint.Char.FULL_STOP = '.';
Overprint.Char.PLUS = '+';
Overprint.Char.MINUS = '-';
Overprint.Char.HASH = '#';
Overprint.Char.DOLLAR = '$';
Overprint.Char.PERCENT = '%';
Overprint.Char.CARET = '^';
Overprint.Char.ASTERISK = '*';
Overprint.Char.TILDE = '~';
Overprint.Char.LEFT_PARENS = '(';
Overprint.Char.RIGHT_PARENS = ')';
Overprint.Char.LEFT_BRACKET = '[';
Overprint.Char.RIGHT_BRACKET = ']';
Overprint.Char.AT = '@';

Overprint.Glyph = function(character, color, bgColor) {
	return {
		char: character || Overprint.Char.NULL,
		color: color || Overprint.Color.WHITE,
		bgColor: bgColor || Overprint.Color.BLACK
	}
}

Overprint.Font = function(family, weight, size) {
	return {
		family: family || 'monospace',
		weight: weight || 'normal',
		size: size || 16,
		toCSS: function() {
			return this.weight + ' '+ this.size +'px ' + this.family;
		}
	}
}

Overprint.Terminal = function(width, height, canvas, font, isResponsive, forceSquare) {
	this._width = width;
	this._height = height;
	this._canvas = canvas;
	this._font = font || Overprint.Font();
	this._responsive = isResponsive ? true : false;
	this._squared = forceSquare ? true : false;

	this._context = this._canvas.getContext('2d');

	this._ratio = window.devicePixelRatio || 1;

	this._context.font = this._font.toCSS();

	this.resetLayout();

	var cell = this._emptyCell = Overprint.Glyph();
	this._display = new Overprint.DisplayState(width, height, cell);
}

Overprint.Terminal.prototype.resetLayout = function() {
	if (this._responsive) {
		// Calculates the dimensions of the containing element first
		if (!this._canvas.style.width) this._canvas.style.width = 640;
		if (!this._canvas.style.height) this._canvas.style.height = 480;

		var elementWidth = parseInt(this._canvas.style.width, 10)  * this._ratio;
		var elementHeight = parseInt(this._canvas.style.height, 10) * this._ratio;

		// Calculates cell width and height based on the containing element
		this._cellWidth = Math.floor(elementWidth / this._width);
		this._cellHeight = Math.floor(elementHeight / this._height);

		this._canvas.width = elementWidth;
		this._canvas.height = elementHeight;

	} else {
		// Measure text width from canvas context
		var textMeasure = this._context.measureText("M");

		// Canvas measure text with direct multiple of font size
		var textWidth = Math.ceil(textMeasure.width);
		var textHeight = this._font.size;

		// Force square aspect ratio
		if (this._squared) {
			textWidth = textHeight = Math.max(textWidth, textHeight);
		}

		var glyphWidth = textWidth;
		var glyphHeight = textHeight;

		this._cellWidth = glyphWidth * this._ratio;
		this._cellHeight = glyphHeight * this._ratio;

		var drawWidth = glyphWidth * this._width;
		var drawHeight = glyphHeight * this._height;

		this._canvas.width = drawWidth * this._ratio;
		this._canvas.height = drawHeight * this._ratio;

		this._canvas.style.width = drawWidth;
		this._canvas.style.height = drawHeight;
	}

	this._font.size = this._font.size * this._ratio;
	this._context.font = this._font.toCSS();
	this._context.textAlign = 'center';
	this._context.textBaseline = 'middle';
}

Overprint.Terminal.prototype.clear = function(glyph) {
	var bgGlyph = glyph ? glyph : this._emptyCell;
	for (var col=0; col<this._width; col++) {
		for (var row=0; row<this._height; row++) {
			this._display.setCell(col, row, bgGlyph);
		}
	}
}

Overprint.Terminal.prototype.fill = function(glyph) {
	this.clear(glyph);
}

Overprint.Terminal.prototype.writeGlyph = function(x, y, glyph) {
	this._display.setCell(x, y, glyph);
}

Overprint.Terminal.prototype.writeText = function(x, y, text) {
	var cursorPosition = 0;
	var endPosition = this._width - x;

	while (cursorPosition <= endPosition) {
		var textGlyph = Overprint.Glyph(text[cursorPosition]);
		this._display.setCell(cursorPosition + x, y, textGlyph);
		cursorPosition++;
	}
}

Overprint.Terminal.prototype.render = function() {
	this._display.render(function(x, y, glyph){
		var cellWidth = this._cellWidth;
		var cellHeight = this._cellHeight;

		this._context.fillStyle = glyph.bgColor;
		this._context.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);

		if (glyph.char == Overprint.Char.NULL) return;

		this._context.fillStyle = glyph.color;

		var xPos = (x * cellWidth) + cellWidth / 2;
		var yPos = (y * cellHeight) + cellHeight / 2;
		this._context.fillText(glyph.char, xPos, yPos);
	}.bind(this));
}

Overprint.Hexgrid = function(width, height, canvas) {
	this._width = width;
	this._height = height;
	this._canvas = canvas;

	this._context = this._canvas.getContext('2d');

	this._ratio = window.devicePixelRatio || 1;

	this.resetLayout();

	var cell = this._emptyCell = Overprint.Glyph();
	this._display = new Overprint.DisplayState(width, height, cell);
}

Overprint.Hexgrid.prototype.resetLayout = function() {
	if (!this._canvas.style.width) this._canvas.style.width = 640;
	if (!this._canvas.style.height) this._canvas.style.height = 480;

	var elementWidth = parseInt(this._canvas.style.width, 10) * this._ratio;
	var elementHeight = parseInt(this._canvas.style.height, 10) * this._ratio;

	this._canvas.width = elementWidth;
	this._canvas.height = elementHeight;

	// TODO: support a hex grid coordinate system
	//this._cellWidth = elementWidth / this._width / 2;
	//this._cellHeight = elementHeight / this._height / 2;
	this._cellWidth = 16;
	this._cellHeight = 16;
}

Overprint.Hexgrid.prototype.writeCell = function(x, y, glyph) {
	this._display.setCell(x, y, glyph);
}

Overprint.Hexgrid.prototype.render = function() {
	this._display.render(function(x, y, glyph){
		var cellWidth = this._cellWidth;
		var cellHeight = this._cellHeight;

		var sideLength = (cellWidth > cellHeight) ? cellWidth : cellHeight;

		var widthRadius = sideLength * Math.cos(60 * Math.PI / 180) + sideLength * 0.5;
		var heightRadius = sideLength * Math.sin(60 * Math.PI / 180);
		var halfSize = sideLength * 0.5;

		// See: http://stackoverflow.com/questions/195262/can-i-turn-off-antialiasing-on-an-html-canvas-element

		//this._context.save();
		this._context.fillStyle = glyph.bgColor;

		this._context.imageSmoothingEnabled = true;

		//this._context.lineJoin = 'round';

		this._context.beginPath();

		centerX = x * (sideLength * 0.5 + widthRadius) + widthRadius;
		centerY = y * heightRadius * 2 + heightRadius * (x % 2 ? 2 : 1);

		this._context.moveTo(centerX - halfSize, centerY - heightRadius);
		this._context.lineTo(centerX + halfSize, centerY - heightRadius);
		this._context.lineTo(centerX + widthRadius, centerY);
		this._context.lineTo(centerX + halfSize, centerY + heightRadius);
		this._context.lineTo(centerX - halfSize, centerY + heightRadius);
		this._context.lineTo(centerX - widthRadius, centerY);
		this._context.lineTo(centerX - halfSize, centerY - heightRadius);
		this._context.fill();

		this._context.strokeStyle = '#fff';
		this._context.strokeSize = 0.1;
		this._context.stroke();

		this._context.closePath();
		//this._context.restore();

	}.bind(this));
}

Overprint.Hexgrid.prototype.clear = function(glyph) {
	var bgGlyph = glyph ? glyph : Overprint.Glyph();
	for (var col=0; col<this._width; col++) {
		for (var row=0; row<this._height; row++) {
			this._display.setCell(col, row, bgGlyph);
		}
	}
}

Overprint.Trigrid = function(width, height, canvas) {
	this._width = width;
	this._height = height;
	this._canvas = canvas;

	this._context = this._canvas.getContext('2d');

	this.resetLayout();

	var cell = this._emptyCell = Overprint.Glyph();
	this._display = new Overprint.DisplayState(width, height, cell);
}

Overprint.Trigrid.prototype.resetLayout = function() {
	if (!this._canvas.style.width) this._canvas.style.width = 640;
	if (!this._canvas.style.height) this._canvas.style.height = 480;

	var elementWidth = parseInt(this._canvas.style.width, 10);
	var elementHeight = parseInt(this._canvas.style.height, 10);

	this._canvas.width = elementWidth;
	this._canvas.height = elementHeight;

	this._cellWidth = elementWidth / this._width;
	this._cellHeight = elementHeight / this._height;
}

// TODO: +api work out the best value obj structure to pass here instead of glyph
Overprint.Trigrid.prototype.writeCell = function(x, y, glyph) {
	this._display.setCell(x, y, glyph);
}

Overprint.Trigrid.prototype.render = function() {
	this._display.render(function(x, y, glyph){
		var cellWidth = this._cellWidth;
		var cellHeight = this._cellHeight;

		var sideLength = (cellWidth > cellHeight) ? cellWidth : cellHeight;

		var widthRadius = sideLength * Math.cos(60 * Math.PI / 180) + sideLength * 0.5;
		var heightRadius = sideLength * Math.sin(60 * Math.PI / 180);
		var halfSize = sideLength * 0.5;

		// See: http://stackoverflow.com/questions/195262/can-i-turn-off-antialiasing-on-an-html-canvas-element
		this._context.fillStyle = glyph.bgColor;

		this._context.imageSmoothingEnabled = true;

		this._context.beginPath();

		var verticalOrientationUp = (y % 2 === 0) ? true : false

		// Calculate the tip vertex based on the row orientation
		var tipX = x * sideLength + (verticalOrientationUp ? halfSize : 0);
		var tipY = y * sideLength;

		// Draw a triangle with an up or down orientation
		// TODO: introduce a specialised coordinate system for this type of grid
		if (verticalOrientationUp) {
			this._context.moveTo(tipX, tipY);
			this._context.lineTo(tipX + halfSize, tipY + sideLength);
			this._context.lineTo(tipX - halfSize, tipY + sideLength);
		} else {
			this._context.moveTo(tipX, tipY);
			this._context.lineTo(tipX + sideLength, tipY);
			this._context.lineTo(tipX + halfSize, tipY + sideLength);
		}

		this._context.fill();

		this._context.strokeStyle = '#fff';
		this._context.strokeSize = 0.1;
		this._context.stroke();

		this._context.closePath();
		//this._context.restore();
	}.bind(this));
}

Overprint.DisplayState = function(width, height, cell) {
	function fillArray2D(width, height, fill) {
		var list = new Array(width);
		for (var col=0; col<width; col++) {
			list[col] = new Array(height);
			for (var row=0; row<height; row++) {
				list[col][row] = fill;
			}
		}
		return list;
	}

	this._width = width;
	this._height = height;
	this._emptyCell = cell;

	this._renderedCells = fillArray2D(width, height, cell);
	this._updatedCells = fillArray2D(width, height, cell);

	this._dirty = true;
}

Overprint.DisplayState.prototype.setCell = function(x, y, cell) {
	if (x < 0) return;
	if (x >= this._width) return;
	if (y < 0) return;
	if (y >= this._height) return;

	if (!cell) cell = this._emptyCell;

	if (this._renderedCells[x][y] !== cell) {
		this._updatedCells[x][y] = cell;
		this._dirty = true;
	} else {
		this._updatedCells[x][y] = null;
	}
}

Overprint.DisplayState.prototype.render = function(callback) {
	if (!this._dirty) return;

	for (var col=0; col<this._width; col++) {
		for (var row=0; row<this._height; row++) {
			var cell = this._updatedCells[col][row];

			if (cell == null) continue;

			callback(col, row, cell);

			this._renderedCells[col][row] = cell;
			this._updatedCells[col][row] = null;
		}
	}
}
<|endoftext|>


<commit_before>// @flow

import React from 'react'
import { Link } from 'react-router'

import styles from './entries.css'
import panelStyles from '../../../styles/panel.css'
import { parseEntriesByDirLevel } from '../../../utils'

import type { TreeEntry } from '../../../../types/nodegit'

export default function Entries({
  entries,
  params
}: {
  entries: Array<TreeEntry>,
  params: {
    owner: string,
    repo: string,
    tree: string,
    splat: string
  }
}) {
  /* static propTypes = {
   *   entries: PropTypes.arrayOf(
   *     PropTypes.shape({
   *       lastCommit: PropTypes.shape({
   *         author: PropTypes.shape({
   *           date: PropTypes.string.isRequired
   *         }).isRequired,
   *         message: PropTypes.string.isRequired,
   *         sha: PropTypes.string.isRequired
   *       }).isRequired,
   *       path: PropTypes.string.isRequired
   *     })
   *   ).isRequired,
   *   params: PropTypes.shape({
   *     owner: PropTypes.string.isRequired,
   *     repo: PropTypes.string.isRequired,
   *     tree: PropTypes.string,
   *     splat: PropTypes.string
   *   }).isRequired
   * }
   */
  const { owner, repo, tree = 'master', splat = '' } = params
  if (entries.length === 0) return
No entries.

  const path = splat.replace(/^\//, '')
  const filteredEntries = parseEntriesByDirLevel(entries, path)
  const latestCommit = filteredEntries.reduce(
    (acc, e) =>
      e.lastCommit.author.date > acc.lastCommit.author.date ? e : acc
  ).lastCommit
  return (

          <a href={`/${latestCommit.author.name}`}>
            {latestCommit.author.name}

          <Link to={`/${owner}/${repo}/commit/${latestCommit.sha}`}>
            {latestCommit.message}
          </Link>

          Latest commit
          <Link
            className={styles.sha}
            to={`/${owner}/${repo}/commit/${latestCommit.sha}`}
          >
            {latestCommit.sha.substr(0, 7)}
          </Link>
          <time-ago datetime={latestCommit.author.date} />

            {filteredEntries.map(entry => (

                  <Link
                    to={`/${[owner, repo, entry.type, tree, path, entry.path]
                      .filter(Boolean)
                      .join('/')}`}
                  >
                    {entry.path}
                  </Link>

                  <Link to={`/${owner}/${repo}/commit/${entry.lastCommit.sha}`}>
                    {entry.lastCommit.message}
                  </Link>

                  <time-ago datetime={entry.lastCommit.author.date} />

            ))}

  )
}
<commit_msg>Remove unused comment<commit_after>// @flow

import React from 'react'
import { Link } from 'react-router'

import styles from './entries.css'
import panelStyles from '../../../styles/panel.css'
import { parseEntriesByDirLevel } from '../../../utils'

import type { TreeEntry } from '../../../../types/nodegit'

export default function Entries({
  entries,
  params
}: {
  entries: Array<TreeEntry>,
  params: {
    owner: string,
    repo: string,
    tree: string,
    splat: string
  }
}) {
  const { owner, repo, tree = 'master', splat = '' } = params
  if (entries.length === 0) return
No entries.

  const path = splat.replace(/^\//, '')
  const filteredEntries = parseEntriesByDirLevel(entries, path)
  const latestCommit = filteredEntries.reduce(
    (acc, e) =>
      e.lastCommit.author.date > acc.lastCommit.author.date ? e : acc
  ).lastCommit
  return (

          <a href={`/${latestCommit.author.name}`}>
            {latestCommit.author.name}

          <Link to={`/${owner}/${repo}/commit/${latestCommit.sha}`}>
            {latestCommit.message}
          </Link>

          Latest commit
          <Link
            className={styles.sha}
            to={`/${owner}/${repo}/commit/${latestCommit.sha}`}
          >
            {latestCommit.sha.substr(0, 7)}
          </Link>
          <time-ago datetime={latestCommit.author.date} />

            {filteredEntries.map(entry => (

                  <Link
                    to={`/${[owner, repo, entry.type, tree, path, entry.path]
                      .filter(Boolean)
                      .join('/')}`}
                  >
                    {entry.path}
                  </Link>

                  <Link to={`/${owner}/${repo}/commit/${entry.lastCommit.sha}`}>
                    {entry.lastCommit.message}
                  </Link>

                  <time-ago datetime={entry.lastCommit.author.date} />

            ))}

  )
}
<|endoftext|>


<commit_before>require('../support');

describe('OPTION /collection-schemas/:id', function() {
    xit('pending', function() {

    });
});
<commit_msg>Acceptance test for CORS headers on OPTIONS request to /collection-schemas/:id.<commit_after>require('../support');

var expect = require('chai').expect;
var loopback = require('loopback');
var request = require('supertest');

var loopbackJsonSchema = require('../../index');

var app = loopback();
app.set('restApiRoot', '/api');
app.installMiddleware();

describe('OPTION /collection-schemas/:id', function() {
    var response;

    before(function(done) {
        request(app)
            .options('/api/collection-schemas/1')
            .set('Access-Control-Request-Headers', 'Content-Type')
            .expect(204)
            .end(function (err, res) {
                if (err) { throw err };
                response = res;
                done();
        });
    });

    it('should include CORS headers', function() {
        expect(response.headers['access-control-allow-origin']).to.eq('*');
        expect(response.headers['access-control-allow-methods']).to.eq('GET,HEAD,PUT,PATCH,POST,DELETE');
        expect(response.headers['access-control-allow-headers']).to.eq('Content-Type');
    });
});
<|endoftext|>


<commit_before>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure

//Declare and Initialize Variables
var AudioAlertsStatus = 0;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume=1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume=1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var NinjaAutoClickStatus = 0;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
                $("#beach").css("border","4px solid white");
                KeepBlue = 1;
            }
            else {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
        $("#beach").css("border","4px solid yellow");
            if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
                audio_Chime.play();
                incoming_ONG = 1;
            }
    }
    else {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	if (Molpy.redactedVisible > 0) {
		//Clicks if AutoClicker Enabled
		if (RKAutoClickStatus == 1) {
			Molpy.ClickRedacted();
		}

		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0};
			status = RKAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0};
			status = NinjaAutoClickStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0};
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	if (option == 'RKAutoClick' || option == 'NinjaAutoClick') {
		switch (status) {
			case '1':
				description = 'On';
				break;
			case '0':
				description = 'Off';
				break;
			default:
				Molpy.Notify('Display Description Error',1);
		}
	}
	if (option == 'AudioAlerts') {
		Molpy.Notify(isNaN(status),1);
		switch (status) {
			case '0':
				description = 'Off';
				break;
			case '1':
				description = 'RK Only';
				break;
			case '2':
				description = 'ONG Only';
				break;
			case '3':
				description = 'RK and ONG';
				break;
			default:
				Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);
		}
	}
	g(option + 'Desc').innerHTML = '
' + description;
}

//Beach Ball Startup
//Set Settings
IdleStatus = prompt("Set to idle? (1 = Yes, 0 = No)");
RKAutoClickStatus = IdleStatus;
NinjaAutoClickStatus = IdleStatus;
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

RK Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Audio Alerts

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

//Main Loop
setInterval(function() {
	Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
    RedundaKitty();
    Ninja();
}, 1800);
<commit_msg>Audio Alerts Bug Fixing<commit_after>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure

//Declare and Initialize Variables
var AudioAlertsStatus = 0;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume=1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume=1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var NinjaAutoClickStatus = 0;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
                $("#beach").css("border","4px solid white");
                KeepBlue = 1;
            }
            else {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
        $("#beach").css("border","4px solid yellow");
            if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
                audio_Chime.play();
                incoming_ONG = 1;
            }
    }
    else {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	if (Molpy.redactedVisible > 0) {
		//Clicks if AutoClicker Enabled
		if (RKAutoClickStatus == 1) {
			Molpy.ClickRedacted();
		}

		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0};
			status = RKAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0};
			status = NinjaAutoClickStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0};
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	if (option == 'RKAutoClick' || option == 'NinjaAutoClick') {
		switch (status) {
			case 0:
				description = 'Off';
				break;
			case 1:
				description = 'On';
				break;
			default:
				Molpy.Notify('Display Description Error',1);
		}
	}
	if (option == 'AudioAlerts') {
		//Molpy.Notify(isNaN(status),1);
		switch (status) {
			case 0:
				description = 'Off';
				break;
			case 1:
				description = 'RK Only';
				break;
			case 2:
				description = 'ONG Only';
				break;
			case 3:
				description = 'RK and ONG';
				break;
			default:
				Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);
		}
	}
	g(option + 'Desc').innerHTML = '
' + description;
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

RK Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Audio Alerts

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

//Main Loop
setInterval(function() {
	Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
    RedundaKitty();
    Ninja();
}, 1800);
<|endoftext|>


<commit_before>var GitHubApi = require("github").GitHubApi
  , request = require('request')
  , github = new GitHubApi()
  , async = require('async')
  , nfs = require('node-fs')
  , fs = require('fs')
  , lockerUrl
  , auth
  , viewers = []
  ;

exports.sync = function(processInfo, cb) {
    auth = processInfo.auth;
    auth.headers = {"Authorization":"token "+auth.accessToken, "Connection":"keep-alive"};
    var cached = {};
    if (processInfo.config && processInfo.config.cached)
        cached = processInfo.config.cached;
    lockerUrl = processInfo.lockerUrl;
    exports.syncRepos(cached, function(err, repos) {
        if (err) console.error(err);
        var responseObj = {data : {}, config: { cached: cached }};
        responseObj.data.repo = repos;
        responseObj.data.view = viewers;
        // logger.debug(viewers);
        cb(err, responseObj);
    });
};

exports.syncRepos = function(cached, callback) {
    github.getRepoApi().getUserRepos(auth.username, function(err, repos) {
        if(err || !repos || !repos.length) return callback(err, []);
        // process each one to get richer data
        async.forEach(repos, function(repo, cb) {
            repo.id = getIDFromUrl(repo.url);
            // nothing changed
            var ckey = repo.pushed_at + repo.watchers;
            if(cached[repo.id] == ckey) return cb();
            cached[repo.id] = ckey;
            // get the watchers, is nice
            // logger.debug("checking "+repo.id);
            github.getRepoApi().getRepoWatchers(auth.username, repo.id.substring(repo.id.indexOf('/') + 1), function(err, watchers){
                repo.watchers = watchers;
                // get a snapshot of the full repo, is nice too
                request.get({uri:"https://api.github.com/repos/" + repo.id + "/git/trees/HEAD?recursive=1", headers:auth.headers, json:true}, function(err, resp, tree) {
                    if(err || !tree || !tree.tree) return cb(err);
                    repo.tree = tree.tree;
                    // see if there's any viewers!
                    var viewer = false;
                    for(var i=0; i < repo.tree.length; i++) if(/^\w+\.app$/.test(repo.tree[i].path)) viewer = repo.tree[i].path;
                    if(!viewer) return cb();
                    // logger.debug("found a viewer! "+repo.id);
                    syncRepo(repo, function(err) {
                        // mangle the manifest so it's a unique handle
                        var manifest = repo.id+"/"+viewer;
                        var js;
                        try {
                            js = JSON.parse(fs.readFileSync(manifest));
                            if(!js || js.static != "true") throw new Error("invalid manifest");
                            js.handle = repo.id.replace("/", "-");
                            js.author = auth.username;
                            js.is = 'app';
                            js.github = "https://www.github.com/" + repo.id;
                            fs.writeFileSync(manifest, JSON.stringify(js));
                        } catch (err) {
                            // bail, no viewer for you
                            console.error("failed: "+err);
                            return cb();
                        }
                        viewers.push({id:repo.id, manifest:manifest, at:repo.pushed_at, viewer:js.viewer});
                        request.post({url:lockerUrl+'/map/upsert?manifest=Me/github/'+manifest+'&type=install'}, function(err, resp) {
                            cb();
                        });
                    });
                });
            });
        }, function(err){
            callback(err, repos);
        });
    });
}

function getIDFromUrl(url) {
    if(typeof url !== 'string')
        return url;
    return url.substring(url.lastIndexOf('/', url.lastIndexOf('/') - 1) + 1);
}

function syncRepo(repo, callback)
{
    var existing = {};
    try {
        var js = JSON.parse(fs.readFileSync(repo.id+".json"));
        for(var i=0; i < js.tree.length; i++)
        {
            existing[js.tree[i].path] = js.tree[i].sha;
        }
    } catch(e){};
    // make sure there's at least one tree entry for the repo dir itself
    repo.tree.push({path:".",sha:"na",type:"tree"});
    async.forEach(repo.tree, function(t, cb){
        if(t.type != "tree") return cb();
        if(existing[t.path] == t.sha) return cb(); // no changes
        nfs.mkdir(repo.id + "/" + t.path, 0777, true, cb);
    }, function(){
        // then the blobs
        async.forEachSeries(repo.tree, function(t, cb){
            if(t.type != "blob") return cb();
            if(existing[t.path] == t.sha) return cb(); // no changes
            setTimeout(function(){
                request.get({uri:'https://raw.github.com/'+repo.id+'/HEAD/'+t.path, encoding: 'binary', headers:auth.headers}, function(err, resp, body) {
                    // logger.debug(resp.statusCode + " for "+ t.path);
                    if(err || !resp || resp.statusCode != 200) {t.sha = ""; return cb(); } // don't save the sha so it gets retried again
                    fs.writeFile(repo.id + "/" + t.path, body, 'binary', cb);
                });
            },500);
        }, function(){
            fs.writeFile(repo.id+".json", JSON.stringify(repo));
            callback();
        });
    });
}
<commit_msg>fixes #519, sometimes we get junk back from github<commit_after>var GitHubApi = require("github").GitHubApi
  , request = require('request')
  , github = new GitHubApi()
  , async = require('async')
  , nfs = require('node-fs')
  , fs = require('fs')
  , lockerUrl
  , auth
  , viewers = []
  ;

exports.sync = function(processInfo, cb) {
    auth = processInfo.auth;
    auth.headers = {"Authorization":"token "+auth.accessToken, "Connection":"keep-alive"};
    var cached = {};
    if (processInfo.config && processInfo.config.cached)
        cached = processInfo.config.cached;
    lockerUrl = processInfo.lockerUrl;
    exports.syncRepos(cached, function(err, repos) {
        if (err) console.error(err);
        var responseObj = {data : {}, config: { cached: cached }};
        responseObj.data.repo = repos;
        responseObj.data.view = viewers;
        // logger.debug(viewers);
        cb(err, responseObj);
    });
};

exports.syncRepos = function(cached, callback) {
    github.getRepoApi().getUserRepos(auth.username, function(err, repos) {
        if(err || !repos || !repos.length) return callback(err, []);
        // process each one to get richer data
        async.forEach(repos, function(repo, cb) {
            repo.id = getIDFromUrl(repo.url);
            // nothing changed
            var ckey = repo.pushed_at + repo.watchers;
            if(cached[repo.id] == ckey) return cb();
            cached[repo.id] = ckey;
            // get the watchers, is nice
            // logger.debug("checking "+repo.id);
            github.getRepoApi().getRepoWatchers(auth.username, repo.id.substring(repo.id.indexOf('/') + 1), function(err, watchers){
                repo.watchers = watchers;
                // get a snapshot of the full repo, is nice too
                request.get({uri:"https://api.github.com/repos/" + repo.id + "/git/trees/HEAD?recursive=1", headers:auth.headers, json:true}, function(err, resp, tree) {
                    if(err || !tree || !tree.tree) return cb(err);
                    repo.tree = tree.tree;
                    // see if there's any viewers!
                    var viewer = false;
                    for(var i=0; i < repo.tree.length; i++) if(/^\w+\.app$/.test(repo.tree[i].path)) viewer = repo.tree[i].path;
                    if(!viewer) return cb();
                    // logger.debug("found a viewer! "+repo.id);
                    syncRepo(repo, function(err) {
                        // mangle the manifest so it's a unique handle
                        var manifest = repo.id+"/"+viewer;
                        var js;
                        try {
                            js = JSON.parse(fs.readFileSync(manifest));
                            if(!js || js.static != "true") throw new Error("invalid manifest");
                            js.handle = repo.id.replace("/", "-");
                            js.author = auth.username;
                            js.is = 'app';
                            js.github = "https://www.github.com/" + repo.id;
                            fs.writeFileSync(manifest, JSON.stringify(js));
                        } catch (err) {
                            // bail, no viewer for you
                            console.error("failed: "+err);
                            return cb();
                        }
                        viewers.push({id:repo.id, manifest:manifest, at:repo.pushed_at, viewer:js.viewer});
                        request.post({url:lockerUrl+'/map/upsert?manifest=Me/github/'+manifest+'&type=install'}, function(err, resp) {
                            cb();
                        });
                    });
                });
            });
        }, function(err){
            callback(err, repos);
        });
    });
}

function getIDFromUrl(url) {
    if(typeof url !== 'string')
        return url;
    return url.substring(url.lastIndexOf('/', url.lastIndexOf('/') - 1) + 1);
}

function syncRepo(repo, callback)
{
    var existing = {};
    try {
        var js = JSON.parse(fs.readFileSync(repo.id+".json"));
        for(var i=0; i < js.tree.length; i++)
        {
            existing[js.tree[i].path] = js.tree[i].sha;
        }
    } catch(e){};
    // make sure there's at least one tree entry for the repo dir itself
    repo.tree.push({path:".",sha:"na",type:"tree"});
    async.forEach(repo.tree, function(t, cb){
        if(t.type != "tree") return cb();
        if(existing[t.path] == t.sha) return cb(); // no changes
        nfs.mkdir(repo.id + "/" + t.path, 0777, true, cb);
    }, function(){
        // then the blobs
        async.forEachSeries(repo.tree, function(t, cb){
            if(t.type != "blob") return cb();
            if(existing[t.path] == t.sha) return cb(); // no changes
            setTimeout(function(){
                request.get({uri:'https://raw.github.com/'+repo.id+'/HEAD/'+t.path, encoding: 'binary', headers:auth.headers}, function(err, resp, body) {
                    // logger.debug(resp.statusCode + " for "+ t.path);
                    if(err || !resp || resp.statusCode != 200) {t.sha = ""; return cb(); } // don't save the sha so it gets retried again
                    if (body) {
                        fs.writeFile(repo.id + "/" + t.path, body, 'binary', cb);
                    } else {
                        cb();
                    }
                });
            },500);
        }, function(){
            fs.writeFile(repo.id+".json", JSON.stringify(repo));
            callback();
        });
    });
}
<|endoftext|>


<commit_before>const BlockStore = require('./')
const test = require('ava')
const fs = require('fs')
const path = require('path')
const mongoose = require('mongoose')
const {Types} = mongoose
const {ObjectId} = Types
const tempFileId = (new ObjectId()).toString() + '.png'

test.serial('listBuckets', t => {
  return BlockStore.listBuckets()
    .then(buckets => t.true(buckets.length >= 1))
})

test.serial('createBucket', t => {
  return BlockStore.createBucket('files')
    .then(e => t.truthy(e))
})

test.serial('signedSetUrl', t => {
  return BlockStore.signedSetUrl({id: tempFileId})
    .then(url => {
      t.truthy(url)
    }).catch(err => t.fail(err))
})

test.serial('signedSetUrl', t => {
  return BlockStore.signedSetUrl({id: tempFileId})
    .then(url => {
      t.truthy(url)
    }).catch(err => t.fail(err))
})

test.serial('set', t => {
  const testFile = fs.createReadStream(path.resolve(__dirname, './config.js'))
  const stats    = fs.statSync(path.resolve(__dirname, './config.js'))
  return BlockStore.set({id: tempFileId, stream: testFile, size: 1757, contentType: 'application/javascript'})
    .then(etag => {
      t.truthy(etag)
    }).catch(err => t.fail(err))
})

test.serial('get', t => {
  return BlockStore.get({id: tempFileId})
    .then(file => {
      t.truthy(file)
    }).catch(err => t.fail(err))
})

test.serial('stat', t => {
  return BlockStore.stat({id: tempFileId})
    .then(file => {
      t.truthy(file.size >= 100)
    }).catch(err => t.fail(err))
})

test.serial('remove', t => {
  return BlockStore.remove({id: tempFileId})
    .then(result => {
      // console.log('result', result, typeof result)
      t.truthy(result)
    }).catch(err => t.fail(err))
})

<commit_msg>fix all tests<commit_after>const BlockStore = require('./')
const test = require('ava')
const fs = require('fs')
const path = require('path')
const mongoose = require('mongoose')
const {Types} = mongoose
const {ObjectId} = Types
const tempFileId = (new ObjectId()).toString() + '.png'

test.serial('createBucket', t => {
  return BlockStore.createBucket('files')
    .then(e => t.truthy(e))
})

test.serial('listBuckets', t => {
  return BlockStore.listBuckets()
    .then(buckets => t.true(buckets.length >= 1))
})

test.serial('signedSetUrl', t => {
  return BlockStore.signedSetUrl({id: tempFileId})
    .then(url => {
      t.truthy(url)
    }).catch(err => t.fail(err))
})

test.serial('signedSetUrl', t => {
  return BlockStore.signedSetUrl({id: tempFileId})
    .then(url => {
      t.truthy(url)
    }).catch(err => t.fail(err))
})

test.serial('set', t => {
  const testFile = fs.createReadStream(path.resolve(__dirname, './config.js'))
  const stats    = fs.statSync(path.resolve(__dirname, './config.js'))
  return BlockStore.set({id: tempFileId, stream: testFile, size: 1757, contentType: 'application/javascript'})
    .then(etag => {
      t.truthy(etag)
    }).catch(err => t.fail(err))
})

test.serial('get', t => {
  return BlockStore.get({id: tempFileId})
    .then(file => {
      t.truthy(file)
    }).catch(err => t.fail(err))
})

test.serial('stat', t => {
  return BlockStore.stat({id: tempFileId})
    .then(file => {
      t.truthy(file.size >= 100)
    }).catch(err => t.fail(err))
})

test.serial('remove', t => {
  return BlockStore.remove({id: tempFileId})
    .then(result => {
      // console.log('result', result, typeof result)
      t.truthy(result)
    }).catch(err => t.fail(err))
})

<|endoftext|>