<commit_before>'use strict';

var assert = require('assert');
var testHelper = require('../helper');

describe('aggregate-intersection analysis', function() {

    var SOURCE_AIRBNB = 'select * from airbnb_rooms';
    var SOURCE_DISTRICTS = 'select * from madrid_districts';
    var AGGREGATE_COLUMN = 'price';
    var UNIQUE_COLUMN = 'cartodb_id';
    var AVERAGE_FUNCTION = 'avg';
    var MAX_FUNCTION = 'max';
    var COUNT_FUNCTION = 'count';

    var sourceAirbnbRooms = {
        type: 'source',
        params: {
            query: SOURCE_DISTRICTS
        }
    };

    var sourceMadridDistrict = {
        type: 'source',
        params: {
            query: SOURCE_AIRBNB
        }
    };

    describe('average price analysis', function  () {
        var averagePriceAnalysisDefinition = {
            type: 'aggregate-intersection',
            params: {
                source: sourceAirbnbRooms,
                target: sourceMadridDistrict,
                aggregate_function: AVERAGE_FUNCTION,
                aggregate_column: AGGREGATE_COLUMN
            }
        };

        it('should create an analysis and get districts with their average price', function (done) {
            testHelper.createAnalyses(averagePriceAnalysisDefinition, function(err, averagePriceAnalysis) {
                assert.ifError(err);

                var rootNode = averagePriceAnalysis.getRoot();

                testHelper.getRows(rootNode.getQuery(), function(err, rows) {
                    assert.ifError(err);
                    rows.forEach(function(row) {
                        assert.ok(typeof row.cartodb_id === 'number');
                        assert.ok(typeof row.the_geom === 'string');
                        assert.ok(typeof row.avg_price === 'number');
                    });

                    return done();
                });
            });
        });
    });

    describe('max price analysis', function  () {
        var maxPriceAnalysisDefinition = {
            type: 'aggregate-intersection',
            params: {
                source: sourceAirbnbRooms,
                target: sourceMadridDistrict,
                aggregate_function: MAX_FUNCTION,
                aggregate_column: AGGREGATE_COLUMN
            }
        };

        it('should create an analysis and get districts with their max price room', function (done) {
            testHelper.createAnalyses(maxPriceAnalysisDefinition, function(err, maxPriceAnalysis) {
                assert.ifError(err);

                var rootNode = maxPriceAnalysis.getRoot();

                testHelper.getRows(rootNode.getQuery(), function(err, rows) {
                    assert.ifError(err);
                    rows.forEach(function(row) {
                        assert.ok(typeof row.cartodb_id === 'number');
                        assert.ok(typeof row.the_geom === 'string');
                        assert.ok(typeof row.max_price === 'number');
                    });

                    return done();
                });
            });
        });
    });

    describe('count rooms analysis', function  () {
        var countRoomsAnalysisDefinition = {
            type: 'aggregate-intersection',
            params: {
                source: sourceAirbnbRooms,
                target: sourceMadridDistrict,
                aggregate_function: COUNT_FUNCTION,
                aggregate_column: UNIQUE_COLUMN
            }
        };

        it('should create an analysis and get districts with their counted rooms', function (done) {
            testHelper.createAnalyses(countRoomsAnalysisDefinition, function(err, countRoomsAnalysis) {
                assert.ifError(err);

                var rootNode = countRoomsAnalysis.getRoot();

                testHelper.getRows(rootNode.getQuery(), function(err, rows) {
                    assert.ifError(err);
                    rows.forEach(function(row) {
                        assert.ok(typeof row.cartodb_id === 'number');
                        assert.ok(typeof row.the_geom === 'string');
                        assert.ok(typeof row.count_vals === 'number');
                    });

                    return done();
                });
            });
        });
    });
});
<commit_msg>Add test to check aggregate-intersection has unique column names<commit_after>'use strict';

var assert = require('assert');
var testHelper = require('../helper');

