<commit_before>(function () {

    var Room = function () {
        // Set default values
        this.roomType = 'seed'; // Or 'branch', 'fake', 'boss'
        this.door = {};
        this.door.up = 'none';  // Or 'open', 'locked'
        this.door.down = 'none';
        this.door.left = 'none';
        this.door.right = 'none';
    };

    var Map = function () {
        this.canvas = document.getElementById('map');
        this.context = this.canvas.getContext('2d');

        // Declare static settings
        this.WIDTH = 600; // Ensure this matches width of canvas tag
        this.HEIGHT = 600; // Same
        this.NUM_ROOMS = 500;
        this.NUM_SEED_ROOMS = Math.ceil(this.NUM_ROOMS / 2) - 3;
        this.NUM_BRANCH_ROOMS = Math.floor(this.NUM_ROOMS / 2);
        this.ROOM_SIZE = 15;
        this.INNER_ROOM_SIZE = this.ROOM_SIZE / 2;
        this.NUM_ROWS = Math.floor(this.HEIGHT / this.ROOM_SIZE);
        this.NUM_COLUMNS = Math.floor(this.WIDTH / this.ROOM_SIZE);
        this.START_X = Math.floor(this.NUM_COLUMNS / 2);
        this.START_Y = Math.floor(this.NUM_ROWS / 2);
        this.START_ROOM_COLOR = '#88d800';
        this.DEFAULT_ROOM_COLOR = '#333333';
        this.END_ROOM_COLOR = '#b53120';
        this.BRANCH_ROOM_COLOR = '#FCB514';
        this.ROOM_BG = '#000000';

        // Make an empty array of arrays for rooms, then create starting rooms
        var grid = this.make2DGrid(this.NUM_ROWS, this.NUM_COLUMNS);
        var firstRoom = grid[this.START_X][this.START_Y - 1] = new Room(); // Create two rooms to start to start to
        var secondRoom = grid[this.START_X][this.START_Y - 2] = new Room(); // ensure that going up is always possible
        var zeroRoom = grid[this.START_X][this.START_Y] = new Room(); // Create a fake, inaccessible room to simulate
        zeroRoom.roomType = 'fake';                       // the dungeon entrance like Zelda

        // Keep track of where existing rooms are
        var existingRoomCoords = [[this.START_X, this.START_Y],
                [this.START_X, this.START_Y - 1],
                [this.START_X, this.START_Y - 2]];

        // Start generating rooms (subtract 3 to account for initial rooms)
        existingRoomCoords = this.makeRooms(grid, existingRoomCoords, [this.START_X, this.START_Y - 2], this.NUM_SEED_ROOMS);
        existingRoomCoords = this.makeBranches(grid, existingRoomCoords, this.NUM_BRANCH_ROOMS, []);

        this.draw(grid, existingRoomCoords, this.DEFAULT_ROOM_COLOR);
    };

    Map.prototype = {

        make2DGrid: function (numRows, numColumns) {
            var grid = [];

            while (numRows > 0) {
                grid.push([]);
                numRows = numRows - 1;
            }
            for (var i = 0; i < numRows; i++) {
                grid[i] = [];
                for (var j = 0; j < numColumns; j++) {
                    grid[i][j] = [];
                }
            }

            return grid;
        },

        makeRooms: function (grid, existingRoomCoords, coords, numRoomsRemaining) {
        // Walk a random path, generating rooms as you go.
            var nextRoomCoords;

            if (numRoomsRemaining < 1) {
                return existingRoomCoords;
            } else {
                nextRoomCoords = this.getRandomCoords(grid, existingRoomCoords, coords);
                grid[nextRoomCoords[0]][nextRoomCoords[1]] = new Room();
                existingRoomCoords.push([nextRoomCoords[0], nextRoomCoords[1]]);
                numRoomsRemaining = numRoomsRemaining - 1;

                return this.makeRooms(grid, existingRoomCoords, [nextRoomCoords[0], nextRoomCoords[1]], numRoomsRemaining);
            }
        },

        makeBranches: function (grid, existingRoomCoords, numRoomsRemaining, branches) {
        // Use branches to create locked areas on the map. Creating this after the seed
        // rooms ensures the map is always solvable. (Keys will be spawned in seed only.)
            var maxBranchLen = (numRoomsRemaining) > 8 ? 8 : (numRoomsRemaining), // 8 is an arbitrary maximum
                currentBranch = [],
                randStart,
                branchLen;

            if (numRoomsRemaining < 1) {
                return existingRoomCoords;
            } else {
                randStart = this.getRandomSeedCoords(grid, existingRoomCoords);
                branchLen = Math.ceil(Math.random() * maxBranchLen);
                this.makeRooms(grid, existingRoomCoords, randStart, branchLen);

                for (var i = 0; i < branchLen; i++) {
                    currentBranch.push(existingRoomCoords[existingRoomCoords.length - branchLen + i]);
                }
                if (branchLen > 0) {
                    this.lockBranch(grid, currentBranch);
                }
                return this.makeBranches(grid, existingRoomCoords, numRoomsRemaining - branchLen, branches);
            }

        },

        lockBranch: function (grid, branch) {
            var branchLen = branch.length,
                lockedDoorDir,
                x,
                y;

                for (var j = 0; j < branchLen; j++) {
                    x = branch[j][0];
                    y = branch[j][1];

                    if (branchLen < 2) { // Can't lock branches one room long
                        continue;
                        //grid[x][y].roomType = 'branch';
                    } else if (j === 0) {
                        lockedDoorDir = this.getDoorDirection(branch[j], branch[j + 1]);
                        grid[x][y].door[lockedDoorDir] = 'locked';

                        x = branch[j + 1][0];
                        y = branch[j + 1][1];
                        lockedDoorDir = this.getDoorDirection(branch[j + 1], branch[j]);
                        grid[x][y].door[lockedDoorDir] = 'locked';
                        grid[x][y].roomType = 'branch';
                    } else {
                        grid[x][y].roomType = 'branch';
                    }
                }

        },

        getDoorDirection: function (roomFrom, roomTo) {
            if (roomFrom[0] > roomTo[0]) {
                return 'left';
            } else if (roomFrom[0] < roomTo[0]) {
                return 'right';
            } else if (roomFrom[1] > roomTo[1]) {
                return 'up';
            } else if (roomFrom[1] < roomTo[1]) {
                return 'down';
            }
        },

        getRandomCoords: function (grid, existingRoomCoords, coords) {
            var adjCoords = this.getAdjacentCoords(coords[0], coords[1]),
                validCoords = this.getValidCoords(adjCoords),
                newCoords = this.getNewCoords(grid, validCoords);

            if (newCoords.length > 0) {
                return this.getRandomFromArray(newCoords);
            } else {
                return this.getRandomCoords(grid, existingRoomCoords, this.getRandomFromArray(existingRoomCoords));
                // Sometimes when walking you box yourself in and need to jump
                // to an existing room to keep going
            }
        },

        getRandomFromArray: function (arr) {
            var rand = arr[Math.floor(Math.random() * arr.length)];
            return rand;
        },

        getRandomSeedCoords: function (grid, existingCoords) {
            var randCoords = this.getRandomFromArray(existingCoords),
                isBranch = this.isBranch(grid, randCoords);

            if (!isBranch) {
                return randCoords;
            } else {
                return this.getRandomSeedCoords(grid, existingCoords);
            }
        },

        getAdjacentCoords: function (X, Y) {
            var adjCoords = [[X + 1, Y],
                [X - 1, Y],
                [X, Y + 1],
                [X, Y - 1]];

            return adjCoords;
        },

        getValidCoords: function (coords) {
            var coordsLen = coords.length,
                validCoords = [],
                x,
                y;

            for (var i = 0; i < coordsLen; i++) {
                x = coords[i][0];
                y = coords[i][1];

                if (x >= 0 && x < this.NUM_COLUMNS && y >= 0 && y < this.NUM_ROWS) {
                    validCoords.push(coords[i]);
                }
            }

            return validCoords;
        },

        getNewCoords: function (grid, coords) {
            var coordsLen = coords.length - 1,
                newCoords = [],
                isRoom;

            while (coordsLen >= 0) {
                isRoom = this.isRoom(grid, coords[coordsLen]);

                if (!isRoom) {
                    newCoords.push(coords[coordsLen]);
                }

                coordsLen = coordsLen - 1;
            }

            return newCoords;
        },

        isRoom: function (grid, coord) {
            if (typeof  grid[coord[0]][coord[1]] !== 'undefined') {
                return true;
            } else {
                return false;
            }
        },

        isBranch: function (grid, coords) {
            var x = coords[0],
                y = coords[1];

            if (grid[x][y].roomType === 'branch') {
                return true;
            } else {
                return false;
            }
        },

        draw: function (grid, existingRooms, colors) {
            var existingLen = existingRooms.length,
                roomType,
                roomColor;

            while (existingLen > 0) {
                existingLen = existingLen - 1;
                roomToDraw = existingRooms[existingLen];
                roomType =  grid[roomToDraw[0]][roomToDraw[1]].roomType

                if (roomType === 'seed') {
                    roomColor = this.DEFAULT_ROOM_COLOR;
                } else if (roomType === 'branch') {
                    roomColor = this.BRANCH_ROOM_COLOR;
                }
                this.drawRoom(grid, roomToDraw, roomColor);
            }
            this.drawRoom(grid, existingRooms[1], this.START_ROOM_COLOR);
        },

        drawRoom: function (grid, roomToDraw, roomColor) {
            var coords = this.convertRoomCoordsToPixels(roomToDraw),
                x = coords[0],
                y = coords[1],
                roomType = grid[roomToDraw[0]][roomToDraw[1]].roomType;

            this.context.fillStyle = this.ROOM_BG;
            this.context.fillRect (x, y, this.ROOM_SIZE, this.ROOM_SIZE);
            this.context.fillStyle = roomColor;

            this.context.fillRect (x + (this.ROOM_SIZE / 4),
                y + (this.ROOM_SIZE / 4),
                this.INNER_ROOM_SIZE,
                this.INNER_ROOM_SIZE);

            this.drawDoors(grid, roomToDraw);
        },

        drawDoors: function (grid, roomToDraw) {

            var roomDoors = grid[roomToDraw[0]][roomToDraw[1]].door,
                doorCoords = this.convertRoomCoordsToPixels(roomToDraw),
                x,
                y;

            for (var doorDir in roomDoors) {
                if (doorDir === 'up') {
                    x = doorCoords[0] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                    y = doorCoords[1];
                } else if (doorDir === 'down') {
                    x = doorCoords[0] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                    y = doorCoords[1] + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 2;
                } else if (doorDir === 'left') {
                    x = doorCoords[0];
                    y = doorCoords[1] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                } else if (doorDir === 'right') {
                    x = doorCoords[0] + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 2;
                    y = doorCoords[1] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                }

                if (roomDoors[doorDir] === 'locked') {
                    this.drawOneDoor([x, y], 'purple');
                } else if (roomDoors[doorDir] === 'open') {
                    this.drawOneDoor([x, y], 'white');
                }
            }
        },

        drawOneDoor: function (doorCoords, color) {
            var x = doorCoords[0],
                y = doorCoords[1],
                doorSize = this.ROOM_SIZE / 4;

            this.context.fillStyle = color;
            this.context.fillRect (x, y, doorSize, doorSize);

        },

        convertRoomCoordsToPixels: function (roomCoords) {
            var x = this.ROOM_SIZE * roomCoords[0];
            var y = this.ROOM_SIZE * roomCoords[1];

            return [x, y];
        }

    };
    window.onload = function () {
        new Map();
    };
})();
<commit_msg>Fix issue with discontinuous locked doors<commit_after>(function () {

    var Room = function () {
        // Set default values
        this.roomType = 'seed'; // Or 'branch', 'fake', 'boss'
        this.door = {};
        this.door.up = 'none';  // Or 'open', 'locked'
        this.door.down = 'none';
        this.door.left = 'none';
        this.door.right = 'none';
    };

    var Map = function () {
        this.canvas = document.getElementById('map');
        this.context = this.canvas.getContext('2d');

        // Declare static settings
        this.WIDTH = 600; // Ensure this matches width of canvas tag
        this.HEIGHT = 600; // Same
        this.NUM_ROOMS = 75;
        this.NUM_SEED_ROOMS = Math.ceil(this.NUM_ROOMS / 2) - 3;
        this.NUM_BRANCH_ROOMS = Math.floor(this.NUM_ROOMS / 2);
        this.ROOM_SIZE = 25;
        this.INNER_ROOM_SIZE = this.ROOM_SIZE / 2;
        this.NUM_ROWS = Math.floor(this.HEIGHT / this.ROOM_SIZE);
        this.NUM_COLUMNS = Math.floor(this.WIDTH / this.ROOM_SIZE);
        this.START_X = Math.floor(this.NUM_COLUMNS / 2);
        this.START_Y = Math.floor(this.NUM_ROWS / 2);
        this.START_ROOM_COLOR = '#88d800';
        this.DEFAULT_ROOM_COLOR = '#333333';
        this.END_ROOM_COLOR = '#b53120';
        this.BRANCH_ROOM_COLOR = '#FCB514';
        this.ROOM_BG = '#000000';

        // Make an empty array of arrays for rooms, then create starting rooms
        var grid = this.make2DGrid(this.NUM_ROWS, this.NUM_COLUMNS);
        var firstRoom = grid[this.START_X][this.START_Y - 1] = new Room(); // Create two rooms to start to start to
        var secondRoom = grid[this.START_X][this.START_Y - 2] = new Room(); // ensure that going up is always possible
        var zeroRoom = grid[this.START_X][this.START_Y] = new Room(); // Create a fake, inaccessible room to simulate
        zeroRoom.roomType = 'fake';                       // the dungeon entrance like Zelda

        // Keep track of where existing rooms are
        var existingRoomCoords = [[this.START_X, this.START_Y],
                [this.START_X, this.START_Y - 1],
                [this.START_X, this.START_Y - 2]];

        // Start generating rooms (subtract 3 to account for initial rooms)
        existingRoomCoords = this.makeRooms(grid, existingRoomCoords, [this.START_X, this.START_Y - 2], this.NUM_SEED_ROOMS);
        existingRoomCoords = this.makeBranches(grid, existingRoomCoords, this.NUM_BRANCH_ROOMS, []);

        this.draw(grid, existingRoomCoords, this.DEFAULT_ROOM_COLOR);
    };

    Map.prototype = {

        make2DGrid: function (numRows, numColumns) {
            var grid = [];

            while (numRows > 0) {
                grid.push([]);
                numRows = numRows - 1;
            }
            for (var i = 0; i < numRows; i++) {
                grid[i] = [];
                for (var j = 0; j < numColumns; j++) {
                    grid[i][j] = [];
                }
            }

            return grid;
        },

        makeRooms: function (grid, existingRoomCoords, coords, numRoomsRemaining) {
        // Walk a random path, generating rooms as you go.
            var nextRoomCoords;

            if (numRoomsRemaining < 1) {
                return existingRoomCoords;
            } else {
                nextRoomCoords = this.getRandomCoords(grid, existingRoomCoords, coords);
                grid[nextRoomCoords[0]][nextRoomCoords[1]] = new Room();
                existingRoomCoords.push([nextRoomCoords[0], nextRoomCoords[1]]);
                numRoomsRemaining = numRoomsRemaining - 1;

                return this.makeRooms(grid, existingRoomCoords, [nextRoomCoords[0], nextRoomCoords[1]], numRoomsRemaining);
            }
        },

        makeBranches: function (grid, existingRoomCoords, numRoomsRemaining, branches) {
        // Use branches to create locked areas on the map. Creating this after the seed
        // rooms ensures the map is always solvable. (Keys will be spawned in seed only.)
            var maxBranchLen = (numRoomsRemaining) > 8 ? 8 : (numRoomsRemaining), // 8 is an arbitrary maximum
                currentBranch = [],
                randStart,
                branchLen;

            if (numRoomsRemaining < 1) {
                return existingRoomCoords;
            } else {
                randStart = this.getRandomSeedCoords(grid, existingRoomCoords);
                branchLen = Math.ceil(Math.random() * maxBranchLen);
                this.makeRooms(grid, existingRoomCoords, randStart, branchLen);

                for (var i = 0; i < branchLen; i++) {
                    currentBranch.push(existingRoomCoords[existingRoomCoords.length - branchLen + i]);
                }
                if (branchLen > 0) {
                    this.lockBranch(grid, currentBranch);
                }
                return this.makeBranches(grid, existingRoomCoords, numRoomsRemaining - branchLen, branches);
            }

        },

        lockBranch: function (grid, branch) {
            var branchLen = branch.length,
                lockedDoorDir,
                x,
                y;

            for (var j = 0; j < branchLen; j++) {
                x = branch[j][0];
                y = branch[j][1];

                if (branchLen < 2) { // Can't lock branches one room long
                    continue;
                } else if (j === 0) {
                    lockedDoorDir = this.getDoorDirection(branch[j], branch[j + 1]);
                    if (lockedDoorDir !== 'none') {
                        grid[x][y].door[lockedDoorDir] = 'locked';
                    }

                    x = branch[j + 1][0];
                    y = branch[j + 1][1];
                    lockedDoorDir = this.getDoorDirection(branch[j + 1], branch[j]);
                    if (lockedDoorDir !== 'none') {
                        grid[x][y].door[lockedDoorDir] = 'locked';
                    }
                    grid[x][y].roomType = 'branch';
                } else {
                    grid[x][y].roomType = 'branch';
                }
            }
        },

        getDoorDirection: function (roomFrom, roomTo) {
            if (roomFrom[0] > roomTo[0] && roomFrom[1] === roomTo[1]) {
                return 'left';
            } else if (roomFrom[0] < roomTo[0] && roomFrom[1] === roomTo[1]) {
                return 'right';
            } else if (roomFrom[1] > roomTo[1] && roomFrom[0] === roomTo[0]) {
                return 'up';
            } else if (roomFrom[1] < roomTo[1] && roomFrom[0] === roomTo[0]) {
                return 'down';
            } else {
                return 'none';
            }
        },

        getRandomCoords: function (grid, existingRoomCoords, coords) {
            var adjCoords = this.getAdjacentCoords(coords[0], coords[1]),
                validCoords = this.getValidCoords(adjCoords),
                newCoords = this.getNewCoords(grid, validCoords);

            if (newCoords.length > 0) {
                return this.getRandomFromArray(newCoords);
            } else {
                return this.getRandomCoords(grid, existingRoomCoords, this.getRandomFromArray(existingRoomCoords));
                // Sometimes when walking you box yourself in and need to jump
                // to an existing room to keep going
            }
        },

        getRandomFromArray: function (arr) {
            var rand = arr[Math.floor(Math.random() * arr.length)];
            return rand;
        },

        getRandomSeedCoords: function (grid, existingCoords) {
            var randCoords = this.getRandomFromArray(existingCoords),
                isSeed = this.isSeed(grid, randCoords),
                isEdge = this.isEdge(grid, randCoords);

            if (isSeed && isEdge) {
                return randCoords;
            } else {
                return this.getRandomSeedCoords(grid, existingCoords);
            }
        },

        getAdjacentCoords: function (x, y) {
            var adjCoords = [[x + 1, y],
                [x - 1, y],
                [x, y + 1],
                [x, y - 1]];

            return adjCoords;
        },

        getValidCoords: function (coords) {
            var coordsLen = coords.length,
                validCoords = [],
                x,
                y;

            for (var i = 0; i < coordsLen; i++) {
                x = coords[i][0];
                y = coords[i][1];

                if (x >= 0 && x < this.NUM_COLUMNS && y >= 0 && y < this.NUM_ROWS) {
                    validCoords.push(coords[i]);
                }
            }

            return validCoords;
        },

        getNewCoords: function (grid, coords) {
            var coordsLen = coords.length - 1,
                newCoords = [],
                isRoom;

            while (coordsLen >= 0) {
                isRoom = this.isRoom(grid, coords[coordsLen]);

                if (!isRoom) {
                    newCoords.push(coords[coordsLen]);
                }

                coordsLen = coordsLen - 1;
            }

            return newCoords;
        },

        isRoom: function (grid, coord) {
            if (typeof  grid[coord[0]][coord[1]] !== 'undefined') {
                return true;
            } else {
                return false;
            }
        },

        isSeed: function (grid, coords) {
            var x = coords[0],
                y = coords[1];

            if (grid[x][y].roomType === 'seed') {
                return true;
            } else {
                return false;
            }
        },

        isEdge: function (grid, coords) {
            var x = coords[0],
                y = coords[1],
                adjCoords = this.getAdjacentCoords(x, y),
                validCoords = this.getValidCoords(adjCoords),
                newCoords = this.getNewCoords(grid, validCoords);

            if (newCoords.length > 0) {
                return true;
            } else {
                return false;
            }
        },

        draw: function (grid, existingRooms, colors) {
            var existingLen = existingRooms.length,
                roomType,
                roomColor;

            while (existingLen > 0) {
                existingLen = existingLen - 1;
                roomToDraw = existingRooms[existingLen];
                roomType =  grid[roomToDraw[0]][roomToDraw[1]].roomType

                if (roomType === 'seed') {
                    roomColor = this.DEFAULT_ROOM_COLOR;
                } else if (roomType === 'branch') {
                    roomColor = this.BRANCH_ROOM_COLOR;
                }
                this.drawRoom(grid, roomToDraw, roomColor);
            }
            this.drawRoom(grid, existingRooms[1], this.START_ROOM_COLOR);
        },

        drawRoom: function (grid, roomToDraw, roomColor) {
            var coords = this.convertRoomCoordsToPixels(roomToDraw),
                x = coords[0],
                y = coords[1],
                roomType = grid[roomToDraw[0]][roomToDraw[1]].roomType;

            this.context.fillStyle = this.ROOM_BG;
            this.context.fillRect (x, y, this.ROOM_SIZE, this.ROOM_SIZE);
            this.context.fillStyle = roomColor;

            this.context.fillRect (x + (this.ROOM_SIZE / 4),
                y + (this.ROOM_SIZE / 4),
                this.INNER_ROOM_SIZE,
                this.INNER_ROOM_SIZE);

            this.drawDoors(grid, roomToDraw);
        },

        drawDoors: function (grid, roomToDraw) {

            var roomDoors = grid[roomToDraw[0]][roomToDraw[1]].door,
                doorCoords = this.convertRoomCoordsToPixels(roomToDraw),
                x,
                y;

            for (var doorDir in roomDoors) {
                if (doorDir === 'up') {
                    x = doorCoords[0] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                    y = doorCoords[1];
                } else if (doorDir === 'down') {
                    x = doorCoords[0] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                    y = doorCoords[1] + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 2;
                } else if (doorDir === 'left') {
                    x = doorCoords[0];
                    y = doorCoords[1] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                } else if (doorDir === 'right') {
                    x = doorCoords[0] + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 2;
                    y = doorCoords[1] + 1 + this.ROOM_SIZE / 4 + this.ROOM_SIZE / 8;
                }

                if (roomDoors[doorDir] === 'locked') {
                    this.drawOneDoor([x, y], 'purple');
                } else if (roomDoors[doorDir] === 'open') {
                    this.drawOneDoor([x, y], 'white');
                }
            }
        },

        drawOneDoor: function (doorCoords, color) {
            var x = doorCoords[0],
                y = doorCoords[1],
                doorSize = this.ROOM_SIZE / 4;

            this.context.fillStyle = color;
            this.context.fillRect (x, y, doorSize, doorSize);

        },

        convertRoomCoordsToPixels: function (roomCoords) {
            var x = this.ROOM_SIZE * roomCoords[0];
            var y = this.ROOM_SIZE * roomCoords[1];

            return [x, y];
        }

    };
    window.onload = function () {
        new Map();
    };
})();
<|endoftext|>