describe('aggregate-intersection analysis', function() {

    var SOURCE_AIRBNB = 'select * from airbnb_rooms';
    var SOURCE_DISTRICTS = 'select * from madrid_districts';
    var AGGREGATE_COLUMN = 'price';
    var UNIQUE_COLUMN = 'cartodb_id';
    var AVERAGE_FUNCTION = 'avg';
    var MAX_FUNCTION = 'max';
    var COUNT_FUNCTION = 'count';

    var sourceAirbnbRooms = {
        type: 'source',
        params: {
            query: SOURCE_DISTRICTS
        }
    };

    var sourceMadridDistrict = {
        type: 'source',
        params: {
            query: SOURCE_AIRBNB
        }
    };

    describe('average price analysis', function  () {
        var averagePriceAnalysisDefinition = {
            type: 'aggregate-intersection',
            params: {
                source: sourceAirbnbRooms,
                target: sourceMadridDistrict,
                aggregate_function: AVERAGE_FUNCTION,
                aggregate_column: AGGREGATE_COLUMN
            }
        };

        it('should create an analysis and get districts with their average price', function (done) {
            testHelper.createAnalyses(averagePriceAnalysisDefinition, function(err, averagePriceAnalysis) {
                assert.ifError(err);

                var rootNode = averagePriceAnalysis.getRoot();

                testHelper.getRows(rootNode.getQuery(), function(err, rows) {
                    assert.ifError(err);
                    rows.forEach(function(row) {
                        assert.ok(typeof row.cartodb_id === 'number');
                        assert.ok(typeof row.the_geom === 'string');
                        assert.ok(typeof row.avg_price === 'number');
                    });

                    return done();
                });
            });
        });
    });

    describe('max price analysis', function  () {
        var maxPriceAnalysisDefinition = {
            type: 'aggregate-intersection',
            params: {
                source: sourceAirbnbRooms,
                target: sourceMadridDistrict,
                aggregate_function: MAX_FUNCTION,
                aggregate_column: AGGREGATE_COLUMN
            }
        };

        it('should create an analysis and get districts with their max price room', function (done) {
            testHelper.createAnalyses(maxPriceAnalysisDefinition, function(err, maxPriceAnalysis) {
                assert.ifError(err);

                var rootNode = maxPriceAnalysis.getRoot();

                testHelper.getRows(rootNode.getQuery(), function(err, rows) {
                    assert.ifError(err);
                    rows.forEach(function(row) {
                        assert.ok(typeof row.cartodb_id === 'number');
                        assert.ok(typeof row.the_geom === 'string');
                        assert.ok(typeof row.max_price === 'number');
                    });

                    return done();
                });
            });
        });
    });

    describe('count rooms analysis', function  () {
        var countRoomsAnalysisDefinition = {
            type: 'aggregate-intersection',
            params: {
                source: sourceAirbnbRooms,
                target: sourceMadridDistrict,
                aggregate_function: COUNT_FUNCTION,
                aggregate_column: UNIQUE_COLUMN
            }
        };
        var countRoomsAnalysisDefinition2 = {
            type: 'aggregate-intersection',
            params: {
                source: countRoomsAnalysisDefinition,
                target: sourceAirbnbRooms,
                aggregate_function: COUNT_FUNCTION,
                aggregate_column: UNIQUE_COLUMN
            }
        };

        it('should create an analysis and get reaggregations with their counted rooms', function (done) {
            testHelper.createAnalyses(countRoomsAnalysisDefinition2, function(err, countRoomsAnalysis) {
                assert.ifError(err);

                var rootNode = countRoomsAnalysis.getRoot();

                testHelper.getRows(rootNode.getQuery(), function(err, rows) {
                    assert.ifError(err);
                    rows.forEach(function(row) {
                        assert.ok(typeof row.cartodb_id === 'number');
                        assert.ok(typeof row.the_geom === 'string');
                        assert.ok(typeof row.count_vals === 'number');
                    });

                    return done();
                });
            });
        });
    });

    describe('chained analysis', function  () {
        var countRoomsAnalysisDefinition = {
            type: 'aggregate-intersection',
            params: {
                source: sourceAirbnbRooms,
                target: sourceMadridDistrict,
                aggregate_function: COUNT_FUNCTION,
                aggregate_column: UNIQUE_COLUMN
            }
        };

        it('should create not fail because of duplicate column names', function (done) {
            testHelper.createAnalyses(countRoomsAnalysisDefinition, function(err, countRoomsAnalysis) {
                assert.ifError(err);

                var rootNode = countRoomsAnalysis.getRoot();

                testHelper.getRows(rootNode.getQuery(), function(err, rows) {
                    assert.ifError(err);
                    rows.forEach(function(row) {
                        assert.ok(typeof row.cartodb_id === 'number');
                        assert.ok(typeof row.the_geom === 'string');
                        assert.ok(typeof row.count_vals === 'number');
                    });

                    return done();
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 DrSmugleaf
//

"use strict"
const expect = require("chai").expect

describe("Info", function() {
  describe("run", function() {
    it("should return a discord reply with the bot's info", function() {
      const command = global.client.registry.resolveCommand("util:info")

      return global.channel.sendMessage("!info").then((msg) => {
        command.run(msg)

        return global.channel.awaitMessages((msg) => {
          return msg.content !== "!info" && msg.author.id === global.client.user.id
        }, { maxMatches: 1 }).then((msg) => {
          const reply = msg.first().content.replace(`<@${global.client.user.id}>, `, "")
          expect(global.constants.responses.INFO["english"]).to.include(reply)
        })
      })
    })
  })
})
<commit_msg>Change !info unit test from include to equal<commit_after>//
// Copyright (c) 2017 DrSmugleaf
//

"use strict"
const expect = require("chai").expect

describe("Info", function() {
  describe("run", function() {
    it("should return a discord reply with the bot's info", function() {
      const command = global.client.registry.resolveCommand("util:info")

      return global.channel.sendMessage("!info").then((msg) => {
        command.run(msg)

        return global.channel.awaitMessages((msg) => {
          return msg.content !== "!info" && msg.author.id === global.client.user.id
        }, { maxMatches: 1 }).then((msg) => {
          const reply = msg.first().content.replace(`<@${global.client.user.id}>, `, "")
          expect(global.constants.responses.INFO["english"]).to.equal(reply)
        })
      })
    })
  })
})
<|endoftext|>


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

define([
    "firebug/lib/object",
    "firebug/chrome/firefox",
    "firebug/firebug",
    "firebug/dom/toggleBranch",
    "firebug/lib/events",
    "firebug/lib/dom",
    "firebug/lib/css",
    "firebug/js/stackFrame",
    "firebug/lib/locale",
    "firebug/lib/string",
    "firebug/dom/domPanel",     // Firebug.DOMBasePanel, Firebug.DOMPanel.DirTable
],
function(Obj, Firefox, Firebug, ToggleBranch, Events, Dom, Css, StackFrame, Locale, Str) {

// ********************************************************************************************* //
// Watch Panel

Firebug.WatchPanel = function()
{
};

/**
 * Represents the Watch side panel available in the Script panel.
 */
Firebug.WatchPanel.prototype = Obj.extend(Firebug.DOMBasePanel.prototype,
/** @lends Firebug.WatchPanel */
{
    tag: Firebug.DOMPanel.DirTable.watchTag,

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // extends Panel

    name: "watches",
    order: 0,
    parentPanel: "script",
    enableA11y: true,
    deriveA11yFrom: "console",

    initialize: function()
    {
        this.onMouseDown = Obj.bind(this.onMouseDown, this);
        this.onMouseOver = Obj.bind(this.onMouseOver, this);
        this.onMouseOut = Obj.bind(this.onMouseOut, this);

        Firebug.registerUIListener(this);

        Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments);
    },

    destroy: function(state)
    {
        state.watches = this.watches;

        Firebug.unregisterUIListener(this);

        Firebug.DOMBasePanel.prototype.destroy.apply(this, arguments);
    },

    show: function(state)
    {
        if (state && state.watches)
            this.watches = state.watches;
    },

    initializeNode: function(oldPanelNode)
    {
        Events.addEventListener(this.panelNode, "mousedown", this.onMouseDown, false);
        Events.addEventListener(this.panelNode, "mouseover", this.onMouseOver, false);
        Events.addEventListener(this.panelNode, "mouseout", this.onMouseOut, false);

        Firebug.DOMBasePanel.prototype.initializeNode.apply(this, arguments);
    },

    destroyNode: function()
    {
        Events.removeEventListener(this.panelNode, "mousedown", this.onMouseDown, false);
        Events.removeEventListener(this.panelNode, "mouseover", this.onMouseOver, false);
        Events.removeEventListener(this.panelNode, "mouseout", this.onMouseOut, false);

        Firebug.DOMBasePanel.prototype.destroyNode.apply(this, arguments);
    },

    refresh: function()
    {
        this.rebuild(true);
    },

    updateSelection: function(frame)
    {
        // this method is called while the debugger has halted JS,
        // so failures don't show up in FBS_ERRORS
        try
        {
            this.doUpdateSelection(frame);
        }
        catch (exc)
        {
            if (FBTrace.DBG_ERRORS && FBTrace.DBG_STACK)
                FBTrace.sysout("updateSelection FAILS " + exc, exc);
        }
    },

    doUpdateSelection: function(frame)
    {
        if (FBTrace.DBG_STACK)
            FBTrace.sysout("dom watch panel updateSelection frame " + frame, frame);

        Events.dispatch(this.fbListeners, "onBeforeDomUpdateSelection", [this]);

        var newFrame = frame && ("signature" in frame) &&
            (frame.signature() != this.frameSignature);

        if (newFrame)
        {
            this.toggles = new ToggleBranch.ToggleBranch();
            this.frameSignature = frame.signature();
        }

        var scopes;
        if (frame instanceof StackFrame.StackFrame)
            scopes = frame.getScopes(Firebug.viewChrome);
        else
            scopes = [this.context.getCurrentGlobal()];

        if (FBTrace.DBG_STACK)
            FBTrace.sysout("dom watch frame isStackFrame " +
                (frame instanceof StackFrame.StackFrame) +
                " updateSelection scopes " + scopes.length, scopes);

        var members = [];

        var context = this.context;
        if (this.watches)
        {
            for (var i = 0; i < this.watches.length; ++i)
            {
                var expr = this.watches[i];
                var value = null;

                Firebug.CommandLine.evaluate(expr, context, null, context.getCurrentGlobal(),
                    function success(result, context)
                    {
                        value = result;
                    },
                    function failed(result, context)
                    {
                        var exc = result;
                        value = new FirebugReps.ErrorCopy(exc+"");
                    }
                );

                this.addMember(scopes[0], "watch", members, expr, value, 0);

                if (FBTrace.DBG_DOM)
                {
                    FBTrace.sysout("watch.updateSelection \"" + expr + "\"",
                        {expr: expr, value: value, members: members});
                }
            }
        }

        if (frame && frame instanceof StackFrame.StackFrame)
        {
            var thisVar = frame.getThisValue();
            if (thisVar)
                this.addMember(scopes[0], "user", members, "this", thisVar, 0);

            // locals, pre-expanded
            members.push.apply(members, this.getMembers(scopes[0], 0));

            for (var i=1; i<scopes.length; i++)
            {
                var scope = scopes[i];
                var name = (scope.hasOwnProperty("toString") ? scope.toString() :
                    Object.prototype.toString.call(scope));

                // Some objects are stringified as [object ClassName]; extract
                // the [[Class]] from those.
                var re = /\[object (.*)\]/.exec(name);
                if (re)
                {
                    if (re[1] === "Window")
                        name = Locale.$STR("Window_Scope");
                    else
                        name = re[1];
                }

                this.addMember(scope, "scopes", members, name, scope, 0);
            }
        }

        this.expandMembers(members, this.toggles, 0, 0);
        this.showMembers(members, false);

        if (FBTrace.DBG_STACK)
            FBTrace.sysout("dom watch panel updateSelection members " + members.length, members);
    },

    rebuild: function()
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.rebuild", this.selection);

        this.updateSelection(this.selection);
    },

    showEmptyMembers: function()
    {
        var domTable = this.tag.replace({domPanel: this, toggles: new ToggleBranch.ToggleBranch()},
            this.panelNode);

        // The direction needs to be adjusted according to the direction
        // of the user agent. See issue 5073.
        // TODO: Set the direction at the <body> to allow correct formatting of all relevant parts.
        // This requires more adjustments related for rtl user agents.
        var mainFrame = Firefox.getElementById("fbMainFrame");
        var cs = mainFrame.ownerDocument.defaultView.getComputedStyle(mainFrame);
        var watchRow = domTable.getElementsByClassName("watchNewRow").item(0);
        watchRow.style.direction = cs.direction;
    },

    addWatch: function(expression)
    {
        expression = Str.trim(expression);

        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.addWatch; expression: "+expression);

        if (!this.watches)
            this.watches = [];

        for (var i=0; i<this.watches.length; i++)
        {
            if (expression == this.watches[i])
                return;
        }

        this.watches.splice(0, 0, expression);
        this.rebuild(true);
    },

    removeWatch: function(expression)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.removeWatch; expression: " + expression);

        if (!this.watches)
            return;

        var index = this.watches.indexOf(expression);
        if (index != -1)
            this.watches.splice(index, 1);
    },

    editNewWatch: function(value)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.editNewWatch; value: " + value);

        var watchNewRow = this.panelNode.getElementsByClassName("watchNewRow").item(0);
        if (watchNewRow)
            this.editProperty(watchNewRow, value);
    },

    setWatchValue: function(row, value)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.setWatchValue", {row: row, value: value});

        var rowIndex = getWatchRowIndex(row);
        this.watches[rowIndex] = value;
        this.rebuild(true);
    },

    deleteWatch: function(row)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.deleteWatch", row);

        var rowIndex = getWatchRowIndex(row);
        this.watches.splice(rowIndex, 1);
        this.rebuild(true);

        this.context.setTimeout(Obj.bindFixed(function()
        {
            this.showToolbox(null);
        }, this));
    },

    // deletes all the watches
    deleteAllWatches: function()
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.deleteAllWatches");
        this.watches = [];
        this.rebuild(true);
        this.context.setTimeout(Obj.bindFixed(function()
        {
            this.showToolbox(null);
        }, this));
    },

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

    showToolbox: function(row)
    {
        var toolbox = this.getToolbox();
        if (row)
        {
            if (Css.hasClass(row, "editing"))
                return;

            toolbox.watchRow = row;

            var offset = Dom.getClientOffset(row);
            toolbox.style.top = offset.y + "px";
            this.panelNode.appendChild(toolbox);
        }
        else
        {
            delete toolbox.watchRow;

            if (toolbox.parentNode)
                toolbox.parentNode.removeChild(toolbox);
        }
    },

    getToolbox: function()
    {
        if (!this.toolbox)
        {
            this.toolbox = Firebug.DOMBasePanel.ToolboxPlate.tag.replace(
                {domPanel: this}, this.document);
        }

        return this.toolbox;
    },

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

    onMouseDown: function(event)
    {
        var watchNewRow = Dom.getAncestorByClass(event.target, "watchNewRow");
        if (watchNewRow)
        {
            this.editProperty(watchNewRow);
            Events.cancelEvent(event);
        }
    },

    onMouseOver: function(event)
    {
        var watchRow = Dom.getAncestorByClass(event.target, "watchRow");
        if (watchRow)
            this.showToolbox(watchRow);
    },

    onMouseOut: function(event)
    {
        if (Dom.isAncestor(event.relatedTarget, this.getToolbox()))
            return;

        var watchRow = Dom.getAncestorByClass(event.relatedTarget, "watchRow");
        if (!watchRow)
            this.showToolbox(null);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Context Menu

    /**
     * Creates "Add Watch" menu item within DOM and Watch panel context menus.
     */
    onContextMenu: function(items, object, target, context, panel, popup)
    {
        // Ignore events from other contexts.
        if (this.context != context)
            return;

        if (panel.name != "dom" && panel.name != "watches")
            return;

        var row = Dom.getAncestorByClass(target, "memberRow");
        if (!row || row.domObject.ignoredPath)
            return;

        var path = this.getPropertyPath(row);
        if (!path || !path.length)
            return;

        // Ignore top level variables in the Watch panel.
        if (panel.name == "watches" && path.length == 1)
            return;

        items.push({
           id: "fbAddWatch",
           label: "AddWatch",
           tooltiptext: "watch.tip.Add_Watch",
           command: Obj.bindFixed(this.addWatch, this, path.join(""))
        });
    },

    getContextMenuItems: function(object, target)
    {
        var items = Firebug.DOMBasePanel.prototype.getContextMenuItems.apply(this, arguments);

        if (!this.watches || this.watches.length == 0)
            return items;

        // find the index of "DeletePropery" in the items:
        var deleteWatchIndex = items.map(function(item)
        {
            return item.id;
        }).indexOf("DeleteProperty");

        // if DeleteWatch was found, we insert DeleteAllWatches after it
        // otherwise, we insert the item at the beginning of the menu
        var deleteAllWatchesIndex = (deleteWatchIndex >= 0) ? deleteWatchIndex + 1 : 0;

        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("insert DeleteAllWatches at: "+ deleteAllWatchesIndex);

        // insert DeleteAllWatches after DeleteWatch
        items.splice(deleteAllWatchesIndex, 0, {
            id: "fbDeleteAllWatches",
            label: "DeleteAllWatches",
            tooltiptext: "watch.tip.Delete_All_Watches",
            command: Obj.bindFixed(this.deleteAllWatches, this)
        });

        return items;
    }
});

// ********************************************************************************************* //
// Local Helpers

function getWatchRowIndex(row)
{
    var index = -1;
    for (; row; row = row.previousSibling)
    {
        if (Css.hasClass(row, "watchRow"))
            ++index;
    }
    return index;
}

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

Firebug.registerPanel(Firebug.WatchPanel);

return Firebug.WatchPanel;

// ********************************************************************************************* //
});
<commit_msg>Issue 6722 ('Delete watch' is only shown after moving mouse to other watch after delete) http://code.google.com/p/fbug/issues/detail?id=6722<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/lib/object",
    "firebug/chrome/firefox",
    "firebug/firebug",
    "firebug/dom/toggleBranch",
    "firebug/lib/events",
    "firebug/lib/dom",
    "firebug/lib/css",
    "firebug/js/stackFrame",
    "firebug/lib/locale",
    "firebug/lib/string",
    "firebug/dom/domPanel",     // Firebug.DOMBasePanel, Firebug.DOMPanel.DirTable
],
function(Obj, Firefox, Firebug, ToggleBranch, Events, Dom, Css, StackFrame, Locale, Str) {

// ********************************************************************************************* //
// Watch Panel

Firebug.WatchPanel = function()
{
};

/**
 * Represents the Watch side panel available in the Script panel.
 */
Firebug.WatchPanel.prototype = Obj.extend(Firebug.DOMBasePanel.prototype,
/** @lends Firebug.WatchPanel */
{
    tag: Firebug.DOMPanel.DirTable.watchTag,

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // extends Panel

    name: "watches",
    order: 0,
    parentPanel: "script",
    enableA11y: true,
    deriveA11yFrom: "console",

    initialize: function()
    {
        this.onMouseDown = Obj.bind(this.onMouseDown, this);
        this.onMouseOver = Obj.bind(this.onMouseOver, this);
        this.onMouseOut = Obj.bind(this.onMouseOut, this);

        Firebug.registerUIListener(this);

        Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments);
    },

    destroy: function(state)
    {
        state.watches = this.watches;

        Firebug.unregisterUIListener(this);

        Firebug.DOMBasePanel.prototype.destroy.apply(this, arguments);
    },

    show: function(state)
    {
        if (state && state.watches)
            this.watches = state.watches;
    },

    initializeNode: function(oldPanelNode)
    {
        Events.addEventListener(this.panelNode, "mousedown", this.onMouseDown, false);
        Events.addEventListener(this.panelNode, "mouseover", this.onMouseOver, false);
        Events.addEventListener(this.panelNode, "mouseout", this.onMouseOut, false);

        Firebug.DOMBasePanel.prototype.initializeNode.apply(this, arguments);
    },

    destroyNode: function()
    {
        Events.removeEventListener(this.panelNode, "mousedown", this.onMouseDown, false);
        Events.removeEventListener(this.panelNode, "mouseover", this.onMouseOver, false);
        Events.removeEventListener(this.panelNode, "mouseout", this.onMouseOut, false);

        Firebug.DOMBasePanel.prototype.destroyNode.apply(this, arguments);
    },

    refresh: function()
    {
        this.rebuild(true);
    },

    updateSelection: function(frame)
    {
        // this method is called while the debugger has halted JS,
        // so failures don't show up in FBS_ERRORS
        try
        {
            this.doUpdateSelection(frame);
        }
        catch (exc)
        {
            if (FBTrace.DBG_ERRORS && FBTrace.DBG_STACK)
                FBTrace.sysout("updateSelection FAILS " + exc, exc);
        }
    },

    doUpdateSelection: function(frame)
    {
        if (FBTrace.DBG_STACK)
            FBTrace.sysout("dom watch panel updateSelection frame " + frame, frame);

        Events.dispatch(this.fbListeners, "onBeforeDomUpdateSelection", [this]);

        var newFrame = frame && ("signature" in frame) &&
            (frame.signature() != this.frameSignature);

        if (newFrame)
        {
            this.toggles = new ToggleBranch.ToggleBranch();
            this.frameSignature = frame.signature();
        }

        var scopes;
        if (frame instanceof StackFrame.StackFrame)
            scopes = frame.getScopes(Firebug.viewChrome);
        else
            scopes = [this.context.getCurrentGlobal()];

        if (FBTrace.DBG_STACK)
            FBTrace.sysout("dom watch frame isStackFrame " +
                (frame instanceof StackFrame.StackFrame) +
                " updateSelection scopes " + scopes.length, scopes);

        var members = [];

        var context = this.context;
        if (this.watches)
        {
            for (var i = 0; i < this.watches.length; ++i)
            {
                var expr = this.watches[i];
                var value = null;

                Firebug.CommandLine.evaluate(expr, context, null, context.getCurrentGlobal(),
                    function success(result, context)
                    {
                        value = result;
                    },
                    function failed(result, context)
                    {
                        var exc = result;
                        value = new FirebugReps.ErrorCopy(exc+"");
                    }
                );

                this.addMember(scopes[0], "watch", members, expr, value, 0);

                if (FBTrace.DBG_DOM)
                {
                    FBTrace.sysout("watch.updateSelection \"" + expr + "\"",
                        {expr: expr, value: value, members: members});
                }
            }
        }

        if (frame && frame instanceof StackFrame.StackFrame)
        {
            var thisVar = frame.getThisValue();
            if (thisVar)
                this.addMember(scopes[0], "user", members, "this", thisVar, 0);

            // locals, pre-expanded
            members.push.apply(members, this.getMembers(scopes[0], 0));

            for (var i=1; i<scopes.length; i++)
            {
                var scope = scopes[i];
                var name = (scope.hasOwnProperty("toString") ? scope.toString() :
                    Object.prototype.toString.call(scope));

                // Some objects are stringified as [object ClassName]; extract
                // the [[Class]] from those.
                var re = /\[object (.*)\]/.exec(name);
                if (re)
                {
                    if (re[1] === "Window")
                        name = Locale.$STR("Window_Scope");
                    else
                        name = re[1];
                }

                this.addMember(scope, "scopes", members, name, scope, 0);
            }
        }

        this.expandMembers(members, this.toggles, 0, 0);
        this.showMembers(members, false);

        if (FBTrace.DBG_STACK)
            FBTrace.sysout("dom watch panel updateSelection members " + members.length, members);
    },

    rebuild: function()
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.rebuild", this.selection);

        this.updateSelection(this.selection);
    },

    showEmptyMembers: function()
    {
        var domTable = this.tag.replace({domPanel: this, toggles: new ToggleBranch.ToggleBranch()},
            this.panelNode);

        // The direction needs to be adjusted according to the direction
        // of the user agent. See issue 5073.
        // TODO: Set the direction at the <body> to allow correct formatting of all relevant parts.
        // This requires more adjustments related for rtl user agents.
        var mainFrame = Firefox.getElementById("fbMainFrame");
        var cs = mainFrame.ownerDocument.defaultView.getComputedStyle(mainFrame);
        var watchRow = domTable.getElementsByClassName("watchNewRow").item(0);
        watchRow.style.direction = cs.direction;
    },

    addWatch: function(expression)
    {
        expression = Str.trim(expression);

        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.addWatch; expression: "+expression);

        if (!this.watches)
            this.watches = [];

        for (var i=0; i<this.watches.length; i++)
        {
            if (expression == this.watches[i])
                return;
        }

        this.watches.splice(0, 0, expression);
        this.rebuild(true);
    },

    removeWatch: function(expression)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.removeWatch; expression: " + expression);

        if (!this.watches)
            return;

        var index = this.watches.indexOf(expression);
        if (index != -1)
            this.watches.splice(index, 1);
    },

    editNewWatch: function(value)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.editNewWatch; value: " + value);

        var watchNewRow = this.panelNode.getElementsByClassName("watchNewRow").item(0);
        if (watchNewRow)
            this.editProperty(watchNewRow, value);
    },

    setWatchValue: function(row, value)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.setWatchValue", {row: row, value: value});

        var rowIndex = getWatchRowIndex(row);
        this.watches[rowIndex] = value;
        this.rebuild(true);
    },

    deleteWatch: function(row)
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.deleteWatch", row);

        var rowIndex = getWatchRowIndex(row);
        this.watches.splice(rowIndex, 1);
        this.rebuild(true);

        this.context.setTimeout(Obj.bindFixed(function()
        {
            var watchRow = this.panelNode.getElementsByClassName("watchRow")[rowIndex];
            this.showToolbox(watchRow);
        }, this));
    },

    // deletes all the watches
    deleteAllWatches: function()
    {
        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("Firebug.WatchPanel.deleteAllWatches");
        this.watches = [];
        this.rebuild(true);
        this.context.setTimeout(Obj.bindFixed(function()
        {
            this.showToolbox(null);
        }, this));
    },

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

    showToolbox: function(row)
    {
        var toolbox = this.getToolbox();
        if (row)
        {
            if (Css.hasClass(row, "editing"))
                return;

            toolbox.watchRow = row;

            var offset = Dom.getClientOffset(row);
            toolbox.style.top = offset.y + "px";
            this.panelNode.appendChild(toolbox);
        }
        else
        {
            delete toolbox.watchRow;

            if (toolbox.parentNode)
                toolbox.parentNode.removeChild(toolbox);
        }
    },

    getToolbox: function()
    {
        if (!this.toolbox)
        {
            this.toolbox = Firebug.DOMBasePanel.ToolboxPlate.tag.replace(
                {domPanel: this}, this.document);
        }

        return this.toolbox;
    },

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

    onMouseDown: function(event)
    {
        var watchNewRow = Dom.getAncestorByClass(event.target, "watchNewRow");
        if (watchNewRow)
        {
            this.editProperty(watchNewRow);
            Events.cancelEvent(event);
        }
    },

    onMouseOver: function(event)
    {
        var watchRow = Dom.getAncestorByClass(event.target, "watchRow");
        if (watchRow)
            this.showToolbox(watchRow);
    },

    onMouseOut: function(event)
    {
        if (Dom.isAncestor(event.relatedTarget, this.getToolbox()))
            return;

        var watchRow = Dom.getAncestorByClass(event.relatedTarget, "watchRow");
        if (!watchRow)
            this.showToolbox(null);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Context Menu

    /**
     * Creates "Add Watch" menu item within DOM and Watch panel context menus.
     */
    onContextMenu: function(items, object, target, context, panel, popup)
    {
        // Ignore events from other contexts.
        if (this.context != context)
            return;

        if (panel.name != "dom" && panel.name != "watches")
            return;

        var row = Dom.getAncestorByClass(target, "memberRow");
        if (!row || row.domObject.ignoredPath)
            return;

        var path = this.getPropertyPath(row);
        if (!path || !path.length)
            return;

        // Ignore top level variables in the Watch panel.
        if (panel.name == "watches" && path.length == 1)
            return;

        items.push({
           id: "fbAddWatch",
           label: "AddWatch",
           tooltiptext: "watch.tip.Add_Watch",
           command: Obj.bindFixed(this.addWatch, this, path.join(""))
        });
    },

    getContextMenuItems: function(object, target)
    {
        var items = Firebug.DOMBasePanel.prototype.getContextMenuItems.apply(this, arguments);

        if (!this.watches || this.watches.length == 0)
            return items;

        // find the index of "DeletePropery" in the items:
        var deleteWatchIndex = items.map(function(item)
        {
            return item.id;
        }).indexOf("DeleteProperty");

        // if DeleteWatch was found, we insert DeleteAllWatches after it
        // otherwise, we insert the item at the beginning of the menu
        var deleteAllWatchesIndex = (deleteWatchIndex >= 0) ? deleteWatchIndex + 1 : 0;

        if (FBTrace.DBG_WATCH)
            FBTrace.sysout("insert DeleteAllWatches at: "+ deleteAllWatchesIndex);

        // insert DeleteAllWatches after DeleteWatch
        items.splice(deleteAllWatchesIndex, 0, {
            id: "fbDeleteAllWatches",
            label: "DeleteAllWatches",
            tooltiptext: "watch.tip.Delete_All_Watches",
            command: Obj.bindFixed(this.deleteAllWatches, this)
        });

        return items;
    }
});

// ********************************************************************************************* //
// Local Helpers

function getWatchRowIndex(row)
{
    var index = -1;
    for (; row; row = row.previousSibling)
    {
        if (Css.hasClass(row, "watchRow"))
            ++index;
    }
    return index;
}

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

Firebug.registerPanel(Firebug.WatchPanel);

return Firebug.WatchPanel;

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


<commit_before>define(['kb.widget.dashboard.base', 'kb.user_profile', 'kb.client.user_profile', 'kb.session', 'kb.appstate', 'kb.utils', 'q'],
   function (DashboardWidget, UserProfile, UserProfileService, Session, AppState, Utils, Q) {
      "use strict";
      var widget = Object.create(DashboardWidget, {
         init: {
            value: function (cfg) {
               cfg.name = 'ProfileWidget';
               cfg.title = 'Your Profile';
               this.DashboardWidget_init(cfg);

               return this;
            }
         },

         afterStart: {
            value: function () {
               // NB: this uses the old original state-on-object rather than
               // the set/get/has state mechanism that most like-minded
               // widgets use.
               AppState.listenForItem('userprofile', {
								 onSet: function (profile) {
									 this.setState('userProfile', profile);
									 this.setState('profileCompletion', this.calcProfileCompletion(profile))
	               }.bind(this),
								 onError: function (err) {
								 	 this.setError(err);
								 }.bind(this)
							 });

               return this;
            }
         },

         setInitialState: {
            value: function (options) {
               return Q.Promise(function (resolve, reject, notify) {
                   if (!Session.isLoggedIn()) {
                     resolve();
                     return;
                  }
                  AppState.whenItem('userprofile')
                  .then(function(profile) {
                     this.setState('userProfile', profile);
										 this.setState('profileCompletion', this.calcProfileCompletion(profile))
                     resolve();
                  }.bind(this))
                  .catch(function (err) {

									 console.log('ERROR'); console.log(err);
                     reject(err);
                  })
                  .done();

               }.bind(this));
            }
         },

         onCreateTemplateContext: {
            value: function (context) {
							return Utils.merge(Utils.merge({}, context), {
								env: {
                	lists: this.lists
                }
              });
            }
         },
         calcProfileCompletion: {
            value: function (profile) {
                var completion = profile.calcProfileCompletion();
                if (completion.status === 'complete') {
                   return null;
                } else {
                   return completion;
                }
            }
         },
         getProfileStatus: {
            value: function () {
							if (this.status === 'error') {
								return 'error';
							} else {
	                if (this.hasState('userProfile')) {
	                   return this.getState('userProfile').getProfileStatus();
	                } else {
	                   return 'none';
	                }
						 	}
            }
         },

         render: {
            value: function () {
               // Generate initial view based on the current state of this widget.
               // Head off at the pass -- if not logged in, can't show profile.
							if (!Session.isLoggedIn()) {
                this.places.title.html('Unauthorized');
                this.places.content.html(this.renderTemplate('unauthorized'));
								return;
							}

							if (this.status === 'error') {
                 this.renderError();
							 } else {
									if (this.hasState('userProfile')) {
										console.log('profile status: ' + this.getState('userProfile').getProfileStatus());
		               switch (this.getState('userProfile').getProfileStatus()) {
		               case 'profile':
		                  // NORMAL PROFILE
		                  // Title can be be based on logged in user infor or the profile.
		                  // set window title.
										 try {
		                  this.places.title.html(this.widgetTitle);
		                  this.places.content.html(this.renderTemplate('view'));
										} catch (ex) {
		                  this.places.title.html(this.widgetTitle);
		                  this.places.content.html('ERROR: ' + ex);
										}
		                  break;
		               case 'stub':
		                  // STUB PROFILE
										 	this.places.title.html(this.widgetTitle);
		                  this.places.content.html(this.renderTemplate('stub_profile'));
		                  break;
		               case 'none':
		                  // NOT FOUND
		                  // no profile, no basic aaccount info
		                  this.places.title.html('User Not Found');
		                  this.places.content.html(this.renderTemplate('no_user'));
		                  break;
		               default:
		                  this.renderErrorView('Invalid profile state "' + state + '"')
		               }
		               return this;
		            }
							}
					}
         }
      });

      return widget;
   });<commit_msg>Remove remnant console log line and minor spacing cleanup.<commit_after>define(['kb.widget.dashboard.base', 'kb.user_profile', 'kb.client.user_profile', 'kb.session', 'kb.appstate', 'kb.utils', 'q'],
        function (DashboardWidget, UserProfile, UserProfileService, Session, AppState, Utils, Q) {
            "use strict";
            var widget = Object.create(DashboardWidget, {
                init: {
                    value: function (cfg) {
                        cfg.name = 'ProfileWidget';
                        cfg.title = 'Your Profile';
                        this.DashboardWidget_init(cfg);

                        return this;
                    }
                },
                afterStart: {
                    value: function () {
                        // NB: this uses the old original state-on-object rather than
                        // the set/get/has state mechanism that most like-minded
                        // widgets use.
                        AppState.listenForItem('userprofile', {
                            onSet: function (profile) {
                                this.setState('userProfile', profile);
                                this.setState('profileCompletion', this.calcProfileCompletion(profile))
                            }.bind(this),
                            onError: function (err) {
                                this.setError(err);
                            }.bind(this)
                        });

                        return this;
                    }
                },
                setInitialState: {
                    value: function (options) {
                        return Q.Promise(function (resolve, reject, notify) {
                            if (!Session.isLoggedIn()) {
                                resolve();
                                return;
                            }
                            AppState.whenItem('userprofile')
                                .then(function (profile) {
                                    this.setState('userProfile', profile);
                                    this.setState('profileCompletion', this.calcProfileCompletion(profile))
                                    resolve();
                                }.bind(this))
                                .catch(function (err) {
                                    console.log('ERROR');
                                    console.log(err);
                                    reject(err);
                                })
                                .done();
                        }.bind(this));
                    }
                },
                onCreateTemplateContext: {
                    value: function (context) {
                        return Utils.merge(Utils.merge({}, context), {
                            env: {
                                lists: this.lists
                            }
                        });
                    }
                },
                calcProfileCompletion: {
                    value: function (profile) {
                        var completion = profile.calcProfileCompletion();
                        if (completion.status === 'complete') {
                            return null;
                        } else {
                            return completion;
                        }
                    }
                },
                getProfileStatus: {
                    value: function () {
                        if (this.status === 'error') {
                            return 'error';
                        } else {
                            if (this.hasState('userProfile')) {
                                return this.getState('userProfile').getProfileStatus();
                            } else {
                                return 'none';
                            }
                        }
                    }
                },
                render: {
                    value: function () {
                        // Generate initial view based on the current state of this widget.
                        // Head off at the pass -- if not logged in, can't show profile.
                        if (!Session.isLoggedIn()) {
                            this.places.title.html('Unauthorized');
                            this.places.content.html(this.renderTemplate('unauthorized'));
                            return;
                        }

                        if (this.status === 'error') {
                            this.renderError();
                        } else {
                            if (this.hasState('userProfile')) {
                                switch (this.getState('userProfile').getProfileStatus()) {
                                    case 'profile':
                                        // NORMAL PROFILE
                                        // Title can be be based on logged in user infor or the profile.
                                        // set window title.
                                        try {
                                            this.places.title.html(this.widgetTitle);
                                            this.places.content.html(this.renderTemplate('view'));
                                        } catch (ex) {
                                            this.places.title.html(this.widgetTitle);
                                            this.places.content.html('ERROR: ' + ex);
                                        }
                                        break;
                                    case 'stub':
                                        // STUB PROFILE
                                        this.places.title.html(this.widgetTitle);
                                        this.places.content.html(this.renderTemplate('stub_profile'));
                                        break;
                                    case 'none':
                                        // NOT FOUND
                                        // no profile, no basic aaccount info
                                        this.places.title.html('User Not Found');
                                        this.places.content.html(this.renderTemplate('no_user'));
                                        break;
                                    default:
                                        this.renderErrorView('Invalid profile state "' + state + '"')
                                }
                                return this;
                            }
                        }
                    }
                }
            });

            return widget;
        });<|endoftext|>


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