<commit_before>/* eslint-env jest */

import moment from 'moment'
import logger from '../../../utils/logger'
import { getMockUserContext, mockDate } from '../../test-utils'
import getCause from '../../cause/getCause'
import { DatabaseItemDoesNotExistException } from '../../../utils/exceptions'

jest.mock('../../../utils/logger')
jest.mock('../../cause/getCause')

const userContext = getMockUserContext()

beforeAll(() => {
  mockDate.on()
})

afterAll(() => {
  mockDate.off()
})

beforeEach(() => {
  jest.clearAllMocks()
})

describe('setUserCause', () => {
  it('sets users cause ID', async () => {
    const UserModel = require('../UserModel').default
    const updateQuery = jest.spyOn(UserModel, 'update')
    const causeId = 'abcd'
    const setUserCause = require('../setUserCause').default
    await setUserCause(userContext, userContext.id, causeId)
    expect(updateQuery).toHaveBeenCalledWith(userContext, {
      id: userContext.id,
      causeId,
      updated: moment.utc().toISOString(),
    })
  })

  it('throws if cause doesnt exist', async () => {
    const error = new DatabaseItemDoesNotExistException()
    getCause.mockImplementationOnce(() => {
      throw error
    })
    const setUserCause = require('../setUserCause').default
    await expect(
      setUserCause(userContext, userContext.id, 'abcd')
    ).rejects.toThrow(error)
  })

  it('throws if calling the DB throws', async () => {
    const UserModel = require('../UserModel').default
    const causeId = 'abcd'
    const mockErr = new Error('No good.')
    jest.spyOn(UserModel, 'update').mockImplementationOnce(() => {
      throw mockErr
    })
    const setUserCause = require('../setUserCause').default
    await expect(
      setUserCause(userContext, userContext.id, causeId)
    ).rejects.toThrow(mockErr)
  })

  it('logs an error if calling the DB throws', async () => {
    const UserModel = require('../UserModel').default
    const causeId = 'abcd'
    const mockErr = new Error('No good.')
    jest.spyOn(UserModel, 'update').mockImplementationOnce(() => {
      throw mockErr
    })
    const setUserCause = require('../setUserCause').default

    try {
      await setUserCause(userContext, userContext.id, causeId)
    } catch (e) {} // eslint-disable-line no-empty
    expect(logger.error).toHaveBeenCalledWith(mockErr)
  })
})
<commit_msg>try adding assertion counts to fix timeout<commit_after>/* eslint-env jest */