import {CONSENT_STRING_TYPE} from '../../../src/consent-state';
import {deepEquals} from '../../../src/json';
import {dev, user} from '../../../src/log';
import {hasOwn, map} from '../../../src/utils/object';
import {isEnumValue, isObject} from '../../../src/types';

const TAG = 'amp-consent';

/**
 * Key values for retriving/storing consent info object.
 * STATE: Set when user accept or reject consent.
 * STRING: Set when a consent string is used to store more granular consent info
 * on vendors.
 * METADATA: set when consent metadata is passed in to store more granular consent info
 * on vendors.
 * DITRYBIT: Set when the stored consent info need to be revoked next time.
 * @enum {string}
 */
export const STORAGE_KEY = {
  STATE: 's',
  STRING: 'r',
  IS_DIRTY: 'd',
  METADATA: 'm',
};

/**
 * Key values for retriving/storing metadata values within consent info
 * @enum {string}
 */
export const METADATA_STORAGE_KEY = {
  CONSENT_STRING_TYPE: 'cst',
  ADDITIONAL_CONSENT: 'ac',
  GDPR_APPLIES: 'ga',
};

/**
 * @enum {number}
 */
export const CONSENT_ITEM_STATE = {
  ACCEPTED: 1,
  REJECTED: 2,
  DISMISSED: 3,
  NOT_REQUIRED: 4,
  UNKNOWN: 5,
  // TODO(@zhouyx): Seperate UI state from consent state. Add consent
  // requirement state ui_state = {pending, active, complete} consent_state =
  // {unknown, accepted, rejected}
};

/**
 * @typedef {{
 *  consentState: CONSENT_ITEM_STATE,
 *  consentString: (string|undefined),
 *  consentMetadata: (ConsentMetadataDef|undefined),
 *  isDirty: (boolean|undefined),
 * }}
 */
export let ConsentInfoDef;

/**
 * Used in ConsentInfoDef
 * @typedef {{
 *  consentStringType: (CONSENT_STRING_TYPE|undefined),
 *  additionalConsent: (string|undefined),
 * }}
 */