import moment from 'moment'
import logger from '../../../utils/logger'
import { getMockUserContext, mockDate } from '../../test-utils'
import getCause from '../../cause/getCause'
import { DatabaseItemDoesNotExistException } from '../../../utils/exceptions'

jest.mock('../../../utils/logger')
jest.mock('../../cause/getCause')

const userContext = getMockUserContext()

beforeAll(() => {
  mockDate.on()
})

afterAll(() => {
  mockDate.off()
})

beforeEach(() => {
  jest.clearAllMocks()
})

describe('setUserCause', () => {
  it('sets users cause ID', async () => {
    expect.assertions(1)
    const UserModel = require('../UserModel').default
    const updateQuery = jest.spyOn(UserModel, 'update')
    const causeId = 'abcd'
    const setUserCause = require('../setUserCause').default
    await setUserCause(userContext, userContext.id, causeId)
    expect(updateQuery).toHaveBeenCalledWith(userContext, {
      id: userContext.id,
      causeId,
      updated: moment.utc().toISOString(),
    })
  })

  it('throws if cause doesnt exist', async () => {
    expect.assertions(1)
    const error = new DatabaseItemDoesNotExistException()
    getCause.mockImplementationOnce(() => {
      throw error
    })
    const setUserCause = require('../setUserCause').default
    await expect(
      setUserCause(userContext, userContext.id, 'abcd')
    ).rejects.toThrow(error)
  })

  it('throws if calling the DB throws', async () => {
    expect.assertions(1)
    const UserModel = require('../UserModel').default
    const causeId = 'abcd'
    const mockErr = new Error('No good.')
    jest.spyOn(UserModel, 'update').mockImplementationOnce(() => {
      throw mockErr
    })
    const setUserCause = require('../setUserCause').default
    await expect(
      setUserCause(userContext, userContext.id, causeId)
    ).rejects.toThrow(mockErr)
  })

  it('logs an error if calling the DB throws', async () => {
    expect.assertions(1)
    const UserModel = require('../UserModel').default
    const causeId = 'abcd'
    const mockErr = new Error('No good.')
    jest.spyOn(UserModel, 'update').mockImplementationOnce(() => {
      throw mockErr
    })
    const setUserCause = require('../setUserCause').default

    try {
      await setUserCause(userContext, userContext.id, causeId)
    } catch (e) {} // eslint-disable-line no-empty
    expect(logger.error).toHaveBeenCalledWith(mockErr)
  })
})
<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

/**
 * Provide the Topology class.
 *
 * @module topology
 */

YUI.add('juju-topology', function(Y) {
  var views = Y.namespace('juju.views'),
      models = Y.namespace('juju.models'),
      components = Y.namespace('d3-components'),
      d3 = Y.namespace('d3'),
      utils = Y.namespace('juju.topology.utils');

  /**
   * Topology models and renders the SVG of the envionment topology
   * with its associated behaviors.
   *
   * The line of where to put code (in the Topology vs a Module) is not 100%
   * clear. The rule of thumb to follow is that shared state, policy and
   * configuration belong here. If the only shared requirement on shared state
   * is watch/event like behavior, fire an event and place the logic in a
   * module.
   *
   * ## Emitted events:
   *
   * - zoom: When the zoom level of the canvas changes a 'zoom'
   *   event is fired. Analogous to d3's zoom event.
   *
   * @class Topology
   */
  var Topology = Y.Base.create('Topology', components.Component, [], {
    initializer: function(options) {
      this.options = Y.mix(options || {}, {
        minZoom: 0.25,
        maxZoom: 2,
        minSlider: 25,
        maxSlider: 200
      });
      Topology.superclass.constructor.apply(this, arguments);
      // Build a service.id -> BoundingBox map for services.
      this.service_boxes = {};
      this._subscriptions = [];
    },

    /**
     * Called by render, conditionally attach container to the DOM if
     * it isn't already. The framework calls this before module
     * rendering so that d3 Events will have attached DOM elements. If
     * your application doesn't need this behavior feel free to override.
     *
     * In this case we currently rely on app.showView to do all the
     * container management, this only works on a preserved view.
     *
     * @method attachContainer
     * @chainable
     */
    attachContainer: function() {
      return this;
    },

    /**
     * Remove container from DOM returning container. This
     * is explicitly not chainable.
     *
     * @method detachContainer
     */
    detachContainer: function() {
      return;
    },

    renderOnce: function() {
      var svg,
          vis,
          width = this.get('width'),
          height = this.get('height'),
          container = this.get('container'),
          templateName = this.options.template || 'overview';

      if (this._templateRendered) {
        return;
      }
      //container.setHTML(views.Templates[templateName]());
      // Take the first element.
      this._templateRendered = true;

      // These are defaults, a (Viewport) Module
      // can implement policy around them.
      this.computeScales();

      // Set up the visualization with a pack layout.
      var canvas = d3.select(container.getDOMNode());
      var base = canvas.select('.topology-canvas');
      if (base.empty()) {
        base = canvas.append('div')
              .classed('topology-canvas', true);
      }

      // Cache the canvas element for style modifications.
      this.set('canvas', container.one('.topology-canvas'));

      svg = base.append('svg:svg')
                .attr('width', width)
                .attr('height', height)
                .attr('class', 'the-canvas');
      this.svg = svg;

      this.zoomPlane = svg.append('rect')
                          .attr('class', 'zoom-plane')
                          .attr('width', width)
                          .attr('height', height)
                          .attr('pointer-events', 'all')
                          .call(this.zoom)
                          .on('dblclick.zoom', null);

      vis = svg.append('svg:g');
      this.vis = vis;

      // Only add the plus service block when requested, leaving it out of
      // the bundle details view.
      if (this.options.includePlus) {
        // Disable max-len, in order to maintain an easy way to paste in new
        // assets from design should they arrive.
        /*eslint-disable max-len*/
        vis.html('<g class="plus-service included-plus" transform="translate(0,0)">' +
            '<circle cx="64" cy="64" r="80" stroke="#888888" stroke-width="1" fill="transparent" stroke-dasharray="5, 5" class="plus-service__halo" id="yui_3_11_0_1_1444041610389_7098"></circle>' +
            '<path class="plus-service__inner-circle" fill="#FAFBFB" d="M63.5 126.5c-34.738 0-63-28.262-63-63s28.262-63 63-63 63 28.262 63 63-28.262 63-63 63z"/>' +
            '<path fill="#CECDCD" d="M63.5 1C97.962 1 126 29.038 126 63.5S97.962 126 63.5 126 1 97.962 1 63.5 29.038 1 63.5 1m0-1C28.43 0 0 28.43 0 63.5S28.43 127 63.5 127 127 98.57 127 63.5 98.57 0 63.5 0z"/>' +
            '<circle fill="#DC4A26" cx="63.5" cy="63.5" r="32.5"/>' +
            '<g fill="none" stroke="#FFF" stroke-width="2" stroke-miterlimit="10">' +
            '<path d="M63.5 54.5v18M72.5 63.5h-18"/>' +
            '</g>' +
            '</g>');
        /*eslint-enable max-len*/
        var plusIndicator = vis.select('.included-plus');
        var self = this;
        plusIndicator.on('click', function() {
          self.fire('changeState', {
            sectionC: {
              component: 'charmbrowser',
              metadata: {
                activeComponent: 'mid-point'
              }
            }
          });
        });
        var plusDrag = d3.behavior.drag()
          .on('drag', function(d) {
            var plus = d3.select(this);
            var oldCoords = plus.attr('transform')
              .split('(')[1]
              .split(')')[0]
              .split(',');
            plus
              .attr('transform',
                  'translate('
                    + [d3.event.dx + parseInt(oldCoords[0], 10),
                       d3.event.dy + parseInt(oldCoords[1], 10)] + ')');
          });
        plusIndicator.call(plusDrag);
      }

      Topology.superclass.renderOnce.apply(this, arguments);
      return this;
    },

    computeScales: function() {
      var self = this,
          width = this.get('width'),
          height = this.get('height');

      if (!this.xScale) {
        this.xScale = d3.scale.linear();
        this.yScale = d3.scale.linear();
        this.zoom = d3.behavior.zoom();
      }
      // Update the pan/zoom behavior manager.
      this.xScale.domain([-width / 2, width / 2])
        .range([0, width])
        .clamp(true)
        .nice();
      this.yScale.domain([-height / 2, height / 2])
        .range([height, 0])
        .clamp(true)
        .nice();

      this.zoom.x(this.xScale)
               .y(this.yScale)
               .scaleExtent([this.options.minZoom, this.options.maxZoom])
               .on('zoom', function(evt) {self.fire('zoom', d3.event);});
    },

    /*
     * Utility method to get a service object from the DB
     * given a BoundingBox.
     */
    serviceForBox: function(boundingBox) {
      var db = this.get('db');
      return db.services.getById(boundingBox.id);
    },

    /**
      Builds a coordinate which is outside of the current topology's service
      boxes. Include the optional includeVertices list of xy coordinates when
      calculating the resulting placement.

      @method servicePointOutside
      @param {Array} includeVertices Optional coordinates to be considered.
      @return {array} An x/y coordinate pair.
    */
    servicePointOutside: function(includeVertices) {
      // Existing service boxes are those with x/y attributes set.
      var existingBoxes = Y.Object.values(this.service_boxes)
        .filter(function(box) {
            return box.x !== undefined && !isNaN(box.center[0]);
          });
      // Find a point outside of the set of existing service boxes.
      var vertices = utils.serviceBoxesToVertices(existingBoxes);
      if (includeVertices && includeVertices.length) {
        includeVertices.forEach(function(item) {
          vertices.push(item);
        });
      }
      return utils.pointOutside(vertices, this.get('servicePadding'));
    },

    /**
     Show the menu for a given service

     @method showMenu
     @param {String} serviceId
    */
    showMenu: function(serviceId) {
      var serviceModule = this.modules.ServiceModule;
      if (!serviceModule) { return;}
      var boxModel = this.service_boxes[serviceId];
      serviceModule.showServiceMenu(boxModel);
    },

    /**
     Record a new box position on the backend. This maintains the proper drag
     state. This method also transitions the viewModel to a DRAG_ENDING state.

     @method annotateBoxPosition
     @param {Object} box.
    */
    annotateBoxPosition: function(box) {
      if (box.pending) { return; }
      this.get('env').update_annotations(
          box.id, 'service', {'gui-x': box.x, 'gui-y': box.y});
      box.inDrag = views.DRAG_ENDING;
    }

  }, {
    ATTRS: {
      /**
       * @property {Object} boundingBox
       * A bounding-box for all of the services
       */
      boundingBox: {},
      /**
       * @property {Y.Node} canvas
       */
      canvas: {},
      /**
       * @property {models.Database} db
       */
      db: {},
      /**
       * @property {utils.EnvironmentChangeSet} ecs
       */
      ecs: {},
      /**
       * @property {store.Environment} env
       */
      env: {},
      /**
       * @property {Array} size
       * A [width, height] tuple representing canvas size.
       */
      size: {value: [640, 480]},
      servicePadding: {value: 300},
      width: {
        getter: function() {return this.get('size')[0];}
      },

      height: {
        getter: function() {return this.get('size')[1];}
      },
      /*
        Scale and translate are managed by an external module
        (PanZoom in this case). If that module isn't
        loaded nothing will modify these values.
       */
      scale: {
        getter: function() {
          if (!this.zoom) { return 1.0;}
          return this.zoom.scale();},
        setter: function(v) {this.zoom.scale(v);}
      },

      translate: {
        getter: function() {
          if (!this.zoom) {return [0, 0]; }
          return this.zoom.translate();},
        setter: function(v) {this.zoom.translate(v);}
      }
    }

  });
  views.Topology = Topology;

  /*
   * Some additional flags used in dragging.
   */
  views.DRAG_START = 1;
  views.DRAG_ACTIVE = 2;
  views.DRAG_ENDING = 3;
}, '0.1.0', {
  requires: [
    'd3',
    'd3-components',
    'node',
    'event',
    'juju-templates',
    'juju-models',
    'juju-topology-service',
    'juju-topology-relation',
    'juju-topology-panzoom',
    'juju-topology-viewport',
    'juju-topology-utils'
  ]
});
<commit_msg>Stop the plus circle click event if it is being dragged.<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