export let ConsentMetadataDef;

/**
 * Convert the legacy storage value to Consent Info
 * @param {boolean|Object|undefined} value
 * @return {ConsentInfoDef}
 */
export function getStoredConsentInfo(value) {
  if (value === undefined) {
    return constructConsentInfo(
      CONSENT_ITEM_STATE.UNKNOWN,
      undefined,
      undefined,
      undefined
    );
  }
  if (typeof value === 'boolean') {
    // legacy format
    return getLegacyStoredConsentInfo(value);
  }
  if (!isObject(value)) {
    throw dev().createError('Invalid stored consent value');
  }

  const consentState = convertValueToState(value[STORAGE_KEY.STATE]);
  return constructConsentInfo(
    consentState,
    value[STORAGE_KEY.STRING],
    convertStorageMetadata(value[STORAGE_KEY.METADATA]),
    value[STORAGE_KEY.IS_DIRTY] && value[STORAGE_KEY.IS_DIRTY] === 1
  );
}

/**
 * Helper function to detect if stored consent has dirtyBit set
 * @param {?ConsentInfoDef} consentInfo
 * @return {boolean}
 */
export function hasDirtyBit(consentInfo) {
  if (!consentInfo) {
    return false;
  }
  if (hasOwn(consentInfo, 'isDirty') && consentInfo['isDirty'] == true) {
    return true;
  }
  return false;
}

/**
 * Return the new consent state value based on stored state and new state
 * @param {!CONSENT_ITEM_STATE} newState
 * @param {!CONSENT_ITEM_STATE} previousState
 * @return {!CONSENT_ITEM_STATE}
 */
export function recalculateConsentStateValue(newState, previousState) {
  if (!isEnumValue(CONSENT_ITEM_STATE, newState)) {
    newState = CONSENT_ITEM_STATE.UNKNOWN;
  }
  if (newState == CONSENT_ITEM_STATE.DISMISSED) {
    return previousState || CONSENT_ITEM_STATE.UNKNOWN;
  }
  if (newState == CONSENT_ITEM_STATE.NOT_REQUIRED) {
    if (previousState && previousState != CONSENT_ITEM_STATE.UNKNOWN) {
      return previousState;
    }
  }
  return newState;
}

/**
 * Compose the value to store to localStorage based on the consentInfo
 * @param {!ConsentInfoDef} consentInfo
 * @return {?boolean|Object}
 */
export function composeStoreValue(consentInfo) {
  const obj = map();
  const consentState = consentInfo['consentState'];
  if (consentState == CONSENT_ITEM_STATE.ACCEPTED) {
    obj[STORAGE_KEY.STATE] = 1;
  } else if (consentState == CONSENT_ITEM_STATE.REJECTED) {
    obj[STORAGE_KEY.STATE] = 0;
  } else {
    // Only store consentString and dirtyBit with reject/accept action
    return null;
  }

  if (consentInfo['consentString']) {
    obj[STORAGE_KEY.STRING] = consentInfo['consentString'];
  }

  if (consentInfo['isDirty'] === true) {
    obj[STORAGE_KEY.IS_DIRTY] = 1;
  }

  if (consentInfo['consentMetadata']) {
    obj[STORAGE_KEY.METADATA] = composeMetadataStoreValue(
      consentInfo['consentMetadata']
    );
  }

  if (Object.keys(obj) == 0) {
    return null;
  }

  return obj;
}

/**
 * Convert the consentState to legacy boolean stored value
 * @param {!CONSENT_ITEM_STATE} consentState
 * @return {?boolean}
 */
export function calculateLegacyStateValue(consentState) {
  if (consentState == CONSENT_ITEM_STATE.ACCEPTED) {
    return true;
  }
  if (consentState == CONSENT_ITEM_STATE.REJECTED) {
    return false;
  }
  return null;
}

/**
 * Compare two consentInfo.
 * Return true if they can be converted to the same stored value.
 * @param {?ConsentInfoDef} infoA
 * @param {?ConsentInfoDef} infoB
 * @param {boolean=} opt_isDirty
 * @return {boolean}
 */
export function isConsentInfoStoredValueSame(infoA, infoB, opt_isDirty) {
  if (!infoA && !infoB) {
    return true;
  }
  if (infoA && infoB) {
    const stateEqual =
      calculateLegacyStateValue(infoA['consentState']) ===
      calculateLegacyStateValue(infoB['consentState']);
    const stringEqual =
      (infoA['consentString'] || '') === (infoB['consentString'] || '');
    let isDirtyEqual;
    if (opt_isDirty) {
      isDirtyEqual = !!infoA['isDirty'] === !!opt_isDirty;
    } else {
      isDirtyEqual = !!infoA['isDirty'] === !!infoB['isDirty'];
    }
    const metadataEqual = deepEquals(
      infoA['consentMetadata'],
      infoB['consentMetadata']
    );
    return stateEqual && stringEqual && metadataEqual && isDirtyEqual;
  }
  return false;
}

/**
 * Convert the legacy boolean stored value to consentInfo object
 * @param {boolean} value
 * @return {!ConsentInfoDef}
 */
function getLegacyStoredConsentInfo(value) {
  const state = convertValueToState(value);
  return constructConsentInfo(state);
}

/**
 * Construct the consentInfo object from values
 *
 * @param {CONSENT_ITEM_STATE} consentState
 * @param {string=} opt_consentString
 * @param {ConsentMetadataDef=} opt_consentMetadata
 * @param {boolean=} opt_isDirty
 * @return {!ConsentInfoDef}
 */
export function constructConsentInfo(
  consentState,
  opt_consentString,
  opt_consentMetadata,
  opt_isDirty
) {
  return {
    'consentState': consentState,
    'consentString': opt_consentString,
    'consentMetadata': opt_consentMetadata,
    'isDirty': opt_isDirty,
  };
}

/**
 * Construct the consentMetadataDef object from values
 *
 * @param {CONSENT_STRING_TYPE=} opt_consentStringType
 * @param {string=} opt_additionalConsent
 * @param {boolean=} opt_gdprApplies
 * @return {!ConsentMetadataDef}
 */
export function constructMetadata(
  opt_consentStringType,
  opt_additionalConsent,
  opt_gdprApplies
) {
  return {
    'consentStringType': opt_consentStringType,
    'additionalConsent': opt_additionalConsent,
    'gdprApplies': opt_gdprApplies,
  };
}

/**
 * Helper function to convert stored value to CONSENT_ITEM_STATE value
 * @param {*} value
 * @return {!CONSENT_ITEM_STATE}
 */
export function convertValueToState(value) {
  if (value === true || value === 1) {
    return CONSENT_ITEM_STATE.ACCEPTED;
  } else if (value === false || value === 0) {
    return CONSENT_ITEM_STATE.REJECTED;
  }
  return CONSENT_ITEM_STATE.UNKNOWN;
}

/**
 * Helper function to convert response enum value to CONSENT_ITEM_STATE value
 * @param {*} value
 * @return {?CONSENT_ITEM_STATE}
 */
export function convertEnumValueToState(value) {
  if (value === 'accepted') {
    return CONSENT_ITEM_STATE.ACCEPTED;
  } else if (value === 'rejected') {
    return CONSENT_ITEM_STATE.REJECTED;
  } else if (value === 'unknown') {
    return CONSENT_ITEM_STATE.UNKNOWN;
  }
  return null;
}

/**
 *
 * @param {!ConsentInfoDef} info
 * @return {boolean}
 */
export function hasStoredValue(info) {
  if (info['consentString']) {
    return true;
  }
  return (
    info['consentState'] === CONSENT_ITEM_STATE.ACCEPTED ||
    info['consentState'] === CONSENT_ITEM_STATE.REJECTED
  );
}

/**
 * Convert the CONSENT_ITEM_STATE back to readable string
 * @param {!CONSENT_ITEM_STATE} enumState
 * @return {string}
 */
export function getConsentStateValue(enumState) {
  if (enumState === CONSENT_ITEM_STATE.ACCEPTED) {
    return 'accepted';
  }

  if (enumState === CONSENT_ITEM_STATE.REJECTED) {
    return 'rejected';
  }

  return 'unknown';
}

/**
 * Converts ConsentMetadataDef to stroage value:
 * {'gdprApplies': true, 'additionalConsent': undefined, 'consentStringType': 2} =>
 * {'ga': true, 'cst': 2}
 *
 * @param {ConsentMetadataDef=} consentInfoMetadata
 * @return {Object}
 */
export function composeMetadataStoreValue(consentInfoMetadata) {
  const storageMetadata = map();
  if (consentInfoMetadata['consentStringType']) {
    storageMetadata[METADATA_STORAGE_KEY.CONSENT_STRING_TYPE] =
      consentInfoMetadata['consentStringType'];
  }
  if (consentInfoMetadata['additionalConsent']) {
    storageMetadata[METADATA_STORAGE_KEY.ADDITIONAL_CONSENT] =
      consentInfoMetadata['additionalConsent'];
  }
  if (consentInfoMetadata['gdprApplies'] != undefined) {
    storageMetadata[METADATA_STORAGE_KEY.GDPR_APPLIES] =
      consentInfoMetadata['gdprApplies'];
  }
  return storageMetadata;
}

/**
 * Converts stroage metadata to ConsentMetadataDef:
 * {'ga': true, 'cst': 2} =>
 * {'gdprApplies': true, 'additionalConsnet': undefined, 'consentStringType': 2}
 *
 * @param {Object|null|undefined} storageMetadata
 * @return {ConsentMetadataDef}
 */
export function convertStorageMetadata(storageMetadata) {
  if (!storageMetadata) {
    return constructMetadata();
  }
  return constructMetadata(
    storageMetadata[METADATA_STORAGE_KEY.CONSENT_STRING_TYPE],
    storageMetadata[METADATA_STORAGE_KEY.ADDITIONAL_CONSENT],
    storageMetadata[METADATA_STORAGE_KEY.GDPR_APPLIES]
  );
}

/**
 * Confirm that the metadata values are valid.
 * Remove and provide user error otherwise.
 * @param {JsonObject} metadata
 */
export function assertMetadataValues(metadata) {
  const consentStringType = metadata['consentStringType'];
  const additionalConsent = metadata['additionalConsent'];
  const gdprApplies = metadata['gdprApplies'];
  const errorFields = [];

  if (
    consentStringType &&
    !isEnumValue(CONSENT_STRING_TYPE, consentStringType)
  ) {
    delete metadata['consentStringType'];
    errorFields.push('consentStringType');
  }
  if (additionalConsent && typeof additionalConsent != 'string') {
    delete metadata['additionalConsent'];
    errorFields.push('additionalConsent');
  }
  if (gdprApplies && typeof gdprApplies != 'boolean') {
    delete metadata['gdprApplies'];
    errorFields.push('gdprApplies');
  }
  for (let i = 0; i < errorFields.length; i++) {
    user().error(
      TAG,
      'Consent metadata value "%s" is invalid.',
      errorFields[i]
    );
  }
}
<commit_msg>📖 Update gdprApplies Comment (#30166)<commit_after>/**
 * Copyright 2018 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {CONSENT_STRING_TYPE} from '../../../src/consent-state';
import {deepEquals} from '../../../src/json';
import {dev, user} from '../../../src/log';
import {hasOwn, map} from '../../../src/utils/object';
import {isEnumValue, isObject} from '../../../src/types';

const TAG = 'amp-consent';

/**
 * Key values for retriving/storing consent info object.
 * STATE: Set when user accept or reject consent.
 * STRING: Set when a consent string is used to store more granular consent info
 * on vendors.
 * METADATA: set when consent metadata is passed in to store more granular consent info
 * on vendors.
 * DITRYBIT: Set when the stored consent info need to be revoked next time.
 * @enum {string}
 */
export const STORAGE_KEY = {
  STATE: 's',
  STRING: 'r',
  IS_DIRTY: 'd',
  METADATA: 'm',
};

/**
 * Key values for retriving/storing metadata values within consent info
 * @enum {string}
 */
export const METADATA_STORAGE_KEY = {
  CONSENT_STRING_TYPE: 'cst',
  ADDITIONAL_CONSENT: 'ac',
  GDPR_APPLIES: 'ga',
};

/**
 * @enum {number}
 */
export const CONSENT_ITEM_STATE = {
  ACCEPTED: 1,
  REJECTED: 2,
  DISMISSED: 3,
  NOT_REQUIRED: 4,
  UNKNOWN: 5,
  // TODO(@zhouyx): Seperate UI state from consent state. Add consent
  // requirement state ui_state = {pending, active, complete} consent_state =
  // {unknown, accepted, rejected}
};

/**
 * @typedef {{
 *  consentState: CONSENT_ITEM_STATE,
 *  consentString: (string|undefined),
 *  consentMetadata: (ConsentMetadataDef|undefined),
 *  isDirty: (boolean|undefined),
 * }}
 */
export let ConsentInfoDef;

/**
 * Used in ConsentInfoDef
 * @typedef {{
 *  consentStringType: (CONSENT_STRING_TYPE|undefined),
 *  additionalConsent: (string|undefined),
 *  gdprApplies: (boolean|undefined),
 * }}
 */
export let ConsentMetadataDef;

/**
 * Convert the legacy storage value to Consent Info
 * @param {boolean|Object|undefined} value
 * @return {ConsentInfoDef}
 */
export function getStoredConsentInfo(value) {
  if (value === undefined) {
    return constructConsentInfo(
      CONSENT_ITEM_STATE.UNKNOWN,
      undefined,
      undefined,
      undefined
    );
  }
  if (typeof value === 'boolean') {
    // legacy format
    return getLegacyStoredConsentInfo(value);
  }
  if (!isObject(value)) {
    throw dev().createError('Invalid stored consent value');
  }

  const consentState = convertValueToState(value[STORAGE_KEY.STATE]);
  return constructConsentInfo(
    consentState,
    value[STORAGE_KEY.STRING],
    convertStorageMetadata(value[STORAGE_KEY.METADATA]),
    value[STORAGE_KEY.IS_DIRTY] && value[STORAGE_KEY.IS_DIRTY] === 1
  );
}

/**
 * Helper function to detect if stored consent has dirtyBit set
 * @param {?ConsentInfoDef} consentInfo
 * @return {boolean}
 */
export function hasDirtyBit(consentInfo) {
  if (!consentInfo) {
    return false;
  }
  if (hasOwn(consentInfo, 'isDirty') && consentInfo['isDirty'] == true) {
    return true;
  }
  return false;
}

/**
 * Return the new consent state value based on stored state and new state
 * @param {!CONSENT_ITEM_STATE} newState
 * @param {!CONSENT_ITEM_STATE} previousState
 * @return {!CONSENT_ITEM_STATE}
 */
export function recalculateConsentStateValue(newState, previousState) {
  if (!isEnumValue(CONSENT_ITEM_STATE, newState)) {
    newState = CONSENT_ITEM_STATE.UNKNOWN;
  }
  if (newState == CONSENT_ITEM_STATE.DISMISSED) {
    return previousState || CONSENT_ITEM_STATE.UNKNOWN;
  }
  if (newState == CONSENT_ITEM_STATE.NOT_REQUIRED) {
    if (previousState && previousState != CONSENT_ITEM_STATE.UNKNOWN) {
      return previousState;
    }
  }
  return newState;
}

/**
 * Compose the value to store to localStorage based on the consentInfo
 * @param {!ConsentInfoDef} consentInfo
 * @return {?boolean|Object}
 */
export function composeStoreValue(consentInfo) {
  const obj = map();
  const consentState = consentInfo['consentState'];
  if (consentState == CONSENT_ITEM_STATE.ACCEPTED) {
    obj[STORAGE_KEY.STATE] = 1;
  } else if (consentState == CONSENT_ITEM_STATE.REJECTED) {
    obj[STORAGE_KEY.STATE] = 0;
  } else {
    // Only store consentString and dirtyBit with reject/accept action
    return null;
  }

  if (consentInfo['consentString']) {
    obj[STORAGE_KEY.STRING] = consentInfo['consentString'];
  }

  if (consentInfo['isDirty'] === true) {
    obj[STORAGE_KEY.IS_DIRTY] = 1;
  }

  if (consentInfo['consentMetadata']) {
    obj[STORAGE_KEY.METADATA] = composeMetadataStoreValue(
      consentInfo['consentMetadata']
    );
  }

  if (Object.keys(obj) == 0) {
    return null;
  }

  return obj;
}

/**
 * Convert the consentState to legacy boolean stored value
 * @param {!CONSENT_ITEM_STATE} consentState
 * @return {?boolean}
 */
export function calculateLegacyStateValue(consentState) {
  if (consentState == CONSENT_ITEM_STATE.ACCEPTED) {
    return true;
  }
  if (consentState == CONSENT_ITEM_STATE.REJECTED) {
    return false;
  }
  return null;
}

/**
 * Compare two consentInfo.
 * Return true if they can be converted to the same stored value.
 * @param {?ConsentInfoDef} infoA
 * @param {?ConsentInfoDef} infoB
 * @param {boolean=} opt_isDirty
 * @return {boolean}
 */
export function isConsentInfoStoredValueSame(infoA, infoB, opt_isDirty) {
  if (!infoA && !infoB) {
    return true;
  }
  if (infoA && infoB) {
    const stateEqual =
      calculateLegacyStateValue(infoA['consentState']) ===
      calculateLegacyStateValue(infoB['consentState']);
    const stringEqual =
      (infoA['consentString'] || '') === (infoB['consentString'] || '');
    let isDirtyEqual;
    if (opt_isDirty) {
      isDirtyEqual = !!infoA['isDirty'] === !!opt_isDirty;
    } else {
      isDirtyEqual = !!infoA['isDirty'] === !!infoB['isDirty'];
    }
    const metadataEqual = deepEquals(
      infoA['consentMetadata'],
      infoB['consentMetadata']
    );
    return stateEqual && stringEqual && metadataEqual && isDirtyEqual;
  }
  return false;
}

/**
 * Convert the legacy boolean stored value to consentInfo object
 * @param {boolean} value
 * @return {!ConsentInfoDef}
 */
function getLegacyStoredConsentInfo(value) {
  const state = convertValueToState(value);
  return constructConsentInfo(state);
}

/**
 * Construct the consentInfo object from values
 *
 * @param {CONSENT_ITEM_STATE} consentState
 * @param {string=} opt_consentString
 * @param {ConsentMetadataDef=} opt_consentMetadata
 * @param {boolean=} opt_isDirty
 * @return {!ConsentInfoDef}
 */
export function constructConsentInfo(
  consentState,
  opt_consentString,
  opt_consentMetadata,
  opt_isDirty
) {
  return {
    'consentState': consentState,
    'consentString': opt_consentString,
    'consentMetadata': opt_consentMetadata,
    'isDirty': opt_isDirty,
  };
}

/**
 * Construct the consentMetadataDef object from values
 *
 * @param {CONSENT_STRING_TYPE=} opt_consentStringType
 * @param {string=} opt_additionalConsent
 * @param {boolean=} opt_gdprApplies
 * @return {!ConsentMetadataDef}
 */
export function constructMetadata(
  opt_consentStringType,
  opt_additionalConsent,
  opt_gdprApplies
) {
  return {
    'consentStringType': opt_consentStringType,
    'additionalConsent': opt_additionalConsent,
    'gdprApplies': opt_gdprApplies,
  };
}

/**
 * Helper function to convert stored value to CONSENT_ITEM_STATE value
 * @param {*} value
 * @return {!CONSENT_ITEM_STATE}
 */
export function convertValueToState(value) {
  if (value === true || value === 1) {
    return CONSENT_ITEM_STATE.ACCEPTED;
  } else if (value === false || value === 0) {
    return CONSENT_ITEM_STATE.REJECTED;
  }
  return CONSENT_ITEM_STATE.UNKNOWN;
}

/**
 * Helper function to convert response enum value to CONSENT_ITEM_STATE value
 * @param {*} value
 * @return {?CONSENT_ITEM_STATE}
 */
export function convertEnumValueToState(value) {
  if (value === 'accepted') {
    return CONSENT_ITEM_STATE.ACCEPTED;
  } else if (value === 'rejected') {
    return CONSENT_ITEM_STATE.REJECTED;
  } else if (value === 'unknown') {
    return CONSENT_ITEM_STATE.UNKNOWN;
  }
  return null;
}

/**
 *
 * @param {!ConsentInfoDef} info
 * @return {boolean}
 */
export function hasStoredValue(info) {
  if (info['consentString']) {
    return true;
  }
  return (
    info['consentState'] === CONSENT_ITEM_STATE.ACCEPTED ||
    info['consentState'] === CONSENT_ITEM_STATE.REJECTED
  );
}

/**
 * Convert the CONSENT_ITEM_STATE back to readable string
 * @param {!CONSENT_ITEM_STATE} enumState
 * @return {string}
 */
export function getConsentStateValue(enumState) {
  if (enumState === CONSENT_ITEM_STATE.ACCEPTED) {
    return 'accepted';
  }

  if (enumState === CONSENT_ITEM_STATE.REJECTED) {
    return 'rejected';
  }

  return 'unknown';
}

/**
 * Converts ConsentMetadataDef to stroage value:
 * {'gdprApplies': true, 'additionalConsent': undefined, 'consentStringType': 2} =>
 * {'ga': true, 'cst': 2}
 *
 * @param {ConsentMetadataDef=} consentInfoMetadata
 * @return {Object}
 */
export function composeMetadataStoreValue(consentInfoMetadata) {
  const storageMetadata = map();
  if (consentInfoMetadata['consentStringType']) {
    storageMetadata[METADATA_STORAGE_KEY.CONSENT_STRING_TYPE] =
      consentInfoMetadata['consentStringType'];
  }
  if (consentInfoMetadata['additionalConsent']) {
    storageMetadata[METADATA_STORAGE_KEY.ADDITIONAL_CONSENT] =
      consentInfoMetadata['additionalConsent'];
  }
  if (consentInfoMetadata['gdprApplies'] != undefined) {
    storageMetadata[METADATA_STORAGE_KEY.GDPR_APPLIES] =
      consentInfoMetadata['gdprApplies'];
  }
  return storageMetadata;
}

/**
 * Converts stroage metadata to ConsentMetadataDef:
 * {'ga': true, 'cst': 2} =>
 * {'gdprApplies': true, 'additionalConsnet': undefined, 'consentStringType': 2}
 *
 * @param {Object|null|undefined} storageMetadata
 * @return {ConsentMetadataDef}
 */
export function convertStorageMetadata(storageMetadata) {
  if (!storageMetadata) {
    return constructMetadata();
  }
  return constructMetadata(
    storageMetadata[METADATA_STORAGE_KEY.CONSENT_STRING_TYPE],
    storageMetadata[METADATA_STORAGE_KEY.ADDITIONAL_CONSENT],
    storageMetadata[METADATA_STORAGE_KEY.GDPR_APPLIES]
  );
}

/**
 * Confirm that the metadata values are valid.
 * Remove and provide user error otherwise.
 * @param {JsonObject} metadata
 */
export function assertMetadataValues(metadata) {
  const consentStringType = metadata['consentStringType'];
  const additionalConsent = metadata['additionalConsent'];
  const gdprApplies = metadata['gdprApplies'];
  const errorFields = [];

  if (
    consentStringType &&
    !isEnumValue(CONSENT_STRING_TYPE, consentStringType)
  ) {
    delete metadata['consentStringType'];
    errorFields.push('consentStringType');
  }
  if (additionalConsent && typeof additionalConsent != 'string') {
    delete metadata['additionalConsent'];
    errorFields.push('additionalConsent');
  }
  if (gdprApplies && typeof gdprApplies != 'boolean') {
    delete metadata['gdprApplies'];
    errorFields.push('gdprApplies');
  }
  for (let i = 0; i < errorFields.length; i++) {
    user().error(
      TAG,
      'Consent metadata value "%s" is invalid.',
      errorFields[i]
    );
  }
}
<|endoftext|>


<commit_before>var chai      = require('chai')
  , expect    = chai.expect
  , config    = require(__dirname + "/config/config")
  , Support   = require(__dirname + '/support')
  , dialect   = Support.getTestDialect()
  , Sequelize = require(__dirname + '/../index')

chai.config.includeStack = true

describe(Support.getTestDialectTeaser("Configuration"), function() {
  describe('Connections problems should fail with a nice message', function() {
    it("when we don't have the correct server details", function(done) {
      // mysql is not properly supported due to the custom pooling system
      if (dialect !== "postgres" && dialect !== "postgres-native") {
        console.log('This dialect doesn\'t support me :(')
        expect(true).to.be.true // Silence Buster
        return done()
      }

      var seq = new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {storage: '/path/to/no/where/land', logging: false, host: '0.0.0.1', port: config[dialect].port, dialect: dialect})
      return expect(seq.query('select 1 as hello')).to.eventually.be.rejectedWith(seq.InvalidConnectionError, 'connect EINVAL')
    })

    it('when we don\'t have the correct login information', function(done) {
      if (dialect !== "postgres" && dialect !== "postgres-native" && dialect !== "mysql") {
        console.log('This dialect doesn\'t support me :(')
        expect(true).to.be.true // Silence Buster
        return done()
      }

      var seq = new Sequelize(config[dialect].database, config[dialect].username, 'fakepass123', {logging: false, host: config[dialect].host, port: 1, dialect: dialect})
      return expect(seq.query('select 1 as hello')).to.eventually.be.rejectedWith(seq.ConnectionRefusedError, 'connect ECONNREFUSED')
    })

    it('when we don\'t have a valid dialect.', function(done) {
      expect(function() {
        new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {host: '0.0.0.1', port: config[dialect].port, dialect: undefined})
      }).to.throw(Error, 'The dialect undefined is not supported.')
      done()
    })
  })

  describe('Instantiation with a URL string', function() {
    it('should accept username, password, host, port, and database', function() {
      var sequelize = new Sequelize('mysql://user:pass@example.com:9821/dbname')
      var config = sequelize.config
      var options = sequelize.options

      expect(options.dialect).to.equal('mysql')

      expect(config.database).to.equal('dbname')
      expect(config.host).to.equal('example.com')
      expect(config.username).to.equal('user')
      expect(config.password).to.equal('pass')
      expect(config.port).to.equal('9821')
    })

    it('should work with no authentication options', function(done) {
      var sequelize = new Sequelize('mysql://example.com:9821/dbname')
      var config = sequelize.config

      expect(config.username).to.not.be.ok
      expect(config.password).to.be.null
      done()
    })

    it('should use the default port when no other is specified', function() {
      var sequelize = new Sequelize('dbname', 'root', 'pass', {
          dialect: dialect
        })
        , config = sequelize.config
        , port

      if (Support.dialectIsMySQL()) {
        port = 3306
      } else if (dialect === "postgres" || dialect === "postgres-native") {
        port = 5432
      } else {
        // sqlite has no concept of ports when connecting
        return
      }

      expect(config.port).to.equal(port)
    })
  })

  describe('Intantiation with arguments', function() {
    it('should accept two parameters (database, username)', function(done) {
      var sequelize = new Sequelize('dbname', 'root')
      var config = sequelize.config

      expect(config.database).to.equal('dbname')
      expect(config.username).to.equal('root')
      done()
    })

    it('should accept three parameters (database, username, password)', function(done) {
      var sequelize = new Sequelize('dbname', 'root', 'pass')
      var config = sequelize.config

      expect(config.database).to.equal('dbname')
      expect(config.username).to.equal('root')
      expect(config.password).to.equal('pass')
      done()
    })

    it('should accept four parameters (database, username, password, options)', function(done) {
      var sequelize = new Sequelize('dbname', 'root', 'pass', {
        port: 999,
        dialectOptions: {
          supportBigNumbers: true,
          bigNumberStrings: true
        }
      })
      var config = sequelize.config

      expect(config.database).to.equal('dbname')
      expect(config.username).to.equal('root')
      expect(config.password).to.equal('pass')
      expect(config.port).to.equal(999)
      expect(config.dialectOptions.supportBigNumbers).to.be.true
      expect(config.dialectOptions.bigNumberStrings).to.be.true
      done()
    })
  })

})
<commit_msg>Removed filters only allowing the tests to occur on Postgres and Postgres native to see if they are passing now.<commit_after>var chai      = require('chai')
  , expect    = chai.expect
  , config    = require(__dirname + "/config/config")
  , Support   = require(__dirname + '/support')
  , dialect   = Support.getTestDialect()
  , Sequelize = require(__dirname + '/../index')