/**
 * Provide the Topology class.
 *
 * @module topology
 */

YUI.add('juju-topology', function(Y) {
  var views = Y.namespace('juju.views'),
      models = Y.namespace('juju.models'),
      components = Y.namespace('d3-components'),
      d3 = Y.namespace('d3'),
      utils = Y.namespace('juju.topology.utils');

  /**
   * Topology models and renders the SVG of the envionment topology
   * with its associated behaviors.
   *
   * The line of where to put code (in the Topology vs a Module) is not 100%
   * clear. The rule of thumb to follow is that shared state, policy and
   * configuration belong here. If the only shared requirement on shared state
   * is watch/event like behavior, fire an event and place the logic in a
   * module.
   *
   * ## Emitted events:
   *
   * - zoom: When the zoom level of the canvas changes a 'zoom'
   *   event is fired. Analogous to d3's zoom event.
   *
   * @class Topology
   */
  var Topology = Y.Base.create('Topology', components.Component, [], {
    initializer: function(options) {
      this.options = Y.mix(options || {}, {
        minZoom: 0.25,
        maxZoom: 2,
        minSlider: 25,
        maxSlider: 200
      });
      Topology.superclass.constructor.apply(this, arguments);
      // Build a service.id -> BoundingBox map for services.
      this.service_boxes = {};
      this._subscriptions = [];
    },

    /**
     * Called by render, conditionally attach container to the DOM if
     * it isn't already. The framework calls this before module
     * rendering so that d3 Events will have attached DOM elements. If
     * your application doesn't need this behavior feel free to override.
     *
     * In this case we currently rely on app.showView to do all the
     * container management, this only works on a preserved view.
     *
     * @method attachContainer
     * @chainable
     */
    attachContainer: function() {
      return this;
    },

    /**
     * Remove container from DOM returning container. This
     * is explicitly not chainable.
     *
     * @method detachContainer
     */
    detachContainer: function() {
      return;
    },

    renderOnce: function() {
      var svg,
          vis,
          width = this.get('width'),
          height = this.get('height'),
          container = this.get('container'),
          templateName = this.options.template || 'overview';

      if (this._templateRendered) {
        return;
      }
      //container.setHTML(views.Templates[templateName]());
      // Take the first element.
      this._templateRendered = true;

      // These are defaults, a (Viewport) Module
      // can implement policy around them.
      this.computeScales();

      // Set up the visualization with a pack layout.
      var canvas = d3.select(container.getDOMNode());
      var base = canvas.select('.topology-canvas');
      if (base.empty()) {
        base = canvas.append('div')
              .classed('topology-canvas', true);
      }

      // Cache the canvas element for style modifications.
      this.set('canvas', container.one('.topology-canvas'));

      svg = base.append('svg:svg')
                .attr('width', width)
                .attr('height', height)
                .attr('class', 'the-canvas');
      this.svg = svg;

      this.zoomPlane = svg.append('rect')
                          .attr('class', 'zoom-plane')
                          .attr('width', width)
                          .attr('height', height)
                          .attr('pointer-events', 'all')
                          .call(this.zoom)
                          .on('dblclick.zoom', null);

      vis = svg.append('svg:g');
      this.vis = vis;

      // Only add the plus service block when requested, leaving it out of
      // the bundle details view.
      if (this.options.includePlus) {
        // Disable max-len, in order to maintain an easy way to paste in new
        // assets from design should they arrive.
        /*eslint-disable max-len*/
        vis.html('<g class="plus-service included-plus" transform="translate(0,0)">' +
            '<circle cx="64" cy="64" r="80" stroke="#888888" stroke-width="1" fill="transparent" stroke-dasharray="5, 5" class="plus-service__halo" id="yui_3_11_0_1_1444041610389_7098"></circle>' +
            '<path class="plus-service__inner-circle" fill="#FAFBFB" d="M63.5 126.5c-34.738 0-63-28.262-63-63s28.262-63 63-63 63 28.262 63 63-28.262 63-63 63z"/>' +
            '<path fill="#CECDCD" d="M63.5 1C97.962 1 126 29.038 126 63.5S97.962 126 63.5 126 1 97.962 1 63.5 29.038 1 63.5 1m0-1C28.43 0 0 28.43 0 63.5S28.43 127 63.5 127 127 98.57 127 63.5 98.57 0 63.5 0z"/>' +
            '<circle fill="#DC4A26" cx="63.5" cy="63.5" r="32.5"/>' +
            '<g fill="none" stroke="#FFF" stroke-width="2" stroke-miterlimit="10">' +
            '<path d="M63.5 54.5v18M72.5 63.5h-18"/>' +
            '</g>' +
            '</g>');
        /*eslint-enable max-len*/
        var plusIndicator = vis.select('.included-plus');
        var self = this;
        plusIndicator.on('click', function() {
          if (d3.event.defaultPrevented) {
            // Don't allow the click if the element is being dragged.
            return;
          }
          self.fire('changeState', {
            sectionC: {
              component: 'charmbrowser',
              metadata: {
                activeComponent: 'mid-point'
              }
            }
          });
        });
        var plusDrag = d3.behavior.drag()
          .on('drag', function(d) {
            var plus = d3.select(this);
            var oldCoords = plus.attr('transform')
              .split('(')[1]
              .split(')')[0]
              .split(',');
            plus
              .attr('transform',
                  'translate('
                    + [d3.event.dx + parseInt(oldCoords[0], 10),
                       d3.event.dy + parseInt(oldCoords[1], 10)] + ')');
          });
        plusIndicator.call(plusDrag);
      }

      Topology.superclass.renderOnce.apply(this, arguments);
      return this;
    },

    computeScales: function() {
      var self = this,
          width = this.get('width'),
          height = this.get('height');

      if (!this.xScale) {
        this.xScale = d3.scale.linear();
        this.yScale = d3.scale.linear();
        this.zoom = d3.behavior.zoom();
      }
      // Update the pan/zoom behavior manager.
      this.xScale.domain([-width / 2, width / 2])
        .range([0, width])
        .clamp(true)
        .nice();
      this.yScale.domain([-height / 2, height / 2])
        .range([height, 0])
        .clamp(true)
        .nice();

      this.zoom.x(this.xScale)
               .y(this.yScale)
               .scaleExtent([this.options.minZoom, this.options.maxZoom])
               .on('zoom', function(evt) {self.fire('zoom', d3.event);});
    },

    /*
     * Utility method to get a service object from the DB
     * given a BoundingBox.
     */
    serviceForBox: function(boundingBox) {
      var db = this.get('db');
      return db.services.getById(boundingBox.id);
    },

    /**
      Builds a coordinate which is outside of the current topology's service
      boxes. Include the optional includeVertices list of xy coordinates when
      calculating the resulting placement.

      @method servicePointOutside
      @param {Array} includeVertices Optional coordinates to be considered.
      @return {array} An x/y coordinate pair.
    */
    servicePointOutside: function(includeVertices) {
      // Existing service boxes are those with x/y attributes set.
      var existingBoxes = Y.Object.values(this.service_boxes)
        .filter(function(box) {
            return box.x !== undefined && !isNaN(box.center[0]);
          });
      // Find a point outside of the set of existing service boxes.
      var vertices = utils.serviceBoxesToVertices(existingBoxes);
      if (includeVertices && includeVertices.length) {
        includeVertices.forEach(function(item) {
          vertices.push(item);
        });
      }
      return utils.pointOutside(vertices, this.get('servicePadding'));
    },

    /**
     Show the menu for a given service

     @method showMenu
     @param {String} serviceId
    */
    showMenu: function(serviceId) {
      var serviceModule = this.modules.ServiceModule;
      if (!serviceModule) { return;}
      var boxModel = this.service_boxes[serviceId];
      serviceModule.showServiceMenu(boxModel);
    },

    /**
     Record a new box position on the backend. This maintains the proper drag
     state. This method also transitions the viewModel to a DRAG_ENDING state.

     @method annotateBoxPosition
     @param {Object} box.
    */
    annotateBoxPosition: function(box) {
      if (box.pending) { return; }
      this.get('env').update_annotations(
          box.id, 'service', {'gui-x': box.x, 'gui-y': box.y});
      box.inDrag = views.DRAG_ENDING;
    }

  }, {
    ATTRS: {
      /**
       * @property {Object} boundingBox
       * A bounding-box for all of the services
       */
      boundingBox: {},
      /**
       * @property {Y.Node} canvas
       */
      canvas: {},
      /**
       * @property {models.Database} db
       */
      db: {},
      /**
       * @property {utils.EnvironmentChangeSet} ecs
       */
      ecs: {},
      /**
       * @property {store.Environment} env
       */
      env: {},
      /**
       * @property {Array} size
       * A [width, height] tuple representing canvas size.
       */
      size: {value: [640, 480]},
      servicePadding: {value: 300},
      width: {
        getter: function() {return this.get('size')[0];}
      },

      height: {
        getter: function() {return this.get('size')[1];}
      },
      /*
        Scale and translate are managed by an external module
        (PanZoom in this case). If that module isn't
        loaded nothing will modify these values.
       */
      scale: {
        getter: function() {
          if (!this.zoom) { return 1.0;}
          return this.zoom.scale();},
        setter: function(v) {this.zoom.scale(v);}
      },

      translate: {
        getter: function() {
          if (!this.zoom) {return [0, 0]; }
          return this.zoom.translate();},
        setter: function(v) {this.zoom.translate(v);}
      }
    }

  });
  views.Topology = Topology;

  /*
   * Some additional flags used in dragging.
   */
  views.DRAG_START = 1;
  views.DRAG_ACTIVE = 2;
  views.DRAG_ENDING = 3;
}, '0.1.0', {
  requires: [
    'd3',
    'd3-components',
    'node',
    'event',
    'juju-templates',
    'juju-models',
    'juju-topology-service',
    'juju-topology-relation',
    'juju-topology-panzoom',
    'juju-topology-viewport',
    'juju-topology-utils'
  ]
});
<|endoftext|>