chai.config.includeStack = true

describe(Support.getTestDialectTeaser("Configuration"), function() {
  describe('Connections problems should fail with a nice message', function() {
    it("when we don't have the correct server details", function(done) {
      var seq = new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {storage: '/path/to/no/where/land', logging: false, host: '0.0.0.1', port: config[dialect].port, dialect: dialect})
      return expect(seq.query('select 1 as hello')).to.eventually.be.rejectedWith(seq.InvalidConnectionError, 'connect EINVAL')
    })

    it('when we don\'t have the correct login information', function(done) {
      var seq = new Sequelize(config[dialect].database, config[dialect].username, 'fakepass123', {logging: false, host: config[dialect].host, port: 1, dialect: dialect})
      return expect(seq.query('select 1 as hello')).to.eventually.be.rejectedWith(seq.ConnectionRefusedError, 'connect ECONNREFUSED')
    })

    it('when we don\'t have a valid dialect.', function(done) {
      expect(function() {
        new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {host: '0.0.0.1', port: config[dialect].port, dialect: undefined})
      }).to.throw(Error, 'The dialect undefined is not supported.')
      done()
    })
  })

  describe('Instantiation with a URL string', function() {
    it('should accept username, password, host, port, and database', function() {
      var sequelize = new Sequelize('mysql://user:pass@example.com:9821/dbname')
      var config = sequelize.config
      var options = sequelize.options

      expect(options.dialect).to.equal('mysql')

      expect(config.database).to.equal('dbname')
      expect(config.host).to.equal('example.com')
      expect(config.username).to.equal('user')
      expect(config.password).to.equal('pass')
      expect(config.port).to.equal('9821')
    })

    it('should work with no authentication options', function(done) {
      var sequelize = new Sequelize('mysql://example.com:9821/dbname')
      var config = sequelize.config

      expect(config.username).to.not.be.ok
      expect(config.password).to.be.null
      done()
    })

    it('should use the default port when no other is specified', function() {
      var sequelize = new Sequelize('dbname', 'root', 'pass', {
          dialect: dialect
        })
        , config = sequelize.config
        , port

      if (Support.dialectIsMySQL()) {
        port = 3306
      } else if (dialect === "postgres" || dialect === "postgres-native") {
        port = 5432
      } else {
        // sqlite has no concept of ports when connecting
        return
      }

      expect(config.port).to.equal(port)
    })
  })

  describe('Intantiation with arguments', function() {
    it('should accept two parameters (database, username)', function(done) {
      var sequelize = new Sequelize('dbname', 'root')
      var config = sequelize.config

      expect(config.database).to.equal('dbname')
      expect(config.username).to.equal('root')
      done()
    })

    it('should accept three parameters (database, username, password)', function(done) {
      var sequelize = new Sequelize('dbname', 'root', 'pass')
      var config = sequelize.config

      expect(config.database).to.equal('dbname')
      expect(config.username).to.equal('root')
      expect(config.password).to.equal('pass')
      done()
    })

    it('should accept four parameters (database, username, password, options)', function(done) {
      var sequelize = new Sequelize('dbname', 'root', 'pass', {
        port: 999,
        dialectOptions: {
          supportBigNumbers: true,
          bigNumberStrings: true
        }
      })
      var config = sequelize.config

      expect(config.database).to.equal('dbname')
      expect(config.username).to.equal('root')
      expect(config.password).to.equal('pass')
      expect(config.port).to.equal(999)
      expect(config.dialectOptions.supportBigNumbers).to.be.true
      expect(config.dialectOptions.bigNumberStrings).to.be.true
      done()
    })
  })

})
<|endoftext|>


<commit_before>/**
 *
 */

VK.init({
    apiId: 1755175
});

var grp = '';
var us = '';
var grpAvatar = '';

var obj = [];
var parsed = [];

function getGroupInfo(groupId) {

    VK.api("groups.getById", { 'group_id': Math.abs(groupId), 'fields': 'members_count,photo_100' }, function (data) {
        console.log(data);
	for(var i=0;i<data.response.length;i++) {
	    grp = data.response[i].name;
	    us = data.response[i].members_count;
	    grpAvatar = data.response[i].photo_100;

	    obj[0] = grp;
	    obj[1] = us;
	    obj[2] = grpAvatar;

	    wait();
	}
    });
}
function getGroupData() {
    return obj;
}

function wait() {
    var a = getGroupData();
    document.getElementById('groupName').innerHTML = a[0];
    document.getElementById('members_count').innerHTML = a[1];
    document.getElementById('av').src = a[2];
    console.log('Done');
}

function parseLink() {
    var link = String(document.getElementById('post').value);

    if (link != '' && (link.match('vk.com')=='vk.com')) {
	var a = document.createElement('a');
	a.href = link;
	parsed[0] = a.search.split('=wall')[1].split('_')[0];
	parsed[1] = a.search.split('=wall')[1].split('_')[1];

	console.log(parsed[0], parsed[1], window.location.host);
	getGroupInfo(parsed[0]);

    }else{
	document.getElementById('post').value = 'Something goes wrong. Enter valid string. GL';
    }
}

function contain(str,what) {
    var s = str;

}

//'http://vk.com/darcor?w=wall-45091870_69859'
//  45091870 <commit_msg>changes<commit_after>/**
 *
 */

VK.init({
    apiId: 1755175
});

var grp = '';
var us = '';
var grpAvatar = '';

var obj = [];
var parsed = [];

function getGroupInfo(groupId) {

    VK.api("groups.getById", { 'group_id': Math.abs(groupId), 'fields': 'members_count,photo_100' }, function (data) {
        if (data.error) {
            return;
        }
	for(var i=0;i<data.response.length;i++) {
	    grp = data.response[i].name;
	    us = data.response[i].members_count;
	    grpAvatar = data.response[i].photo_100;

	    obj[0] = grp;
	    obj[1] = us;
	    obj[2] = grpAvatar;

	    wait();
	}
    });
}
function getGroupData() {
    return obj;
}

function wait() {
    var a = getGroupData();
    document.getElementById('groupName').innerHTML = a[0];
    document.getElementById('members_count').innerHTML = a[1];
    document.getElementById('av').src = a[2];
    console.log('Done');
}

function parseLink() {
    var link = String(document.getElementById('post').value);

    if (link != '' && (link.match('vk.com')=='vk.com') && (link.match('wall-')=='wall-')) {
	var a = document.createElement('a');
	a.href = link;
	parsed[0] = a.search.split('=wall')[1].split('_')[0];
	parsed[1] = a.search.split('=wall')[1].split('_')[1];

	console.log(parsed[0], parsed[1], window.location.host);
	getGroupInfo(parsed[0]);

    }else{
        document.getElementById('post').value = 'Something goes wrong. Enter valid string. GL';
        setTimeout(clearadress, 800);
    }
}

function clearadress() {
    document.getElementById('post').value = '';
}

function contain(str,what) {
    var s = str;

}

//'http://vk.com/darcor?w=wall-45091870_69859'
//  45091870 <|endoftext|>


<commit_before>/**
 *
 */

VK.init({
    apiId: 1755175
});

var WRONG_TEXT = 'Something goes wrong. Enter valid post address.';

var grp = '';
var us = '';
var grpAvatar = '';

var obj = [];
var parsed = [0,0];

function getGroupInfo(groupId) {

    VK.api("groups.getById", { 'group_id': Math.abs(groupId), 'fields': 'members_count,photo_100' }, function (data) {
        if (data.error) {
            errorMSG('Error in data. Wrong group data.')
        }else{
            for (var i = 0; i < data.response.length; i++) {
                grp = data.response[i].name;
                us = data.response[i].members_count;
                grpAvatar = data.response[i].photo_100;

                obj[0] = grp;
                obj[1] = us;
                obj[2] = grpAvatar;

            }
        }
	});

    groupViewChanges(getGroupData());
    waiting();//wait
    getGroupMembers(parsed);
}

function getGroupMembers(objTargets,memCount,offset) {
    var aboutPost = objTargets; // 0-group, 1-item_post
    var code = '';

    var manPos = []; //man
    var womanPos = []; //woman

    var bothSex = [];

    var code1 = 'var a=API.likes.getList({"type":"post","owner_id":"-10639516","item_id":"58333241","offset":0,"count":100}); return {"ids":a.items};';

    code = 'var c=0;var co=100;var p=[];var i=0;var o=0;var u=[];'+
        'while(i!=10) {var li=API.likes.getList({"type":"post","owner_id":'+aboutPost[0]+',"item_id":'+aboutPost[1]+',"filter":"likes","friends_only":0,"offset":o,"count":co});'+
        'c=li.count;u=u+API.users.get({"user_ids":li.items,"fields":"sex"})@.sex;i=i+1;o=o+co;}'+
        'return {"count":c,"user":u,"le":u.length};';

    VK.api('execute', { 'code': code1, }, function (data) {
        console.log(data);
        if (data.response.error) {
            errorMSG('Wrong: Group Member');
            console.log("error");
        } else {
            //group_members_count = data.response.count;
            bothSex = bothSex.concat(data.response.user);
            /*for (i = 0; i < bothSex.length; i++) {
                if (bothSex[i] == 1) {
                    manPos.push(i);
                } else {
                    womanPos.push(i);
                }
            }*/

            console.log(data,"bo l: "+bothSex.length, "bo arr: "+bothSex);
            console.log("m: " + manPos.length);
            console.log("w: " + womanPos.length);
        }
    });
}

function getGroupData() {
    return obj;
}

function getParsedInfo() {
    return parsed;
}

function waiting() {
    var se = 0;
    setTimeout(function () {
        if (s++ < 1) {
            waiting();
            console.log('wait');
        }
    }, 400);
}

    function groupViewChanges(obj) {
        var a = obj;
        document.getElementById('groupName').innerHTML = 'Name: '+a[0];
        document.getElementById('members_count').innerHTML = 'Count: '+a[1];
        document.getElementById('av').src = a[2];
    }

    function parseLink() {
        var link = String(document.getElementById('post').value);

        if (link != '' && (link.match('vk.com') == 'vk.com') && (link.match('wall-') == 'wall-')) {

            if (link.indexOf('=wall') != -1) {
                var adr = link.substring(link.indexOf('=wall') + 5, link.length);
                var p = adr.split('_');
                if ((p[0] === undefined) && (p[1] === undefined)) {
                    errorMSG('Wrong: group or post or both');
                } else {
                    if ((/\d+/.test(p[0])) && (/\d+/.test(p[1]))) {
                        parsed[0] = p[0]; parsed[1] = p[1];
                        getGroupInfo(parsed[0]);
                    }

                }
            } else {
                errorMSG('Wrong: not wall post');
            }
        }else{
            errorMSG('Wrong: not vk.com');
        }
    }

    function clearadress() {
        document.getElementById('post').value = '';
    }

    function errorMSG(msg) {
        document.getElementById('post').value = msg;
        setTimeout(clearadress, 1000);
    }
<commit_msg>changes<commit_after>/**
 *
 */

VK.init({
    apiId: 1755175
});

var WRONG_TEXT = 'Something goes wrong. Enter valid post address.';

var grp = '';
var us = '';
var grpAvatar = '';

var obj = [];
var parsed = [0,0];

function getGroupInfo(groupId) {

    VK.api("groups.getById", { 'group_id': Math.abs(groupId), 'fields': 'members_count,photo_100' }, function (data) {
        if (data.error) {
            errorMSG('Error in data. Wrong group data.')
        }else{
            for (var i = 0; i < data.response.length; i++) {
                grp = data.response[i].name;
                us = data.response[i].members_count;
                grpAvatar = data.response[i].photo_100;

                obj[0] = grp;
                obj[1] = us;
                obj[2] = grpAvatar;

            }
            groupViewChanges(getGroupData());
        }
	});

    waiting();//wait
    getGroupMembers(parsed);
}

function getGroupMembers(objTargets,memCount,offset) {
    var aboutPost = objTargets; // 0-group, 1-item_post
    var code = '';

    var manPos = []; //man
    var womanPos = []; //woman

    var bothSex = [];

    var code1 = 'var a=API.likes.getList({"type":"post","owner_id":"-10639516","item_id":"58333241","offset":0,"count":100}); return {"ids":a};';

    code = 'var c=0;var co=100;var p=[];var i=0;var o=0;var u=[];'+
        'while(i!=10) {var li=API.likes.getList({"type":"post","owner_id":'+aboutPost[0]+',"item_id":'+aboutPost[1]+',"filter":"likes","friends_only":0,"offset":o,"count":co});'+
        'c=li.count;u=u+API.users.get({"user_ids":li.items,"fields":"sex"})@.sex;i=i+1;o=o+co;}'+
        'return {"count":c,"user":u,"le":u.length};';

    VK.api('execute', { 'code': code1, }, function (data) {
        console.log(data);
        if (data.response.error) {
            errorMSG('Wrong: Group Member');
            console.log("error");
        } else {
            //group_members_count = data.response.count;
            bothSex = bothSex.concat(data.response.users);
            /*for (i = 0; i < bothSex.length; i++) {
                if (bothSex[i] == 1) {
                    manPos.push(i);
                } else {
                    womanPos.push(i);
                }
            }*/

            console.log("bo l: "+bothSex.length, "bo arr: "+bothSex);
            console.log("m: " + manPos.length);
            console.log("w: " + womanPos.length);
        }
    });
}

function getGroupData() {
    return obj;
}

function getParsedInfo() {
    return parsed;
}

function waiting() {
    var se = 0;
    setTimeout(function () {
        if (se++ < 1) {
            waiting();
            console.log('wait');
        }
    }, 400);
}

    function groupViewChanges(obj) {
        var a = obj;
        document.getElementById('groupName').innerHTML = 'Name: '+a[0];
        document.getElementById('members_count').innerHTML = 'Count: '+a[1];
        document.getElementById('av').src = a[2];
    }

    function parseLink() {
        var link = String(document.getElementById('post').value);

        if (link != '' && (link.match('vk.com') == 'vk.com') && (link.match('wall-') == 'wall-')) {

            if (link.indexOf('=wall') != -1) {
                var adr = link.substring(link.indexOf('=wall') + 5, link.length);
                var p = adr.split('_');
                if ((p[0] === undefined) && (p[1] === undefined)) {
                    errorMSG('Wrong: group or post or both');
                } else {
                    if ((/\d+/.test(p[0])) && (/\d+/.test(p[1]))) {
                        parsed[0] = p[0]; parsed[1] = p[1];
                        getGroupInfo(parsed[0]);
                    }

                }
            } else {
                errorMSG('Wrong: not wall post');
            }
        }else{
            errorMSG('Wrong: not vk.com');
        }
    }

    function clearadress() {
        document.getElementById('post').value = '';
    }

    function errorMSG(msg) {
        document.getElementById('post').value = msg;
        setTimeout(clearadress, 1000);
    }
<|endoftext|>