<commit_before>describe('MapInfowindow', function () {
  describe('leaflet', function() {
    GroupLayerSpecs(cdb.admin.LeafletMapView);
  });

  function GroupLayerSpecs(mapViewClass) {
    beforeEach(function () {
      base = new cdb.geo.TileLayer({ urlTemplate: 'test' });
      layer1 = new cdb.admin.CartoDBLayer({ tile_style: 'test1', query: 'sql1', interactivity: 'int1', visible: true});
      layer2 = new cdb.admin.CartoDBLayer({ tile_style: 'test2', query: 'sql2', interactivity: 'int2', visible: true});
      var map = new cdb.admin.Map();
      mapView = new mapViewClass({ map: map, user: new cdb.admin.User() });

      model = new cdb.geo.ui.InfowindowModel({
        fields: [{ name: 'name1', title: true, position: 0, length: 4 }]
      });

      table = new cdb.admin.CartoDBTableMetadata({
        name: 'testTable',
        schema: [
          ['name1', 'string'],
          ['name2', 'number'],
          ['name3', 'number']
        ]
      });

      this.view = new cdb.admin.MapInfowindow({
        model: model,
        mapView: mapView,
        table: table
      });

      this.view.row = {
        attributes: {
          name: 'caracola',
          length: 4
        }
      };

      spyOn(this.view, 'setLoading');
      this.view.renderInfo();
    });

    it('should update the model with fields blabla (explain better what are the side-effects calling renderInfo', function () {
      expect(this.view.model.get('content').fields).toContain('name');
      expect(this.view.model.get('content').fields).toContain('length');
    });

    it('should not set loading', function () {
      expect(this.view.setLoading).not.toHaveBeenCalled();
    });
  }
});
<commit_msg>MapInfowindow tests<commit_after>describe('MapInfowindow', function () {
  describe('leaflet', function () {
    GroupLayerSpecs(cdb.admin.LeafletMapView);
  });

  function GroupLayerSpecs (MapViewClass) {
    beforeEach(function () {
      var map = new cdb.admin.Map();
      var mapView = new MapViewClass({ map: map, user: new cdb.admin.User() });

      var model = new cdb.geo.ui.InfowindowModel({
        fields: [{ name: 'name', title: true, position: 0 }, { name: 'length', position: 1, title: true }]
      });

      var table = new cdb.admin.CartoDBTableMetadata({
        name: 'testTable',
        schema: [
          ['name', 'lorem ipsum'],
          ['description', 'dolor sit amet'],
          ['length', 4]
        ]
      });

      this.view = new cdb.admin.MapInfowindow({
        model: model,
        mapView: mapView,
        table: table
      });

      this.view.row = {
        attributes: {
          name: 'lorem ipsum',
          length: 4
        }
      };

      spyOn(this.view, 'setLoading');
      this.view.renderInfo();
    });

    it('should update the model with fields including the length one', function () {
      expect(this.view.model.get('fields')[0]['name']).toContain('name');
      expect(this.view.model.get('fields')[1]['name']).toContain('length');
    });

    it('should not set loading', function () {
      expect(this.view.setLoading).not.toHaveBeenCalled();
    });
  }
});
<|endoftext|>


<commit_before>	var M = {};
	M.init = function(){
		M.etsy.init();
		$('#etsy .more').tappable(function(){
			M.etsy.more();
		});

		M.write.get();
		$('#write .more').tappable(function(){
			M.write.get();
		});

		$('.home').tappable(function(){
			M.nav.home();
		});

		$('[show]:not(.prep)').addClass('prep').tappable(function(){
		var show = $(this).attr('show');
		router.navigate('/'+show);
		$('[show].act').removeClass('act');
		$('[show='+show+']').addClass('act');
		});
	}

	M.etsy = {};
	M.etsy.items = {};
	M.etsy.page = 0;
	M.etsy.limit = 25;
	M.etsy.isMore = true;
	M.etsy.get = function(){
		if ( M.etsy.isMore ){
			limit = M.etsy.limit;
			var offset = M.etsy.page*limit;
			var url = 'http://openapi.etsy.com/v2/shops/catandglove/listings/active.js?callback=getData&api_key=3lrt6kdjs0ppzxvxj1ypo0m4&includes=Images&limit='+limit+'&order=date_desc&offset='+offset;

			$.ajax({
			url:url,
			dataType: 'jsonp'
			}).done(function(data){
				if (data.ok){
				M.etsy.page++;
				var count = 0;
					for (x in data.results)
					{
						count++;
						var result = data.results[x];
						M.etsy.items[result.listing_id] = result;
					}
					if ( count < limit ) { M.etsy.isMore = false;}
					M.etsy.render();
				}
				else
				{

				}
			});
		}
	}

	M.etsy.hideMoreButton = function (){
		$('#etsy .more').hide();
	}

	M.etsy.showMoreButton = function (){
		$('#etsy .more').show();
	}

	M.etsy.render = function(){
		var itemTemp = '

{{{title}}}

';
		var etsyHTML = [];

		for (x in M.etsy.items){
			var result = M.etsy.items[x];
			if (result.rendered == undefined){
				result.image = result.Images[0]['url_570xN'];
				etsyHTML.push(Mustache.render(itemTemp, result));
				M.etsy.items[x]['rendered'] = true;
			}
		}

		var loadHTML = function(){
			if (etsyHTML.length > 0)
			{
				var $item = $(etsyHTML.pop());
				$('#etsy .items').append($item);
				$item.hide().fadeIn(1000);
				setTimeout(loadHTML, 100);
			}
			else
			{
				if ( M.etsy.isMore ){
					M.etsy.showMoreButton();
				}
				else
				{
					M.etsy.hideMoreButton();
				}
			}
		}
		loadHTML();
	}

	M.etsy.init = M.etsy.get;
	M.etsy.more = M.etsy.get;

	M.wp = {};
M.wp.category = '';
M.wp.items = {};
M.wp.page = 1;
M.wp.limit = 25;
M.wp.isMore = true;

M.wp.get = function(){
	if ( this.isMore ){
		var wp = this;
		url = '/press?json=get_category_posts&category_slug='+this.category+'&count='+this.limit+'&page='+this.page;
		$.get(url).
		done( function( data ){
			if ( data.status == 'ok' ){
				wp.page++;
				var count = 0;
				for ( x in data.posts ){
					count++;
					var result = data.posts[x];
					wp.items[result['slug']] = result;
				}
				if ( count < wp.limit ) { wp.isMore = false;}
			}
			wp.render();
		})
	}
}

M.write = M.wp;
M.write.category = 'write';
M.write.showMoreButton = function(){
	$('#write .more').show();
};
M.write.hideMoreButton = function(){
	$('#write .more').hide();
};
M.write.render = function(){
	var itemTemp = '

{{{title}}}
{{{content}}}

';
	var writeHTML = [];

	for (x in this.items){
		var result = this.items[x];
		if (result.rendered == undefined){
			//result.image = result.Images[0]['url_570xN'];
			writeHTML.push(Mustache.render(itemTemp, result));
			this.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (writeHTML.length > 0)
		{
			var $item = $(writeHTML.pop());
			$('#write .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			if ( M.write.isMore ){
				M.write.showMoreButton();
			}
			else
			{
				M.write.hideMoreButton();
			}
		}
	}
	loadHTML();
}

M.nav = {};
M.nav.home = function () {
	router.navigate('/');
}

M.nav.makeActive = function ($id){
	if ( !$id.hasClass('twelve') ){
		var id = $id.attr('id');
		$('[show]').removeClass('act');
		$('[show='+id+']').addClass('act');
		$('.content>.twelve').removeClass('twelve').addClass('four');
		$('.hidden').removeClass('hidden');
		$('#etsy, #write, #art').addClass('hidden');
		$id.removeClass('hidden').removeClass('four').addClass('twelve');
	}
}

M.nav.removeActive = function($id){
$('#etsy, #write, #art').removeClass('hidden');
$('.content>.twelve').removeClass('twelve').addClass('four');
}

M.nav.pageByID = function(type, id){

	if ( M[type]['items'][id] != undefined )
	{
		var data = M[type]['items'][id];
		M[type]['renderItem']( data );
		console.log(data.title);
	}
	else
	{
		M[type]['getSingle'](id);
	}
}

var router = new Router();

router.route('/', function(){
	M.nav.removeActive();
});

router.route('/etsy', function(){
	M.nav.makeActive($('#etsy'));
});

router.route('/etsy/:id', function(id){
	M.nav.pageByID('etsy', id);
});

router.route('/write', function(){
	M.nav.makeActive($('#write'));
});

router.route('/write/:id', function(id){
	M.nav.pageByID('write', id);
});

router.route('/art', function(){
	M.nav.makeActive($('#art'));
});

router.route('/art/:id', function(id){
	M.nav.pageByID('art', id);
});

<commit_msg>autonav to etsy for mobile devices<commit_after>	var M = {};
	M.init = function(){
		M.etsy.init();
		$('#etsy .more').tappable(function(){
			M.etsy.more();
		});

		M.write.get();
		$('#write .more').tappable(function(){
			M.write.get();
		});

		$('.home').tappable(function(){
			M.nav.home();
		});

		if ( $('.mobNav').css('display') == 'block' ){
			router.navigate('/etsy');
		}

		$('[show]:not(.prep)').addClass('prep').tappable(function(){
			var show = $(this).attr('show');
			router.navigate('/'+show);
			$('[show].act').removeClass('act');
			$('[show='+show+']').addClass('act');
		});
	}

	M.etsy = {};
	M.etsy.items = {};
	M.etsy.page = 0;
	M.etsy.limit = 25;
	M.etsy.isMore = true;
	M.etsy.get = function(){
		if ( M.etsy.isMore ){
			limit = M.etsy.limit;
			var offset = M.etsy.page*limit;
			var url = 'http://openapi.etsy.com/v2/shops/catandglove/listings/active.js?callback=getData&api_key=3lrt6kdjs0ppzxvxj1ypo0m4&includes=Images&limit='+limit+'&order=date_desc&offset='+offset;

			$.ajax({
			url:url,
			dataType: 'jsonp'
			}).done(function(data){
				if (data.ok){
				M.etsy.page++;
				var count = 0;
					for (x in data.results)
					{
						count++;
						var result = data.results[x];
						M.etsy.items[result.listing_id] = result;
					}
					if ( count < limit ) { M.etsy.isMore = false;}
					M.etsy.render();
				}
				else
				{

				}
			});
		}
	}

	M.etsy.hideMoreButton = function (){
		$('#etsy .more').hide();
	}

	M.etsy.showMoreButton = function (){
		$('#etsy .more').show();
	}

	M.etsy.render = function(){
		var itemTemp = '

{{{title}}}

';
		var etsyHTML = [];

		for (x in M.etsy.items){
			var result = M.etsy.items[x];
			if (result.rendered == undefined){
				result.image = result.Images[0]['url_570xN'];
				etsyHTML.push(Mustache.render(itemTemp, result));
				M.etsy.items[x]['rendered'] = true;
			}
		}

		var loadHTML = function(){
			if (etsyHTML.length > 0)
			{
				var $item = $(etsyHTML.pop());
				$('#etsy .items').append($item);
				$item.hide().fadeIn(1000);
				setTimeout(loadHTML, 100);
			}
			else
			{
				if ( M.etsy.isMore ){
					M.etsy.showMoreButton();
				}
				else
				{
					M.etsy.hideMoreButton();
				}
			}
		}
		loadHTML();
	}

	M.etsy.init = M.etsy.get;
	M.etsy.more = M.etsy.get;

	M.wp = {};
M.wp.category = '';
M.wp.items = {};
M.wp.page = 1;
M.wp.limit = 25;
M.wp.isMore = true;

M.wp.get = function(){
	if ( this.isMore ){
		var wp = this;
		url = '/press?json=get_category_posts&category_slug='+this.category+'&count='+this.limit+'&page='+this.page;
		$.get(url).
		done( function( data ){
			if ( data.status == 'ok' ){
				wp.page++;
				var count = 0;
				for ( x in data.posts ){
					count++;
					var result = data.posts[x];
					wp.items[result['slug']] = result;
				}
				if ( count < wp.limit ) { wp.isMore = false;}
			}
			wp.render();
		})
	}
}

M.write = M.wp;
M.write.category = 'write';
M.write.showMoreButton = function(){
	$('#write .more').show();
};
M.write.hideMoreButton = function(){
	$('#write .more').hide();
};
M.write.render = function(){
	var itemTemp = '

{{{title}}}
{{{content}}}

';
	var writeHTML = [];

	for (x in this.items){
		var result = this.items[x];
		if (result.rendered == undefined){
			//result.image = result.Images[0]['url_570xN'];
			writeHTML.push(Mustache.render(itemTemp, result));
			this.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (writeHTML.length > 0)
		{
			var $item = $(writeHTML.pop());
			$('#write .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			if ( M.write.isMore ){
				M.write.showMoreButton();
			}
			else
			{
				M.write.hideMoreButton();
			}
		}
	}
	loadHTML();
}

M.nav = {};
M.nav.home = function () {
	router.navigate('/');
}

M.nav.makeActive = function ($id){
	if ( !$id.hasClass('twelve') ){
		var id = $id.attr('id');
		$('[show]').removeClass('act');
		$('[show='+id+']').addClass('act');
		$('.content>.twelve').removeClass('twelve').addClass('four');
		$('.hidden').removeClass('hidden');
		$('#etsy, #write, #art').addClass('hidden');
		$id.removeClass('hidden').removeClass('four').addClass('twelve');
	}
}

M.nav.removeActive = function($id){
$('#etsy, #write, #art').removeClass('hidden');
$('.content>.twelve').removeClass('twelve').addClass('four');
}

M.nav.pageByID = function(type, id){

	if ( M[type]['items'][id] != undefined )
	{
		var data = M[type]['items'][id];
		M[type]['renderItem']( data );
		console.log(data.title);
	}
	else
	{
		M[type]['getSingle'](id);
	}
}

var router = new Router();

router.route('/', function(){
	M.nav.removeActive();
});

router.route('/etsy', function(){
	M.nav.makeActive($('#etsy'));
});

router.route('/etsy/:id', function(id){
	M.nav.pageByID('etsy', id);
});

router.route('/write', function(){
	M.nav.makeActive($('#write'));
});

router.route('/write/:id', function(id){
	M.nav.pageByID('write', id);
});

router.route('/art', function(){
	M.nav.makeActive($('#art'));
});

router.route('/art/:id', function(id){
	M.nav.pageByID('art', id);
});

<|endoftext|>


<commit_before>import Component from '@ember/component';
import layout from './template';
import { computed, observer, get, set, setProperties } from '@ember/object';
import { on } from '@ember/object/evented';
import { inject as service } from '@ember/service';
import { all as PromiseAll } from 'rsvp';

export default Component.extend({
  layout,
  globalStore:     service(),
  access:          service(),

  editing:         false,
  memberArray:     null,
  memberConfig:    null,
  model:           null,
  primaryResource: null,
  roles:           null,
  type:            null,
  users:           null,
  creator:         null,
  showCreator:     true,
  toAddCustom: null,
  _bindings: null,

  init() {
    this._super(...arguments);
    this.buildUpdateList(get(this,'primaryResource'))
    this.sendAction('initAlert', this.primaryResourceSaved.bind(this));
  },

  buildUpdateList(resource) {
    let bindingType = `${get(resource, 'type')}RoleTemplateBindings`;
    let bindings = get(resource, bindingType);
    let existing = [];
    let grouped = {};
    set(this, "_bindings", bindings.slice());
    if (bindings && get(this, 'editing')) {
      bindings.forEach((b) => {
        if (grouped[get(b, 'subjectName')]) {
          grouped[get(b, 'subjectName')].push(b);
        } else {
          grouped[get(b, 'subjectName')] = [b];
        }
      });

      if (grouped) {
        Object.keys(grouped).forEach((g) => {
          if (grouped[g].length >1) {
            let idsOut = [];
            grouped[g].forEach((m) => {
              idsOut.push(get(m, 'roleTemplateId'))
            });
            let config = get(this, 'memberConfig');
            set(config, 'subjectKind', 'User'); //should be upper but make sure
            set(config, 'subjectName', g);
            let record = get(this,'globalStore').createRecord(config);

            let out = {
              role: record,
              toUpdate: false,
              toAdd: false,
              toDelete: false,
              customRolesExisting: idsOut
            }

            existing.push(out);
          } else {
            existing.push({
              role: grouped[g][0],
              toUpdate: false,
              toAdd: false,
              toDelete: false,
              id: Math.random()
            })
          }
        });
      }
    }
    set(this, 'memberArray', existing);
  },

  primaryResourceSaved: function() {
    // returns a promise of all the adds/removes/updates to the parent
    const pr = get(this, 'primaryResource');
    const resourceId = get(pr, 'id');
    const memberArray = get(this, 'memberArray').slice();

    const customToAdd = memberArray.filterBy('customRolesToAdd');
    const customToRemove = memberArray.filterBy('customRolesToRemove');

    const add = get(this, 'memberArray').filter(r => get(r, 'toAdd') && !get(r, 'customRolesToAdd')).map(a => a.role);
    const update = get(this, 'memberArray').filterBy('toUpdate', true).map(u => u.role);
    const remove = get(this, 'memberArray').filterBy('toRemove', true).map(r => r.role);

    customToRemove.forEach((rm) => {
      // custom obj from custom
      get(rm, 'customRolesToRemove').forEach((roleTempId) => {
        let match = get(this, '_bindings').find((binding) => {
          if (get(binding, 'roleTemplateId') === roleTempId) {
            return binding;
          }
        });
        remove.push(match);
      });
    });
    customToAdd.forEach((m) => {
      get(m, 'customRolesToAdd').forEach((a) => {
        let role = get(m, 'role').clone();
        set(role, 'roleTemplateId', a);
        add.addObject(role);
      })
    });

    add.forEach((x) => {
      x.set(`${get(this, 'type')}Id`, resourceId);
      x.set('name', null);
    });

    return PromiseAll(add.map(x => x.save())).then(() => {
      return PromiseAll(update.map(x => x.save())).then(() => {
        return PromiseAll(remove.map(x => x.delete())).then(() => {
          return pr;
        });
      });
    });
  },

  actions: {
    setCustomToAdd(member, customIds, customIdsRemove) {
      set(member, 'customRolesToAdd', customIds);
      set(member, 'customRolesToRemove', customIdsRemove);
    },

    cancel() {
      this.goBack();
    },

    addMember(kind) {
      let config = get(this, 'memberConfig');
      set(config, 'subjectKind', kind.capitalize()); //should be upper but make sure
      // not setting the name correctly
      let record = get(this,'globalStore').createRecord(config);
      let out = {
        role: record,
        toAdd: true,
        toUpate: false,
        toRemove: false,
        id: Math.random()
      };
      get(this,'memberArray').pushObject(out);
    },

    removeMember(obj) {
      let exists = get(this, 'memberArray').findBy('id', get(obj, 'id'));
      if (get(obj, 'toAdd') && exists) {
        // we just added and should remove it because the record has not been persisted yet
        get(this,'memberArray').removeObject(obj);
      } else if (exists) {
        setProperties(exists, {
          toAdd: false,
          toUpdate: false,
          toDelete: true,
        });
      }
    },
  },

  filteredUsers: computed('users.@each.{id,state}', function() {
    let users = get(this, 'users');
    if (get(this, 'editing')) {
      users = users.filter(u => !u.hasOwnProperty('me'));
    }
    return users.sortBy('displayName');
  }),

});
<commit_msg>fixes<commit_after>import Component from '@ember/component';
import layout from './template';
import { computed, get, set, setProperties } from '@ember/object';
import { inject as service } from '@ember/service';
import { all as PromiseAll } from 'rsvp';

export default Component.extend({
  layout,
  globalStore:     service(),
  access:          service(),

  editing:         false,
  memberArray:     null,
  memberConfig:    null,
  model:           null,
  primaryResource: null,
  roles:           null,
  type:            null,
  users:           null,
  creator:         null,
  showCreator:     true,
  toAddCustom: null,
  _bindings: null,

  init() {
    this._super(...arguments);
    this.buildUpdateList(get(this,'primaryResource'))
    this.sendAction('initAlert', this.primaryResourceSaved.bind(this));
  },

  buildUpdateList(resource) {
    let bindingType = `${get(resource, 'type')}RoleTemplateBindings`;
    let bindings = get(resource, bindingType).filter(b => b.name !== 'creator');
    let existing = [];
    let grouped = {};
    set(this, "_bindings", bindings.slice());
    if (bindings && get(this, 'editing')) {
      bindings.forEach((b) => {
        if (grouped[get(b, 'subjectName')]) {
          grouped[get(b, 'subjectName')].push(b);
        } else {
          grouped[get(b, 'subjectName')] = [b];
        }
      });

      if (grouped) {
        Object.keys(grouped).forEach((g) => {
          if (grouped[g].length >1) {
            let idsOut = [];
            grouped[g].forEach((m) => {
              idsOut.push(get(m, 'roleTemplateId'))
            });
            let config = get(this, 'memberConfig');
            set(config, 'subjectKind', 'User'); //should be upper but make sure
            set(config, 'subjectName', g);
            let record = get(this,'globalStore').createRecord(config);

            let out = {
              role: record,
              toUpdate: false,
              toAdd: false,
              toDelete: false,
              customRolesExisting: idsOut
            }

            existing.push(out);
          } else {
            existing.push({
              role: grouped[g][0],
              toUpdate: false,
              toAdd: false,
              toDelete: false,
              id: Math.random()
            })
          }
        });
      }
    }
    set(this, 'memberArray', existing);
  },

  primaryResourceSaved: function() {
    // returns a promise of all the adds/removes/updates to the parent
    const pr = get(this, 'primaryResource');
    const resourceId = get(pr, 'id');
    const memberArray = get(this, 'memberArray').slice();

    const customToAdd = memberArray.filterBy('customRolesToAdd');
    const customToRemove = memberArray.filterBy('customRolesToRemove');

    const add = get(this, 'memberArray').filter(r => get(r, 'toAdd') && !get(r, 'customRolesToAdd')).map(a => a.role);
    const update = get(this, 'memberArray').filterBy('toUpdate', true).map(u => u.role);
    const remove = get(this, 'memberArray').filterBy('toRemove', true).map(r => r.role);

    customToRemove.forEach((rm) => {
      // custom obj from custom
      get(rm, 'customRolesToRemove').forEach((roleTempId) => {
        let match = get(this, '_bindings').find((binding) => {
          if (get(binding, 'roleTemplateId') === roleTempId) {
            return binding;
          }
        });
        remove.push(match);
      });
    });
    customToAdd.forEach((m) => {
      get(m, 'customRolesToAdd').forEach((a) => {
        let role = get(m, 'role').clone();
        set(role, 'roleTemplateId', a);
        add.addObject(role);
      })
    });

    add.forEach((x) => {
      x.set(`${get(this, 'type')}Id`, resourceId);
      x.set('name', null);
    });

    return PromiseAll(add.map(x => x.save())).then(() => {
      return PromiseAll(update.map(x => x.save())).then(() => {
        return PromiseAll(remove.map(x => x.delete())).then(() => {
          return pr;
        });
      });
    });
  },

  actions: {
    setCustomToAdd(member, customIds, customIdsRemove) {
      set(member, 'customRolesToAdd', customIds);
      set(member, 'customRolesToRemove', customIdsRemove);
    },

    cancel() {
      this.goBack();
    },

    addMember(kind) {
      let config = get(this, 'memberConfig');
      set(config, 'subjectKind', kind.capitalize()); //should be upper but make sure
      // not setting the name correctly
      let record = get(this,'globalStore').createRecord(config);
      let out = {
        role: record,
        toAdd: true,
        toUpate: false,
        toRemove: false,
        id: Math.random()
      };
      get(this,'memberArray').pushObject(out);
    },

    removeMember(obj) {
      let exists = get(this, 'memberArray').findBy('id', get(obj, 'id'));
      if (get(obj, 'toAdd') && exists) {
        // we just added and should remove it because the record has not been persisted yet
        get(this,'memberArray').removeObject(obj);
      } else if (exists) {
        setProperties(exists, {
          toAdd: false,
          toUpdate: false,
          toDelete: true,
        });
      }
    },
  },

  filteredUsers: computed('users.@each.{id,state}', function() {
    let users = get(this, 'users');
    if (get(this, 'editing')) {
      users = users.filter(u => !u.hasOwnProperty('me'));
    }
    return users.sortBy('displayName');
  }),

});
<|endoftext|>


<commit_before>var utils = require('../utils');
var chefconfig = require('config').Chef;
var fs = require('fs');
var awsconfig = require('config').AWS;
var dnsconfig = require('config').DNS;

module.exports = function(params) {
  var jobs = params.jobs;
  var AWS = params.AWS;
  var ec2 = new AWS.EC2();
  var ProjectService = params.models.projectservice;

  var validationpem = (chefconfig.enable ? fs.readFileSync(__dirname + "/../" + chefconfig.validationpem).toString().split('\n') : "");

  jobs.process('createservice', function(job, done){
    //console.log(job.data.projectservice);
    /*
    ec2.describeVpcs({}, function(err, data) {
     if (err) console.log(err, err.stack); // an error occurred
     else     console.log(data);           // successful response
    });
    */

    var nodename = job.data.projectservice.name + "-" + job.data.projectservice.serverids.length+1;

    var ec2params = {
      ImageId: awsconfig.ec2.ImageId,
      InstanceType: awsconfig.ec2.InstanceType,
      MinCount: 1,
      MaxCount: 1,
      SecurityGroupIds: awsconfig.ec2.SecurityGroupIds,
      SubnetId: awsconfig.ec2.SubnetId,
      KeyName: awsconfig.ec2.KeyName
    };

    var runlist = ['"role[uhost]"', '"role[' + job.data.projectservice.serviceid.role + ']"'];

    var userdata = [];
    userdata.push('#!/bin/bash');
    userdata.push('');
    userdata.push('set -x');
    userdata.push('');
    userdata.push('wget -P /tmp https://www.chef.io/chef/install.sh');
    userdata.push('bash /tmp/install.sh -v 12.3.0-1');
    userdata.push('mkdir -p /etc/chef');
    userdata.push('cat << EOF | sudo tee /etc/chef/validation.pem > /dev/null');
    validationpem.forEach(function(line) {
      userdata.push(line);
    });
    userdata.push('EOF');
    userdata.push('');
    userdata.push('cat << EOF | sudo tee /etc/chef/client.rb > /dev/null');
    userdata.push('log_level        :info');
    userdata.push('log_location     STDOUT');
    userdata.push('chef_server_url  "' + chefconfig.chef_server_url + '"');
    userdata.push('validation_client_name "' + chefconfig.validation_client_name + '"');
    userdata.push('node_name "' + nodename + '"');
    userdata.push('ssl_verify_mode :verify_none');
    userdata.push('EOF');
    userdata.push('');
    userdata.push('cat << EOF | sudo tee /etc/chef/first-boot.json > /dev/null');
    userdata.push('{');
    userdata.push('  "servername": "' + nodename + "." + dnsconfig.domainname + '",');
    userdata.push('  "run_list": [' + runlist + ']');
    userdata.push('}');
    userdata.push('EOF');
    userdata.push('');
    userdata.push('mkdir -p /etc/chef/ohai/hints');
    userdata.push('touch /etc/chef/ohai/hints/ec2.json');
    userdata.push('');
    userdata.push('sudo chef-client -j /etc/chef/first-boot.json');

    //console.log(userdata.join('\n'));

    ec2params.UserData = new Buffer(userdata.join('\n')).toString('base64');

    //console.log(ec2params)
    ec2.runInstances(ec2params, function(err, data) {
      if (err) {
        console.log("Could not create instance", err);
        done();
      } else {
        var instanceId = data.Instances[0].InstanceId;
        console.log("Created instance", instanceId);
        //console.log(data.Instances[0]);

        // Add tags to the instance
        ec2params = {Resources: [instanceId], Tags: [
          {Key: 'Name', Value: job.data.projectservice.name}
        ]};
        ec2.createTags(ec2params, function(err) {
        console.log("Tagging instance", err ? "failure" : "success");

          var createserveractionjob = jobs.create('createserveraction', { projectservice: job.data.projectservice, instance: instanceId, nodename: nodename }).save( function(err) {
            if (err) {
              console.log(err);
            }
            console.log(createserveractionjob.type + ": " + createserveractionjob.id);
            done();
          });
        });
      }
    });
  });

};
<commit_msg>Now creating a public ip address for the instance<commit_after>var utils = require('../utils');
var chefconfig = require('config').Chef;
var fs = require('fs');
var awsconfig = require('config').AWS;
var dnsconfig = require('config').DNS;

module.exports = function(params) {
  var jobs = params.jobs;
  var AWS = params.AWS;
  var ec2 = new AWS.EC2();
  var ProjectService = params.models.projectservice;

  var validationpem = (chefconfig.enable ? fs.readFileSync(__dirname + "/../" + chefconfig.validationpem).toString().split('\n') : "");

  jobs.process('createservice', function(job, done){
    //console.log(job.data.projectservice);
    /*
    ec2.describeVpcs({}, function(err, data) {
     if (err) console.log(err, err.stack); // an error occurred
     else     console.log(data);           // successful response
    });
    */

    var nodename = job.data.projectservice.name + "-" + job.data.projectservice.serverids.length+1;

    var ec2params = {
      ImageId: awsconfig.ec2.ImageId,
      InstanceType: awsconfig.ec2.InstanceType,
      MinCount: 1,
      MaxCount: 1,
      NetworkInterfaces: [{
        DeviceIndex: 0,
	AssociatePublicIpAddress: true,
	SubnetId: awsconfig.ec2.SubnetId,
	Groups: awsconfig.ec2.SecurityGroupIds,
      }],
      KeyName: awsconfig.ec2.KeyName
    };

    var runlist = ['"role[uhost]"', '"role[' + job.data.projectservice.serviceid.role + ']"'];

    var userdata = [];
    userdata.push('#!/bin/bash');
    userdata.push('');
    userdata.push('set -x');
    userdata.push('');
    userdata.push('wget -P /tmp https://www.chef.io/chef/install.sh');
    userdata.push('bash /tmp/install.sh -v 12.3.0-1');
    userdata.push('mkdir -p /etc/chef');
    userdata.push('cat << EOF | sudo tee /etc/chef/validation.pem > /dev/null');
    validationpem.forEach(function(line) {
      userdata.push(line);
    });
    userdata.push('EOF');
    userdata.push('');
    userdata.push('cat << EOF | sudo tee /etc/chef/client.rb > /dev/null');
    userdata.push('log_level        :info');
    userdata.push('log_location     STDOUT');
    userdata.push('chef_server_url  "' + chefconfig.chef_server_url + '"');
    userdata.push('validation_client_name "' + chefconfig.validation_client_name + '"');
    userdata.push('node_name "' + nodename + '"');
    userdata.push('ssl_verify_mode :verify_none');
    userdata.push('EOF');
    userdata.push('');
    userdata.push('cat << EOF | sudo tee /etc/chef/first-boot.json > /dev/null');
    userdata.push('{');
    userdata.push('  "servername": "' + nodename + "." + dnsconfig.domainname + '",');
    userdata.push('  "run_list": [' + runlist + ']');
    userdata.push('}');
    userdata.push('EOF');
    userdata.push('');
    userdata.push('mkdir -p /etc/chef/ohai/hints');
    userdata.push('touch /etc/chef/ohai/hints/ec2.json');
    userdata.push('');
    userdata.push('sudo chef-client -j /etc/chef/first-boot.json');

    //console.log(userdata.join('\n'));

    ec2params.UserData = new Buffer(userdata.join('\n')).toString('base64');

    //console.log(ec2params)
    ec2.runInstances(ec2params, function(err, data) {
      if (err) {
        console.log("Could not create instance", err);
        done();
      } else {
        var instanceId = data.Instances[0].InstanceId;
        console.log("Created instance", instanceId);
        //console.log(data.Instances[0]);

        // Add tags to the instance
        ec2params = {Resources: [instanceId], Tags: [
          {Key: 'Name', Value: job.data.projectservice.name}
        ]};
        ec2.createTags(ec2params, function(err) {
        console.log("Tagging instance", err ? "failure" : "success");

          var createserveractionjob = jobs.create('createserveraction', { projectservice: job.data.projectservice, instance: instanceId, nodename: nodename }).save( function(err) {
            if (err) {
              console.log(err);
            }
            console.log(createserveractionjob.type + ": " + createserveractionjob.id);
            done();
          });
        });
      }
    });
  });

};
<|endoftext|>


<commit_before>;(function($, window, document, undefined) {

  var pluginName = 'boilerplate';
  var defaults = {};

  // Define your private variables here.

  function Plugin(element, options) {
    var self = this;
    self._element = element;
    self._options = options;
    self._settings = $.extend(defaults, self._options);

    // Do more stuff here.

    this.init();
  }

  /**
   * preventDefault and stopPropagation helper
   *
   * @param {Event} event     Event object
   * @param {Bool}  bubbling  Cancel event bubbling
   *
   * @return {Void}
   */
  var _stopDefault = function(event, bubbling) {
    event.preventDefault();
    if (!bubbling) {
      event.stopPropagation();
    }
  };

  /**
   * Private method
   *
   * @return {Void}
   */
  var _privateMethod = function() {
    console.log('_privatemethod()');
  };

  /**
   * Initialize
   *
   * @return {Void}
   */
  Plugin.prototype.init = function() {
    // Place initialization logic here
    // You already have access to the DOM element and
    // the options via the instance, e.g. this._element
    // and this._options
  };

  /**
   * Reload
   *
   * @return {Void}
   */
  Plugin.prototype.reload = function() {

  };

  /**
   * Destroy
   *
   * @return {Void}
   */
  Plugin.prototype.destroy = function() {

  };

  /**
   * A really lightweight plugin wrapper around the constructor,
   * preventing against multiple instantiations
   */
  $.fn[pluginName] = function(options) {
    return this.each(function() {
      if (!$.data(this, 'plugin_' + pluginName)) {
        $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
      }
    });
  }

})(jQuery, window, document);
<commit_msg>Added plugin version<commit_after>;(function($, window, document, undefined) {

  var pluginName = 'boilerplate',
      pluginVerion = '0.1.0';

  // Default settings of the plugin
  var defaults = {};

  // Define other variables here
  var otherVariable = {};

  function Plugin(element, options) {
    var self = this;
    self._element = element;
    self._options = options;
    self._settings = $.extend(defaults, self._options);

    // Do more stuff here
    // ...

    this.init();
  }

  /**
   * preventDefault and stopPropagation helper
   *
   * @param {Event} event     Event object
   * @param {Bool}  bubbling  Cancel event bubbling
   *
   * @return {Void}
   */
  var _stopDefault = function(event, bubbling) {
    event.preventDefault();
    if (!bubbling) {
      event.stopPropagation();
    }
  };

  /**
   * Private method
   *
   * @return {Void}
   */
  var _privateMethod = function() {
    console.log('_privatemethod()');
  };

  /**
   * Initialize
   *
   * @return {Void}
   */
  Plugin.prototype.init = function() {
    // Place initialization logic here
    // You already have access to the DOM element and
    // the options via the instance, e.g. this._element
    // and this._options
  };

  /**
   * Reload
   *
   * @return {Void}
   */
  Plugin.prototype.reload = function() {

  };

  /**
   * Destroy
   *
   * @return {Void}
   */
  Plugin.prototype.destroy = function() {

  };

  /**
   * A really lightweight plugin wrapper around the constructor,
   * preventing against multiple instantiations
   */
  $.fn[pluginName] = function(options) {
    return this.each(function() {
      if (!$.data(this, 'plugin_' + pluginName)) {
        $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
      }
    });
  }

})(jQuery, window, document);
<|endoftext|>


<commit_before>(function ($)  {
	$.widget( 'stog.checkboxify', {

		options: {
			selectAll:	true,
		},

		_create: function() {
			var that = this;
			// add in checkboxes
			this.element.find('tr td:first-child').each( function () {
				var $this= $(this);
				var id = $this.parent().data('checkboxify-id');
				if(!id)
					id = $this.text().trim();
				$this.append('
<input type="checkbox" class="checkboxify" data-id="' + id + '">');
			});

			// add buttons
			if(this.options.buttons || this.options.selectAll) {
				buttDiv = $('

');
				this.element.before(buttDiv);

				if(this.options.selectAll) {
					// add select all button
					newButton = $('<button><input type="checkbox" class="checkboxify-all"></button>');
					newButton.click(function() {
							$(that.element).find('.checkboxify').prop('checked',$('input',this).prop('checked'));
					});
					if(this.options.selectAll.class)
						newButton.addClass(this.options.selectAll.class);
					buttDiv.append(newButton);

					// select all checkbox to react to changes to row checkboxes
					$('.checkboxify', that.element).change(function() {
						nAll = $('.checkboxify', that.element).length;
						nOn = $('.checkboxify:checked', that.element).length;
						if(!nOn)
							$('.checkboxify-all').prop('checked', false).prop('indeterminate',false);
						else if(nAll == nOn)
							$('.checkboxify-all').prop('checked', true).prop('indeterminate',false);
						else
							$('.checkboxify-all').prop('checked', true).prop('indeterminate', true);
					});
				}

				var nButtons = this.options.buttons.length;
				for(var i=0; i<nButtons; i++) {
					but = this.options.buttons[i];
					newButton = $('<button>' + but.label + '</button>')
					newButton.data('checkboxify-action', but.action)
					.data('checkboxify-params', but.params);
					if(but.confirm) {
						newButton.click(function(event) {
							if(!confirm(but.confirm))
								ev.stopPropogation();
						});
					}
					newButton.click(function() {
						$this = $(this);
						var all_params = $.extend($this.data('checkboxify-params'), {id: that.getSelected() });
						$.redirect($this.data('checkboxify-action'), all_params);
					});
					if(but.class)
						newButton.addClass(but.class);
					buttDiv.append(newButton)
				}
			}
		},

		getSelected: function() {
			var a = this.element.find('input.checkboxify:checked').map( function () {
				return $(this).data('id');
			}).get();
			return a;
		}

	});

}( jQuery ));
<commit_msg>New Options Added: itemSelector and prependCheckbox. chckxy id data can now be in item as well as parent.<commit_after>(function ($)  {
	$.widget( 'stog.checkboxify', {

		options: {
			selectAll:			true,
			itemSelector:		'tr td:first-child',
			prependCheckbox:	false,
		},

		_create: function() {
			var that = this;
			// add in checkboxes
			this.element.find(this.options.itemSelector).each( function () {
				var $this= $(this);
				var id = $this.parent().data('checkboxify-id');
				if(!id)
					id = $this.data('checkboxify-id');
				if(!id)
					id = $this.text().trim();
				var boxHtml = '<input type="checkbox" class="checkboxify" data-id="' + id + '">';
				if(that.options.prependCheckbox)
					$this.prepend(boxHtml);
				else {
					if($this.text().length > 0);
						boxHtml = '
' + boxHtml;
					$this.append(boxHtml);
				}
			});

			// add buttons
			if(this.options.buttons || this.options.selectAll) {
				buttDiv = $('

');
				this.element.before(buttDiv);

				if(this.options.selectAll) {
					// add select all button
					newButton = $('<button><input type="checkbox" class="checkboxify-all"></button>');
					newButton.click(function() {
							$(that.element).find('.checkboxify').prop('checked',$('input',this).prop('checked'));
					});
					if(this.options.selectAll.class)
						newButton.addClass(this.options.selectAll.class);
					buttDiv.append(newButton);

					// select all checkbox to react to changes to row checkboxes
					$('.checkboxify', that.element).change(function() {
						nAll = $('.checkboxify', that.element).length;
						nOn = $('.checkboxify:checked', that.element).length;
						if(!nOn)
							$('.checkboxify-all').prop('checked', false).prop('indeterminate',false);
						else if(nAll == nOn)
							$('.checkboxify-all').prop('checked', true).prop('indeterminate',false);
						else
							$('.checkboxify-all').prop('checked', true).prop('indeterminate', true);
					});
				}

				var nButtons = this.options.buttons.length;
				for(var i=0; i<nButtons; i++) {
					but = this.options.buttons[i];
					newButton = $('<button>' + but.label + '</button>')
					newButton.data('checkboxify-action', but.action)
					.data('checkboxify-params', but.params);
					if(but.confirm) {
						newButton.click(function(event) {
							if(!confirm(but.confirm))
								ev.stopPropogation();
						});
					}
					newButton.click(function() {
						$this = $(this);
						var all_params = $.extend($this.data('checkboxify-params'), {id: that.getSelected() });
						$.redirect($this.data('checkboxify-action'), all_params);
					});
					if(but.class)
						newButton.addClass(but.class);
					buttDiv.append(newButton)
				}
			}
		},

		getSelected: function() {
			var a = this.element.find('input.checkboxify:checked').map( function () {
				return $(this).data('id');
			}).get();
			return a;
		}

	});

}( jQuery ));

<|endoftext|>