<commit_before>
const RG = require('./rg');
RG.Random = require('./random');

RG.Template = require('./template');

const Crypt = require('../data/tiles.crypt');

const baseTemplates = Crypt.tiles;
const fillerTempl = Crypt.filler;

/*
const fillerFloor = `
name:FILLER
X=.
Y=.

.X...X.
Y......
.......
.......
.......
Y......
.......`;
*/

RG.Template.Level = function(tilesX, tilesY) {
    this.tilesX = tilesX;
    this.tilesY = tilesY;
    this.genParams = [1, 1, 1, 1];

    this.genParamMin = 1;
    this.genParamMax = 1;

    this.filler = RG.Template.createTemplate(fillerTempl);
    this.templates = baseTemplates.map(t => RG.Template.createTemplate(t));
    this._unusedExits = [];
    this.freeExits = {};

    this.sortedByExit = {
        N: [], S: [], E: [], W: []
    };
    // Sort data into 4 lists with N, S, E, W exists
    this.templates.forEach(templ => {
        const dir = templ.getProp('dir');
        if (/N/.test(dir)) {this.sortedByExit.N.push(templ);}
        if (/S/.test(dir)) {this.sortedByExit.S.push(templ);}
        if (/E/.test(dir)) {this.sortedByExit.E.push(templ);}
        if (/W/.test(dir)) {this.sortedByExit.W.push(templ);}
    });

    // Initialize a map with filler cells
    this.templMap = [];
    for (let x = 0; x < this.tilesX; x++) {
        this.templMap[x] = [];
        for (let y = 0; y < this.tilesY; y++) {
            this.templMap[x][y] = this.filler;
        }
    }

    this.setGenParams = function(arr) {
        this.genParams = arr;
    };

    /* Creates the level. Result is in this.map.
    * Main function you want to call. */
    this.create = function() {

        let dungeonInvalid = true;
        while (dungeonInvalid) {
            this._placeStartRoom();

            let roomCount = 0;
            const goalCount = 40;
            let numTries = 0;
            let hasExits = true;

            while (numTries < 1000 && hasExits) {

                // Get a room with unused exists
                const room = this._getRoomWithUnusedExits();
                if (room === null) {
                    hasExits = false;
                    break;
                }

                const {x, y} = room;

                console.log(`Current room in ${x},${y}`);

                const exits = this._getFreeExits(room);

                // Pick one exit randomly
                const chosen = RG.RAND.arrayGetRand(exits);

                // Get required matching exit
                const exitRequired = this.getMatchingExit(chosen);

                // Get a new room matching this exit
                const listMatching = this.sortedByExit[exitRequired];
                const templMatch = RG.RAND.arrayGetRand(listMatching);

                // Make sure the new room is valid
                const newX = this._getNewX(x, exitRequired);
                const newY = this._getNewY(y, exitRequired);
                if (this._isRoomLegal(newX, newY)) {
                    this._placeRoom(
                        x, y, chosen, newX, newY, exitRequired, templMatch);
                    ++roomCount;
                    console.log('Room count incremented to ' + roomCount);
                }

                // Place the new room and incr roomCount
                ++numTries;
            }

            if (roomCount >= goalCount) {
                dungeonInvalid = false;
            }
            else {
                this._cleanupAndTryAgain();
            }

        }

        // Create gen params for each tile
        this.genParamsX = [];
        this.genParamsY = [];
        for (let x = 0; x < this.tilesX; x++) {
            const paramsX = [1, 1];
            this.genParamsX.push(paramsX);
        }
        for (let y = 0; y < this.tilesY; y++) {
            const paramsY = [2, 2];
            this.genParamsY.push(paramsY);
        }

        this.mapExpanded = [];
        for (let x = 0; x < this.tilesX; x++) {
            this.mapExpanded[x] = [];
            for (let y = 0; y < this.tilesY; y++) {
                const params = this.genParamsX[x].concat(this.genParamsY[y]);
                // console.log(`${x},${y}: ` +
                    // `${JSON.stringify(this.mapExpanded[x][y])}`);
                this.mapExpanded[x][y] = this.templMap[x][y].getChars(params);
            }
        }

        this.map = [];
        // let xOffset = 0;
        // Now we have an unflattened map: 4-dimensional arrays
        for (let tileX = 0; tileX < this.tilesX; tileX++) {
            const numCols = this.mapExpanded[tileX][0].length;
            console.log(`tileX: ${tileX} numCols: ${numCols}`);
            for (let i = 0; i < numCols; i++) {
                let finalCol = [];
                for (let tileY = 0; tileY < this.tilesY; tileY++) {
                    const tileCol = this.mapExpanded[tileX][tileY][i];
                    finalCol = finalCol.concat(tileCol);
                }
                this.map.push(finalCol);
            }
            // xOffset += numCols;
        }

    };

    //----------------------------------------------------------------
    // PRIVATE
    //----------------------------------------------------------------

    this._getRoomWithUnusedExits = function() {
        if (this._unusedExits.length > 0) {
            return RG.RAND.arrayGetRand(this._unusedExits);
        }
        return null;
    };

    this._getFreeExits = function(room) {
        const {x, y} = room;
        const key = x + ',' + y;
        if (this.freeExits[key]) {
            return this.freeExits[key];
        }
        else {
            RG.err('Template', '_getFreeExits',
                `No ${key}, Room: ${JSON.stringify(room)}`);
        }
        return null;
    };

    this._removeChosenExit = function(x, y, chosen) {
        const key = x + ',' + y;
        const exits = this.freeExits[key];
        console.log(JSON.stringify(this.freeExits));
        console.log(`${x},${y} removeChosenExit ${chosen}`);
        console.log(`\tnExits: ${exits.length}`);
        const index = exits.indexOf(chosen);
        if (index >= 0) {
            this.freeExits[key].splice(index, 1);
            if (this.freeExits[key].length === 0) {
                const unusedIndex = this._unusedExits.findIndex(room => {
                    return room.x === x && room.y === y;
                });
                if (unusedIndex >= 0) {
                    this._unusedExits.splice(unusedIndex, 1);
                    delete this.freeExits[key];
                    console.log(`\t${x},${y} has no unused exits anymore.`);
                }
                else {
                    RG.err('Template', '_removeChosenExit',
                        `Cannot find ${x},${y} in unusedExits to remove.`);
                }
            }
            console.log('\tAfter remove: '
                + JSON.stringify(this.freeExits[key]));
        }
        else {
            RG.err('Template', '_removeChosenExit',
                `${x},${y} dir: ${chosen} not found.`);
        }
    };

    this._isRoomLegal = function(x, y) {
        if (x < this.tilesX && y < this.tilesY) {
            return true;
        }
        return false;
    };

    this._placeStartRoom = function() {
        const x = RG.RAND.getUniformInt(0, this.tilesX - 1);
        const y = RG.RAND.getUniformInt(0, this.tilesY - 1);
        this.templMap[x][y] = this.getRandomTemplate();
        const room = {x, y, room: this.templMap[x][y]};

        this._addRoomData(room);

        this._removeBorderExits(room);

    };

    this._placeRoom = function(
        x, y, chosen, newX, newY, exitRequired, templMatch
    ) {
        // Remove chosen exit (old room) from unused exits
        this._removeChosenExit(x, y, chosen);

        // Add new room data to unused exits
        const room = {x: newX, y: newY, room: templMatch};
        this._addRoomData(room);

        // But remove chosen exit
        this._removeChosenExit(newX, newY, exitRequired);

        // Check for abutting rooms on other edges and remove any exits
        this._checkAbuttingRooms(room);

        this._removeBorderExits(room);

        // Finally add new room to templMap
        this.templMap[newX][newY] = templMatch;

    };

    this._addRoomData = function(room) {
        this._unusedExits.push(room);
        const exits = room.room.getProp('dir').split('');
        const key = room.x + ',' + room.y;
        this.freeExits[key] = exits;
        console.log('>>> Added room ' + JSON.stringify(room));
    };

    this.getMatchingExit = function(chosen) {
        switch (chosen) {
            case 'N': return 'S';
            case 'S': return 'N';
            case 'E': return 'W';
            case 'W': return 'E';
            default: return 'N';
        }
    };

    this._getNewX = function(x, dir) {
        if (dir === 'E') {return x - 1;}
        if (dir === 'W') {return x + 1;}
        return x;

    };

    this._getNewY = function(y, dir) {
        if (dir === 'N') {return y + 1;}
        if (dir === 'S') {return y - 1;}
        return y;
    };

    this.getRandomTemplate = function() {
        // TODO at some point, we need to check how the entrances in rooms match
        return RG.RAND.arrayGetRand(this.templates);
    };

    /* Removes exits from tiles which are placed in any borders of the map. */
    this._removeBorderExits = function(room) {
        const {x, y} = room;
        if (x === 0) {
            if (this._hasExit('W', x, y)) {
                this._removeChosenExit(x, y, 'W');
            }
        }

        if (x === this.tilesX - 1) {
            if (this._hasExit('E', x, y)) {
                this._removeChosenExit(x, y, 'E');
            }
        }

        if (y === 0) {
            if (this._hasExit('N', x, y)) {
                this._removeChosenExit(x, y, 'N');
            }
        }

        if (y === this.tilesY - 1) {
            if (this._hasExit('S', x, y)) {
                this._removeChosenExit(x, y, 'S');
            }
        }

    };

    /* Checks for rooms already in place around the placed room, and removes all
     * matching exists. */
    this._checkAbuttingRooms = function(room) {
        const {x, y} = room;

        console.log(`CheckAbut ${x},${y}`);
        if (x > 0) {
            const nx = x - 1;
            if (!this._isFiller(nx, y)) {
                this._removeExitByXY('W', x, y);
                this._removeExitByXY('E', nx, y);
            }
        }

        if (x < this.tilesX - 1) {
            const nx = x + 1;
            if (!this._isFiller(nx, y)) {
                this._removeExitByXY('E', x, y);
                this._removeExitByXY('W', nx, y);
            }
        }

        if (y > 0) {
            const ny = y - 1;
            if (!this._isFiller(x, ny)) {
                this._removeExitByXY('N', x, y);
                this._removeExitByXY('S', x, ny);
            }
        }

        if (y < this.tilesY - 1) {
            const ny = y + 1;
            if (!this._isFiller(x, ny)) {
                this._removeExitByXY('S', x, y);
                this._removeExitByXY('N', x, ny);
            }
        }

    };

    this._isFiller = function(x, y) {
        console.log(`isFiller x,y ${x},${y}`);
        return this.templMap[x][y].getProp('name') === 'FILLER';
    };

    this._removeExitByXY = function(dir, x, y) {
        if (this._hasExit(dir, x, y)) {
            this._removeChosenExit(x, y, dir);
        }
    };

    this._hasExit = function(dir, x, y) {
        const key = x + ',' + y;
        if (this.freeExits[key]) {
            return this.freeExits[key].indexOf(dir) >= 0;
        }
        return false;
    };

    this._cleanupAndTryAgain = function() {
        // Initialize a map with filler cells
        this.templMap = [];
        for (let x = 0; x < this.tilesX; x++) {
            this.templMap[x] = [];
            for (let y = 0; y < this.tilesY; y++) {
                this.templMap[x][y] = this.filler;
            }
        }
        this.freeExits = {};
        this._unusedExits = [];
        // this.create();
    };

};

module.exports = RG.Template.Level;
<commit_msg>Added setRoomCount() and proper termination when target room count reached.<commit_after>
const RG = require('./rg');
RG.Random = require('./random');

RG.Template = require('./template');

const Crypt = require('../data/tiles.crypt');

const baseTemplates = Crypt.tiles;
const fillerTempl = Crypt.filler;

/*
const fillerFloor = `
name:FILLER
X=.
Y=.

.X...X.
Y......
.......
.......
.......
Y......
.......`;
*/

RG.Template.Level = function(tilesX, tilesY) {
    this.tilesX = tilesX;
    this.tilesY = tilesY;
    this.genParams = [1, 1, 1, 1];
    this.roomCount = 40;

    this.genParamMin = 1;
    this.genParamMax = 1;

    this.filler = RG.Template.createTemplate(fillerTempl);
    this.templates = baseTemplates.map(t => RG.Template.createTemplate(t));
    this._unusedExits = [];
    this.freeExits = {};

    this.sortedByExit = {
        N: [], S: [], E: [], W: []
    };
    // Sort data into 4 lists with N, S, E, W exits
    this.templates.forEach(templ => {
        const dir = templ.getProp('dir');
        if (/N/.test(dir)) {this.sortedByExit.N.push(templ);}
        if (/S/.test(dir)) {this.sortedByExit.S.push(templ);}
        if (/E/.test(dir)) {this.sortedByExit.E.push(templ);}
        if (/W/.test(dir)) {this.sortedByExit.W.push(templ);}
    });

    // Initialize a map with filler cells
    this.templMap = [];
    for (let x = 0; x < this.tilesX; x++) {
        this.templMap[x] = [];
        for (let y = 0; y < this.tilesY; y++) {
            this.templMap[x][y] = this.filler;
        }
    }

    this.setGenParams = function(arr) {
        this.genParams = arr;
    };

    this.setRoomCount = function(count) {
        this.roomCount = count;
    };

    /* Creates the level. Result is in this.map.
    * Main function you want to call. */
    this.create = function() {

        let dungeonInvalid = true;
        while (dungeonInvalid) {
            this._placeStartRoom();

            let roomCount = 0;
            const goalCount = this.roomCount;
            let numTries = 0;
            let hasExits = true;

            while (numTries < 1000 && hasExits) {

                // Get a room with unused exists
                const room = this._getRoomWithUnusedExits();
                if (room === null) {
                    hasExits = false;
                    break;
                }

                const {x, y} = room;

                console.log(`Current room in ${x},${y}`);

                const exits = this._getFreeExits(room);

                // Pick one exit randomly
                const chosen = RG.RAND.arrayGetRand(exits);

                // Get required matching exit
                const exitRequired = this.getMatchingExit(chosen);

                // Get a new room matching this exit
                const listMatching = this.sortedByExit[exitRequired];
                const templMatch = RG.RAND.arrayGetRand(listMatching);

                // Make sure the new room is valid
                const newX = this._getNewX(x, exitRequired);
                const newY = this._getNewY(y, exitRequired);
                if (this._isRoomLegal(newX, newY)) {
                    this._placeRoom(
                        x, y, chosen, newX, newY, exitRequired, templMatch);
                    ++roomCount;
                    console.log('Room count incremented to ' + roomCount);
                }

                // Place the new room and incr roomCount
                ++numTries;

                if (roomCount >= goalCount) {
                    dungeonInvalid = false;
                    break;
                }
            }

            if (roomCount >= goalCount) {
                dungeonInvalid = false;
            }
            else {
                this._cleanupAndTryAgain();
            }

        }

        // Create gen params for each tile
        this.genParamsX = [];
        this.genParamsY = [];
        for (let x = 0; x < this.tilesX; x++) {
            const paramsX = [this.genParams[0], this.genParams[1]];
            this.genParamsX.push(paramsX);
        }
        for (let y = 0; y < this.tilesY; y++) {
            const paramsY = [this.genParams[2], this.genParams[3]];
            this.genParamsY.push(paramsY);
        }

        // Expand the tiles with parameters
        this.mapExpanded = [];
        for (let x = 0; x < this.tilesX; x++) {
            this.mapExpanded[x] = [];
            for (let y = 0; y < this.tilesY; y++) {
                const params = this.genParamsX[x].concat(this.genParamsY[y]);
                this.mapExpanded[x][y] = this.templMap[x][y].getChars(params);
            }
        }

        this.map = [];
        // Now we have an unflattened map: 4-dimensional arrays
        for (let tileX = 0; tileX < this.tilesX; tileX++) {
            const numCols = this.mapExpanded[tileX][0].length;
            for (let i = 0; i < numCols; i++) {
                let finalCol = [];
                for (let tileY = 0; tileY < this.tilesY; tileY++) {
                    const tileCol = this.mapExpanded[tileX][tileY][i];
                    finalCol = finalCol.concat(tileCol);
                }
                this.map.push(finalCol);
            }
        }

    };

    //----------------------------------------------------------------
    // PRIVATE
    //----------------------------------------------------------------

    this._getRoomWithUnusedExits = function() {
        if (this._unusedExits.length > 0) {
            return RG.RAND.arrayGetRand(this._unusedExits);
        }
        return null;
    };

    this._getFreeExits = function(room) {
        const {x, y} = room;
        const key = x + ',' + y;
        if (this.freeExits[key]) {
            return this.freeExits[key];
        }
        else {
            RG.err('Template', '_getFreeExits',
                `No ${key}, Room: ${JSON.stringify(room)}`);
        }
        return null;
    };

    this._removeChosenExit = function(x, y, chosen) {
        const key = x + ',' + y;
        const exits = this.freeExits[key];
        console.log(JSON.stringify(this.freeExits));
        console.log(`${x},${y} removeChosenExit ${chosen}`);
        console.log(`\tnExits: ${exits.length}`);
        const index = exits.indexOf(chosen);
        if (index >= 0) {
            this.freeExits[key].splice(index, 1);
            if (this.freeExits[key].length === 0) {
                const unusedIndex = this._unusedExits.findIndex(room => {
                    return room.x === x && room.y === y;
                });
                if (unusedIndex >= 0) {
                    this._unusedExits.splice(unusedIndex, 1);
                    delete this.freeExits[key];
                    console.log(`\t${x},${y} has no unused exits anymore.`);
                }
                else {
                    RG.err('Template', '_removeChosenExit',
                        `Cannot find ${x},${y} in unusedExits to remove.`);
                }
            }
            console.log('\tAfter remove: '
                + JSON.stringify(this.freeExits[key]));
        }
        else {
            RG.err('Template', '_removeChosenExit',
                `${x},${y} dir: ${chosen} not found.`);
        }
    };

    this._isRoomLegal = function(x, y) {
        if (x < this.tilesX && y < this.tilesY) {
            return true;
        }
        return false;
    };

    this._placeStartRoom = function() {
        const x = RG.RAND.getUniformInt(0, this.tilesX - 1);
        const y = RG.RAND.getUniformInt(0, this.tilesY - 1);
        this.templMap[x][y] = this.getRandomTemplate();
        const room = {x, y, room: this.templMap[x][y]};

        this._addRoomData(room);

        this._removeBorderExits(room);

    };

    this._placeRoom = function(
        x, y, chosen, newX, newY, exitRequired, templMatch
    ) {
        // Remove chosen exit (old room) from unused exits
        this._removeChosenExit(x, y, chosen);

        // Add new room data to unused exits
        const room = {x: newX, y: newY, room: templMatch};
        this._addRoomData(room);

        // But remove chosen exit
        this._removeChosenExit(newX, newY, exitRequired);

        // Check for abutting rooms on other edges and remove any exits
        this._checkAbuttingRooms(room);

        this._removeBorderExits(room);

        // Finally add new room to templMap
        this.templMap[newX][newY] = templMatch;

    };

    this._addRoomData = function(room) {
        this._unusedExits.push(room);
        const exits = room.room.getProp('dir').split('');
        const key = room.x + ',' + room.y;
        this.freeExits[key] = exits;
        console.log('>>> Added room ' + JSON.stringify(room));
    };

    this.getMatchingExit = function(chosen) {
        switch (chosen) {
            case 'N': return 'S';
            case 'S': return 'N';
            case 'E': return 'W';
            case 'W': return 'E';
            default: return 'N';
        }
    };

    this._getNewX = function(x, dir) {
        if (dir === 'E') {return x - 1;}
        if (dir === 'W') {return x + 1;}
        return x;

    };

    this._getNewY = function(y, dir) {
        if (dir === 'N') {return y + 1;}
        if (dir === 'S') {return y - 1;}
        return y;
    };

    this.getRandomTemplate = function() {
        // TODO at some point, we need to check how the entrances in rooms match
        return RG.RAND.arrayGetRand(this.templates);
    };

    /* Removes exits from tiles which are placed in any borders of the map. */
    this._removeBorderExits = function(room) {
        const {x, y} = room;
        if (x === 0) {
            if (this._hasExit('W', x, y)) {
                this._removeChosenExit(x, y, 'W');
            }
        }

        if (x === this.tilesX - 1) {
            if (this._hasExit('E', x, y)) {
                this._removeChosenExit(x, y, 'E');
            }
        }

        if (y === 0) {
            if (this._hasExit('N', x, y)) {
                this._removeChosenExit(x, y, 'N');
            }
        }

        if (y === this.tilesY - 1) {
            if (this._hasExit('S', x, y)) {
                this._removeChosenExit(x, y, 'S');
            }
        }

    };

    /* Checks for rooms already in place around the placed room, and removes all
     * matching exists. */
    this._checkAbuttingRooms = function(room) {
        const {x, y} = room;

        console.log(`CheckAbut ${x},${y}`);
        if (x > 0) {
            const nx = x - 1;
            if (!this._isFiller(nx, y)) {
                this._removeExitByXY('W', x, y);
                this._removeExitByXY('E', nx, y);
            }
        }

        if (x < this.tilesX - 1) {
            const nx = x + 1;
            if (!this._isFiller(nx, y)) {
                this._removeExitByXY('E', x, y);
                this._removeExitByXY('W', nx, y);
            }
        }

        if (y > 0) {
            const ny = y - 1;
            if (!this._isFiller(x, ny)) {
                this._removeExitByXY('N', x, y);
                this._removeExitByXY('S', x, ny);
            }
        }

        if (y < this.tilesY - 1) {
            const ny = y + 1;
            if (!this._isFiller(x, ny)) {
                this._removeExitByXY('S', x, y);
                this._removeExitByXY('N', x, ny);
            }
        }

    };

    this._isFiller = function(x, y) {
        console.log(`isFiller x,y ${x},${y}`);
        return this.templMap[x][y].getProp('name') === 'FILLER';
    };

    this._removeExitByXY = function(dir, x, y) {
        if (this._hasExit(dir, x, y)) {
            this._removeChosenExit(x, y, dir);
        }
    };

    this._hasExit = function(dir, x, y) {
        const key = x + ',' + y;
        if (this.freeExits[key]) {
            return this.freeExits[key].indexOf(dir) >= 0;
        }
        return false;
    };

    this._cleanupAndTryAgain = function() {
        // Initialize a map with filler cells
        this.templMap = [];
        for (let x = 0; x < this.tilesX; x++) {
            this.templMap[x] = [];
            for (let y = 0; y < this.tilesY; y++) {
                this.templMap[x][y] = this.filler;
            }
        }
        this.freeExits = {};
        this._unusedExits = [];
        // this.create();
    };

};

module.exports = RG.Template.Level;
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import { formValueSelector, SubmissionError } from 'redux-form';
import PropTypes from 'prop-types';
import { path } from 'ramda';
import {
  Stepper,
  Step,
  StepContent,
  StepLabel,
} from '../customStepper';
import LegalStatus from './legalStatus';
import OrganizationType from './organizationType';
import BasicInformation from './basicInformation';
import RegistrationStep from './registrationStep';
import Declaration from './declaration';
import Account from './account';
import AlertDialog from '../common/alertDialog';
import { loadCountries } from '../../reducers/countries';
import { registerUser } from '../../reducers/session';
import { loadPartnerConfig } from '../../reducers/partnerProfileConfig';

const messages = {
  error: 'Registration failed',
  declarationInfo: 'You answered no to at least one of the questions, cannot proceed',
  warning: 'Warning',
  legalInfo: 'You have to upload at least one of Registration, Governing documents or letter of reference to proceed registration process',
};

class RegistrationStepper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      stepIndex: 0,
      lastStep: 4,
      declarationAlert: false,
      legalStatusAlert: false,
    };
    this.handleNext = this.handleNext.bind(this);
    this.handleNextQuestions = this.handleNextQuestions.bind(this);
    this.handleNextLegalStatus = this.handleNextLegalStatus.bind(this);
    this.handlePrev = this.handlePrev.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentWillMount() {
    this.props.loadCountries();
    this.props.loadPartnerConfig();
  }

  handleNext() {
    const { stepIndex } = this.state;
    this.setState({
      stepIndex: stepIndex + 1,
    });
  }

  handleNextQuestions() {
    const answers = this.props.answers;
    if (answers && answers.some(answer => answer === false)) {
      this.setState({ declarationAlert: true });
      return;
    }
    this.handleNext();
  }

  handleNextLegalStatus() {
    const legalStatusData = this.props.legalStatusData;

    if (!legalStatusData.have_gov_doc
      || !legalStatusData.have_ref_letter
      || !legalStatusData.have_registration_doc) {
      this.setState({ legalStatusAlert: true });
      return;
    }

    this.handleNext();
  }

  handlePrev() {
    const { stepIndex } = this.state;
    if (stepIndex > 0) {
      this.setState({ stepIndex: stepIndex - 1 });
    }
  }

  handleSubmit(values) {
    return this.props.registerUser(values.json).catch((error) => {
      const errorMsg = path(['response', 'data', 'non_field_errors'], error) || messages.error;
      if (error.response.data.user) {
        this.setState({ stepIndex: 3 });
      }
      throw new SubmissionError({
        json: { ...error.response.data },
        _error: errorMsg,
      });
    });
  }

  render() {
    const { stepIndex } = this.state;
    return (

        <Stepper linear activeStep={stepIndex} orientation="vertical">
          <Step>
            <StepLabel>Select type of organization</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNext} first>
                <OrganizationType />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Enter basic identification information</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNext} handlePrev={this.handlePrev}>
                <BasicInformation />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Legal Status</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNextLegalStatus} handlePrev={this.handlePrev}>
                <LegalStatus />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Partner Declaration</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNextQuestions} handlePrev={this.handlePrev}>
                <Declaration />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Provide e-mail and create password</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNext} handlePrev={this.handlePrev}>
                <Account />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Complete the process</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleSubmit} handlePrev={this.handlePrev} last />
            </StepContent>
          </Step>
        </Stepper>
        <AlertDialog
          trigger={!!this.state.declarationAlert}
          title={messages.warning}
          text={messages.declarationInfo}
          handleDialogClose={() => this.setState({ declarationAlert: false })}
        />
        <AlertDialog
          trigger={!!this.state.legalStatusAlert}
          title={messages.warning}
          text={messages.legalInfo}
          handleDialogClose={() => this.setState({ legalStatusAlert: false })}
        />

    );
  }
}
RegistrationStepper.propTypes = {
  /**
   * answers to all questions in declaration component, show dialog when at least one is false
   */
  answers: PropTypes.arrayOf(PropTypes.bool),
  legalStatusData: PropTypes.object,
  loadPartnerConfig: PropTypes.func,
  loadCountries: PropTypes.func,
  registerUser: PropTypes.func,
};

const selector = formValueSelector('registration');
const connectedRegistrationStepper = connect(
  state => ({
    answers: selector(state, 'questions'),
    legalStatusData: selector(state, 'json.legal'),
  }),
  dispatch => ({
    loadCountries: () => dispatch(loadCountries()),
    loadPartnerConfig: () => dispatch(loadPartnerConfig()),
    registerUser: values => dispatch(registerUser(values)),
  }),
)(RegistrationStepper);

export default connectedRegistrationStepper;
<commit_msg>comment legal status of registration<commit_after>import React from 'react';
import { connect } from 'react-redux';
import { formValueSelector, SubmissionError } from 'redux-form';
import PropTypes from 'prop-types';
import { path } from 'ramda';
import {
  Stepper,
  Step,
  StepContent,
  StepLabel,
} from '../customStepper';
import LegalStatus from './legalStatus';
import OrganizationType from './organizationType';
import BasicInformation from './basicInformation';
import RegistrationStep from './registrationStep';
import Declaration from './declaration';
import Account from './account';
import AlertDialog from '../common/alertDialog';
import { loadCountries } from '../../reducers/countries';
import { registerUser } from '../../reducers/session';
import { loadPartnerConfig } from '../../reducers/partnerProfileConfig';

const messages = {
  error: 'Registration failed',
  declarationInfo: 'You answered no to at least one of the questions, cannot proceed',
  warning: 'Warning',
  legalInfo: 'You have to upload at least one of Registration, Governing documents or letter of reference to proceed registration process',
};

class RegistrationStepper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      stepIndex: 0,
      lastStep: 4,
      declarationAlert: false,
      legalStatusAlert: false,
    };
    this.handleNext = this.handleNext.bind(this);
    this.handleNextQuestions = this.handleNextQuestions.bind(this);
    this.handleNextLegalStatus = this.handleNextLegalStatus.bind(this);
    this.handlePrev = this.handlePrev.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentWillMount() {
    this.props.loadCountries();
    this.props.loadPartnerConfig();
  }

  handleNext() {
    const { stepIndex } = this.state;
    this.setState({
      stepIndex: stepIndex + 1,
    });
  }

  handleNextQuestions() {
    const answers = this.props.answers;
    if (answers && answers.some(answer => answer === false)) {
      this.setState({ declarationAlert: true });
      return;
    }
    this.handleNext();
  }

  handleNextLegalStatus() {
    const legalStatusData = this.props.legalStatusData;

    if (!legalStatusData.have_gov_doc
      || !legalStatusData.have_ref_letter
      || !legalStatusData.have_registration_doc) {
      this.setState({ legalStatusAlert: true });
      return;
    }

    this.handleNext();
  }

  handlePrev() {
    const { stepIndex } = this.state;
    if (stepIndex > 0) {
      this.setState({ stepIndex: stepIndex - 1 });
    }
  }

  handleSubmit(values) {
    return this.props.registerUser(values.json).catch((error) => {
      const errorMsg = path(['response', 'data', 'non_field_errors'], error) || messages.error;
      if (error.response.data.user) {
        this.setState({ stepIndex: 3 });
      }
      throw new SubmissionError({
        json: { ...error.response.data },
        _error: errorMsg,
      });
    });
  }

  render() {
    const { stepIndex } = this.state;
    return (

        <Stepper linear activeStep={stepIndex} orientation="vertical">
          <Step>
            <StepLabel>Select type of organization</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNext} first>
                <OrganizationType />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Enter basic identification information</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNext} handlePrev={this.handlePrev}>
                <BasicInformation />
              </RegistrationStep>
            </StepContent>
          </Step>
          {/* <Step>
            <StepLabel>Legal Status</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNextLegalStatus} handlePrev={this.handlePrev}>
                <LegalStatus />
              </RegistrationStep>
            </StepContent>
          </Step> */}
          <Step>
            <StepLabel>Partner Declaration</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNextQuestions} handlePrev={this.handlePrev}>
                <Declaration />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Provide e-mail and create password</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleNext} handlePrev={this.handlePrev}>
                <Account />
              </RegistrationStep>
            </StepContent>
          </Step>
          <Step>
            <StepLabel>Complete the process</StepLabel>
            <StepContent>
              <RegistrationStep onSubmit={this.handleSubmit} handlePrev={this.handlePrev} last />
            </StepContent>
          </Step>
        </Stepper>
        <AlertDialog
          trigger={!!this.state.declarationAlert}
          title={messages.warning}
          text={messages.declarationInfo}
          handleDialogClose={() => this.setState({ declarationAlert: false })}
        />
        <AlertDialog
          trigger={!!this.state.legalStatusAlert}
          title={messages.warning}
          text={messages.legalInfo}
          handleDialogClose={() => this.setState({ legalStatusAlert: false })}
        />

    );
  }
}
RegistrationStepper.propTypes = {
  /**
   * answers to all questions in declaration component, show dialog when at least one is false
   */
  answers: PropTypes.arrayOf(PropTypes.bool),
  legalStatusData: PropTypes.object,
  loadPartnerConfig: PropTypes.func,
  loadCountries: PropTypes.func,
  registerUser: PropTypes.func,
};

const selector = formValueSelector('registration');
const connectedRegistrationStepper = connect(
  state => ({
    answers: selector(state, 'questions'),
    legalStatusData: selector(state, 'json.legal'),
  }),
  dispatch => ({
    loadCountries: () => dispatch(loadCountries()),
    loadPartnerConfig: () => dispatch(loadPartnerConfig()),
    registerUser: values => dispatch(registerUser(values)),
  }),
)(RegistrationStepper);

export default connectedRegistrationStepper;
<|endoftext|>


<commit_before>import {LightningElement, api, track} from 'lwc';
import GeFormService from 'c/geFormService';

const LIGHTNING_INPUT_TYPES = ['CHECKBOX', 'CURRENCY', 'DATE', 'DATETIME', 'EMAIL', 'NUMBER', 'PERCENT', 'STRING', 'PHONE', 'TEXT', 'TIME', 'URL'];
const RICH_TEXT_TYPE = 'RICHTEXT';
const LOOKUP_TYPE = 'REFERENCE';
const PICKLIST_TYPE = 'PICKLIST';
const TEXT_AREA_TYPE = 'TEXTAREA';
const DELAY = 300;

export default class GeFormField extends LightningElement {
    @track value;
    @track picklistValues = [];
    @api element;

    changeTimeout;

    handleValueChange(event) {
        this.value = event.target.value;
        window.clearTimeout(this.changeTimeout);
        this.changeTimeout = setTimeout(() => {
            // parent component (formSection) should bind to onchange event
            const evt = new CustomEvent('change', {field: this.element, value: this.value});
            this.dispatchEvent(evt);
        }, DELAY);
    }

    @api
    get fieldAndValue() {
        let fieldAndValue = {};

        // KIET TBD: This is where we are keeping the field mapping
        // CMT record name at, element.value.
        // However, it may change to the array dataImportFieldMappingDevNames
        // If so, we need to update this to reflect that.
        // In the Execute Anonymous code, both fields are populated.
        fieldAndValue[this.element.value] = this.value;

        return fieldAndValue;
    }

    get inputType() {
        return GeFormService.getInputTypeFromDataType(this.fieldType);
    }

    get formatter() {
        return GeFormService.getNumberFormatterByDescribeType(this.fieldType);
    }

    get fieldInfo() {
        return GeFormService.getFieldMappingWrapper(this.element.value);
    }

    get objectInfo() {
        return GeFormService.getObjectMappingWrapper(this.objectDevName);
    }

    get fieldType() {
        return this.fieldInfo.Target_Field_Data_Type;
    }

    get isLightningInput() {
        return LIGHTNING_INPUT_TYPES.indexOf(this.fieldType) !== -1;
    }

    get isRichText() {
        return this.fieldType === RICH_TEXT_TYPE;
    }

    get isLookup() {
        return this.fieldType === LOOKUP_TYPE;
    }

    get isPicklist() {
        return this.fieldType === PICKLIST_TYPE;
    }

    get isTextArea() {
        return this.fieldType === TEXT_AREA_TYPE;
    }

    get objectDevName() {
        return this.fieldInfo.Target_Object_Mapping_Dev_Name;
    }

    get objectApiName() {
        return this.objectInfo.Object_API_Name;
    }

    get fieldApiName() {
        return this.fieldInfo.Target_Field_API_Name;
    }
}<commit_msg>added fix for checkboxes-the field type is boolean<commit_after>import {LightningElement, api, track} from 'lwc';
import GeFormService from 'c/geFormService';

const LIGHTNING_INPUT_TYPES = ['BOOLEAN', 'CURRENCY', 'DATE', 'DATETIME', 'EMAIL', 'NUMBER', 'PERCENT', 'STRING', 'PHONE', 'TEXT', 'TIME', 'URL'];
const RICH_TEXT_TYPE = 'RICHTEXT';
const LOOKUP_TYPE = 'REFERENCE';
const PICKLIST_TYPE = 'PICKLIST';
const TEXT_AREA_TYPE = 'TEXTAREA';
const BOOLEAN_TYPE = 'BOOLEAN';
const CHECKBOX_TYPE = 'CHECKBOX';
const DELAY = 300;

export default class GeFormField extends LightningElement {
    @track value;
    @track picklistValues = [];
    @api element;

    changeTimeout;

    handleValueChange(event) {
        this.value = event.target.value;
        window.clearTimeout(this.changeTimeout);
        this.changeTimeout = setTimeout(() => {
            // parent component (formSection) should bind to onchange event
            const evt = new CustomEvent('change', {field: this.element, value: this.value});
            this.dispatchEvent(evt);
        }, DELAY);
    }

    @api
    get fieldAndValue() {
        let fieldAndValue = {};

        // KIET TBD: This is where we are keeping the field mapping
        // CMT record name at, element.value.
        // However, it may change to the array dataImportFieldMappingDevNames
        // If so, we need to update this to reflect that.
        // In the Execute Anonymous code, both fields are populated.
        fieldAndValue[this.element.value] = this.value;

        return fieldAndValue;
    }

    get inputType() {
        // the field type is boolean, not checkbox
        if (this.fieldType === BOOLEAN_TYPE) {
            return CHECKBOX_TYPE;
        }
        return GeFormService.getInputTypeFromDataType(this.fieldType);
    }

    get formatter() {
        return GeFormService.getNumberFormatterByDescribeType(this.fieldType);
    }

    get fieldInfo() {
        return GeFormService.getFieldMappingWrapper(this.element.value);
    }

    get objectInfo() {
        return GeFormService.getObjectMappingWrapper(this.objectDevName);
    }

    get fieldType() {
        return this.fieldInfo.Target_Field_Data_Type;
    }

    get isLightningInput() {
        return LIGHTNING_INPUT_TYPES.indexOf(this.fieldType) !== -1;
    }

    get isRichText() {
        return this.fieldType === RICH_TEXT_TYPE;
    }

    get isLookup() {
        return this.fieldType === LOOKUP_TYPE;
    }

    get isPicklist() {
        return this.fieldType === PICKLIST_TYPE;
    }

    get isTextArea() {
        return this.fieldType === TEXT_AREA_TYPE;
    }

    get objectDevName() {
        return this.fieldInfo.Target_Object_Mapping_Dev_Name;
    }

    get objectApiName() {
        return this.objectInfo.Object_API_Name;
    }

    get fieldApiName() {
        return this.fieldInfo.Target_Field_API_Name;
    }
}<|endoftext|>


<commit_before>import API from './api';

export default {
  getAll: () => API.get('promo'),
};
<commit_msg>cambio de GET a /promos<commit_after>import API from './api';

export default {
  getAll: () => API.get('promos'),
};
<|endoftext|>


<commit_before>define(["Cell", "process/Move", "process/Strategy"],
    function(Cell, Move, Strategy)
    {
        "use strict";

        function SudokuSolver(strategiesIn)
        {
            // strategies optional.

            var strategies = (strategiesIn !== undefined ? strategiesIn : [Strategy.NakedSingle, Strategy.NakedPair]);

            this.strategies = function()
            {
                return strategies;
            };
        }

        SudokuSolver.prototype.forwardSearch = function(puzzle, solver)
        {
            InputValidator.validateNotNull("puzzle", puzzle);
            InputValidator.validateNotNull("solver", solver);

            // Try two candidate cell values.
            var indices = puzzle.findCellsWithCandidateLength(2);
            var answer;

            for (var i = 0; i < indices.length && answer === undefined; i++)
            {
                var index = indices[i];
                var cell = puzzle.get(index);
                var candidates = cell.candidates();

                for (var j = 0; j < candidates.size && answer === undefined; j++)
                {
                    var candidate = candidates.get(j);
                    var puzzleClone = puzzle.withCell(index, new Cell.Value(candidate));
                    puzzleClone = puzzleClone.adjustCandidates();
                    puzzleClone = solver.solve(puzzleClone);

                    if (solver.isDone(puzzleClone))
                    {
                        answer = new Move.SetCellValue(puzzle, index, candidate, "forward search");
                    }
                }
            }

            return answer;
        };

        SudokuSolver.prototype.getMove = function(puzzle)
        {
            InputValidator.validateNotNull("puzzle", puzzle);

            var answer;
            var strategies = this.strategies();

            for (var i = 0; i < strategies.length && answer === undefined; i++)
            {
                var strategy = strategies[i];
                answer = strategy.getMove(puzzle);
            }

            if (answer === undefined)
            {
                answer = this.forwardSearch(puzzle, this);
            }

            return answer;
        };

        SudokuSolver.prototype.isDone = function(puzzle)
        {
            InputValidator.validateNotNull("puzzle", puzzle);

            for (var i = 0; i < puzzle.cells().size; i++)
            {
                var cell = puzzle.get(i);

                if (cell.isCandidates === true)
                {
                    return false;
                }
            }

            return true;
        };

        SudokuSolver.prototype.solve = function(puzzle)
        {
            InputValidator.validateNotNull("puzzle", puzzle);

            LOGGER.trace("solve() start");

            var myPuzzle = puzzle;
            myPuzzle = myPuzzle.adjustCandidates();
            var start = new Date().getTime();
            var maxTries = 81;
            var count = 0;

            while (!this.isDone(myPuzzle) && count < maxTries)
            {
                var move = this.getMove(myPuzzle);

                if (move === undefined)
                {
                    break;
                }

                myPuzzle = move.execute();
                count++;
            }

            LOGGER.time("solve()", start, new Date().getTime());
            LOGGER.trace("solve() end");

            return myPuzzle;
        };

        return SudokuSolver;
    });
<commit_msg>Made the forward search optional.<commit_after>define(["Cell", "process/Move", "process/Strategy"],
    function(Cell, Move, Strategy)
    {
        "use strict";

        function SudokuSolver(useForwardSearchIn, strategiesIn)
        {
            // useForwardSearch optional. default: true
            // strategies optional.

            var useForwardSearch = (useForwardSearchIn !== undefined ? useForwardSearchIn : true);
            var strategies = (strategiesIn !== undefined ? strategiesIn : [Strategy.NakedSingle, Strategy.NakedPair]);

            this.useForwardSearch = function()
            {
                return useForwardSearch;
            };

            this.strategies = function()
            {
                return strategies;
            };
        }

        SudokuSolver.prototype.forwardSearch = function(puzzle)
        {
            InputValidator.validateNotNull("puzzle", puzzle);

            // Try two candidate cell values.
            var indices = puzzle.findCellsWithCandidateLength(2);
            var useForwardSearch = false;
            var solver = new SudokuSolver(useForwardSearch);
            var answer;

            for (var i = 0; i < indices.length && answer === undefined; i++)
            {
                var index = indices[i];
                var cell = puzzle.get(index);
                var candidates = cell.candidates();

                for (var j = 0; j < candidates.size && answer === undefined; j++)
                {
                    var candidate = candidates.get(j);
                    var puzzleClone = puzzle.withCell(index, new Cell.Value(candidate));
                    puzzleClone = puzzleClone.adjustCandidates();
                    puzzleClone = solver.solve(puzzleClone);

                    if (solver.isDone(puzzleClone))
                    {
                        answer = new Move.SetCellValue(puzzle, index, candidate, "forward search");
                    }
                }
            }

            return answer;
        };

        SudokuSolver.prototype.getMove = function(puzzle)
        {
            InputValidator.validateNotNull("puzzle", puzzle);

            var answer;
            var strategies = this.strategies();

            for (var i = 0; i < strategies.length && answer === undefined; i++)
            {
                var strategy = strategies[i];
                answer = strategy.getMove(puzzle);
            }

            if (this.useForwardSearch() && answer === undefined)
            {
                answer = this.forwardSearch(puzzle);
            }

            return answer;
        };

        SudokuSolver.prototype.isDone = function(puzzle)
        {
            InputValidator.validateNotNull("puzzle", puzzle);

            for (var i = 0; i < puzzle.cells().size; i++)
            {
                var cell = puzzle.get(i);

                if (cell.isCandidates === true)
                {
                    return false;
                }
            }

            return true;
        };

        SudokuSolver.prototype.solve = function(puzzle)
        {
            InputValidator.validateNotNull("puzzle", puzzle);

            LOGGER.trace("solve() start");

            var myPuzzle = puzzle;
            myPuzzle = myPuzzle.adjustCandidates();
            var start = new Date().getTime();
            var maxTries = 81;
            var count = 0;

            while (!this.isDone(myPuzzle) && count < maxTries)
            {
                var move = this.getMove(myPuzzle);

                if (move === undefined)
                {
                    break;
                }

                myPuzzle = move.execute();
                count++;
            }

            LOGGER.time("solve()", start, new Date().getTime());
            LOGGER.trace("solve() end");

            return myPuzzle;
        };

        return SudokuSolver;
    });
<|endoftext|>


<commit_before>import { browserHistory } from 'react-router';
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import { routerMiddleware, routerReducer } from 'react-router-redux';
import thunk from 'redux-thunk';
// Reducers
import location from './reducer/location';

// Enable ReduxDevTools (if installed) only in development and only in client.
const ReduxDevTools = (
  process.env.BROWSER === true &&
  process.env.NODE_ENV === 'development' ? window.devToolsExtension : false
);

// Store
const store = createStore(
  combineReducers({ // Reducers
    location,
    routing: routerReducer,
  }),
  // process.env.BROWSER ? window.PRELOADED_STATE : {}, // Default state
  compose( // Middleware
    applyMiddleware(thunk),
    applyMiddleware(routerMiddleware(browserHistory)), // Manage navigation events via Redux actions
    ReduxDevTools ? ReduxDevTools() : f => f,
  ),
);
export default store;
<commit_msg>Adds hot reloading when Redux stores are modified.<commit_after>import { browserHistory } from 'react-router';
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import { routerMiddleware, routerReducer } from 'react-router-redux';
import thunk from 'redux-thunk';
// Reducers
import location from './reducer/location';

// Enable ReduxDevTools (if installed) only in development and only in client.
const ReduxDevTools = (
  process.env.BROWSER === true &&
  process.env.NODE_ENV === 'development' ? window.devToolsExtension : false
);

// Return all reducers
const getReducers = () => combineReducers({
  location,
  routing: routerReducer,
});

// Store
const store = createStore(
  getReducers(),
  compose( // Middleware
    applyMiddleware(thunk),
    applyMiddleware(routerMiddleware(browserHistory)), // Manage navigation events via Redux actions
    ReduxDevTools ? ReduxDevTools() : f => f,
  ),
);

// Hot reload! Redux
if (module.hot) {
  module.hot.accept('./reducers/', () => {
    store.replaceReducer(getReducers());
  });
}
export default store;
<|endoftext|>


<commit_before>'use strict'

const FS = require('fs')
const Base = require('./base')

class GenericPlugin extends Base {
  constructor() {
    super()
    this.registerTag(['Compiler-Include'], function(name, value) {
      return new Promise((resolve, reject) =>
        FS.readFile(value, function(err, data) {
          if (err) reject(err)
          else resolve(data.toString())
        })
      )
    })
  }
  compile(contents, options) {
    return this.executeTags(contents, options)
  }
}

module.exports = GenericPlugin
<commit_msg>:new: Add Compiler-Output tag support<commit_after>'use strict'

const FS = require('fs')
const Base = require('./base')

class GenericPlugin extends Base {
  constructor() {
    super()
    this.registerTag(['Compiler-Include'], function(name, value) {
      return new Promise((resolve, reject) =>
        FS.readFile(value, function(err, data) {
          if (err) reject(err)
          else resolve(data.toString())
        })
      )
    })
    this.registerTag(['Compiler-Output'], function(name, value, contents, options) {
      options.Output = value
    })
  }
  compile(contents, options) {
    return this.executeTags(contents, options)
  }
}

module.exports = GenericPlugin
<|endoftext|>


<commit_before>
const RG = require('./rg');
const debug = require('debug')('bitn:WorldFromJSON');

/* This class converts a serialized world back to World.Top object. It supports
 * unloaded AreaTiles, and does not create them as objects. */
export default class WorldFromJSON {

    constructor(id2level) {
        this.id2level = id2level;
        this._conf = new RG.Factory.ConfStack();
        this._verif = new RG.Verify.Conf('WorldFromJSON');
        this.worldElemByID = {}; // Stores world elements by ID
        this.createAllZones = true;
    }

    createWorld(placeJSON) {
        let world = null;
        if (placeJSON.conf) {
            this.dbg('Creating a restored world now');
            world = this.createRestoredWorld(placeJSON);
        }
        else {
            RG.err('WorldFromJSON', 'Should not be called at all.', 'ERROR');
            this.dbg('Creating world using Factory.World fully');
            const fact = new RG.Factory.World();
            fact.setId2Level(this.id2level);
            world = fact.createWorld(placeJSON);
        }
        return world;
    }

    /* Given a serialized world in JSON, returns the created World.Top object.
     * */
    createRestoredWorld(worldJSON) {
        if (!worldJSON.conf) {
            RG.err('WorldFromJSON', 'createRestoredWorld',
                'No worldJSON.conf. Does not look like restored world.');
        }
        const world = this.createWorldFromJSON(worldJSON);

        // Need to restore configurations here
        world.setConf(worldJSON.conf);

        const areas = world.getAreas();
        if (areas.length > 0) {
            const keys = `${Object.keys(worldJSON.conf)}`;
            if (!worldJSON.conf.hasOwnProperty('area')) {
                RG.err('WorldFromJSON', 'createRestoredWorld',
                    `No prop 'area' in ${worldJSON.conf}. Props ${keys}`);
            }
        }

        areas.forEach((area, i) => {
            area.setConf(worldJSON.conf.area[i]);
        });
        return world;
    }

    pushScope(json) {
        this._conf.pushScope(json);
        this.fact.pushScope(json);
    }

    popScope(json) {
        this._conf.popScope(json);
        this.fact.popScope(json);
    }

    getHierName() {return this._conf.getScope().join('.');}

    createWorldFromJSON(worldJSON) {
        const fact = new RG.Factory.World();
        fact.setId2Level(this.id2level);
        this.fact = fact;

        this.verify('createWorld', worldJSON, ['name', 'nAreas']);
        if (worldJSON.hasOwnProperty('createAllZones')) {
            this.createAllZones = worldJSON.createAllZones;
            this.dbg('createAllZones set to ' + this.createAllZones);
            fact.createAllZones = this.createAllZones;
        }
        this.pushScope(worldJSON);
        const world = new RG.World.Top(worldJSON.name);
        world.setConf(worldJSON);
        for (let i = 0; i < worldJSON.nAreas; i++) {
            const areaConf = worldJSON.area[i];

            // Factory.World START
            const area = this.fact.createArea(areaConf);

            if (areaConf.zonesCreated) { // Only during restore game
                this.fact.restoreCreatedZones(world, area, areaConf);
            }
            // Factory.World END

            world.addArea(area);
            this.addWorldID(areaConf, area);
        }
        this.popScope(worldJSON);
        this.addWorldID(worldJSON, world);
        return world;
    }

    /* Creates an area which can be added to a world. */
    createArea(conf) {
        this.verify('createArea', conf,
            ['name', 'maxX', 'maxY']);
        this.pushScope(conf);

        // >>>>>>>>>>>>>>>>>> Factory.World START
        let areaLevels = null;
        if (this.id2levelSet) {
            areaLevels = this.fact.getAreaLevels(conf);
        }

        const area = new RG.World.Area(conf.name, conf.maxX, conf.maxY,
            conf.cols, conf.rows, areaLevels);
        area.setConf(conf);
        area.setHierName(this.getHierName());

        // When player enters a given area tile, create zones for that tile
        if (this.createAllZones) {
            this.fact._createAllZones(area, conf);
        // >>>>>>>>>>>>>>>>>> Factory.World END
            area.markAllZonesCreated();
        }
        else {
            this.dbg('Skipping the zone creating due to createZones=false');
        }
        this.popScope(conf);
        return area;
    }

    /* Adds a world ID to given world element. */
    addWorldID(conf, worldElem) {
        if (!RG.isNullOrUndef([conf.id])) {
            worldElem.setID(conf.id);
        }
        this.worldElemByID[worldElem.getID()] = worldElem;
    }

    dbg(msg) {
        if (debug.enabled) {
            console.log(msg);
        }
    }

    /* Verifies that given config is OK. */
    verify(funcName, conf, list) {
        this._verif.verifyConf(funcName, conf, list);
    }

}
<commit_msg>Added getAreaLevels() and removed unneeded code left over from Factory.World.<commit_after>
const RG = require('./rg');
const debug = require('debug')('bitn:WorldFromJSON');

/* This class converts a serialized world back to World.Top object. It supports
 * unloaded AreaTiles, and does not create them as objects. */
export default class WorldFromJSON {

    constructor(id2level) {
        this.id2level = id2level;
        this._conf = new RG.Factory.ConfStack();
        this._verif = new RG.Verify.Conf('WorldFromJSON');
        this.worldElemByID = {}; // Stores world elements by ID
        this.createAllZones = true;
        this._IND = 0; // Used for indenting debug messages
    }

    createWorld(placeJSON) {
        let world = null;
        if (placeJSON.conf) {
            this.dbg('Creating a restored world now');
            world = this.createRestoredWorld(placeJSON);
        }
        else {
            RG.err('WorldFromJSON', 'Should not be called at all.', 'ERROR');
            this.dbg('Creating world using Factory.World fully');
            const fact = new RG.Factory.World();
            fact.setId2Level(this.id2level);
            world = fact.createWorld(placeJSON);
        }
        return world;
    }

    /* Given a serialized world in JSON, returns the created World.Top object.
     * */
    createRestoredWorld(worldJSON) {
        if (!worldJSON.conf) {
            RG.err('WorldFromJSON', 'createRestoredWorld',
                'No worldJSON.conf. Does not look like restored world.');
        }
        const world = this.createWorldFromJSON(worldJSON);

        // Need to restore configurations here
        world.setConf(worldJSON.conf);

        const areas = world.getAreas();
        if (areas.length > 0) {
            const keys = `${Object.keys(worldJSON.conf)}`;
            if (!worldJSON.conf.hasOwnProperty('area')) {
                RG.err('WorldFromJSON', 'createRestoredWorld',
                    `No prop 'area' in ${worldJSON.conf}. Props ${keys}`);
            }
        }

        areas.forEach((area, i) => {
            area.setConf(worldJSON.conf.area[i]);
        });
        return world;
    }

    pushScope(json) {
        this._conf.pushScope(json);
        this.fact.pushScope(json);
        ++this.IND;
    }

    popScope(json) {
        this._conf.popScope(json);
        this.fact.popScope(json);
        --this.IND;
    }

    getHierName() {return this._conf.getScope().join('.');}

    createWorldFromJSON(worldJSON) {
        const fact = new RG.Factory.World();
        fact.setId2Level(this.id2level);
        this.fact = fact;

        this.verify('createWorld', worldJSON, ['name', 'nAreas']);
        if (worldJSON.hasOwnProperty('createAllZones')) {
            this.createAllZones = worldJSON.createAllZones;
            this.dbg('createAllZones set to ' + this.createAllZones);
            fact.createAllZones = this.createAllZones;
        }
        this.pushScope(worldJSON);
        const world = new RG.World.Top(worldJSON.name);
        world.setConf(worldJSON);
        for (let i = 0; i < worldJSON.nAreas; i++) {
            const areaJSON = worldJSON.area[i];
            this.printKeys('areaJSON keys', areaJSON);
            const area = this.createArea(areaJSON);

            // >>>>>>>>>>>>>>>>>>>>>> Factory.World START
            if (areaJSON.zonesCreated) { // Only during restore game
                this.fact.restoreCreatedZones(world, area, areaJSON);
            }
            // >>>>>>>>>>>>>>>>>>>>>> Factory.World END

            world.addArea(area);
            this.addWorldID(areaJSON, area);
        }
        this.popScope(worldJSON);
        this.addWorldID(worldJSON, world);
        return world;
    }

    /* Creates an area which can be added to a world. */
    createArea(areaJSON) {
        this.verify('createArea', areaJSON,
            ['name', 'maxX', 'maxY']);
        this.pushScope(areaJSON);

        const areaLevels = this.getAreaLevels(areaJSON);

        const {name, maxX, maxY, cols, rows} = areaJSON;
        const area = new RG.World.Area(name, maxX, maxY, cols, rows,
            areaLevels);
        area.setConf(areaJSON);
        area.setHierName(this.getHierName());

        // When player enters a given area tile, create zones for that tile
        if (this.createAllZones) {
        // >>>>>>>>>>>>>>>>>> Factory.World START
            this.fact._createAllZones(area, areaJSON);
        // >>>>>>>>>>>>>>>>>> Factory.World END
            area.markAllZonesCreated();
        }
        else {
            this.dbg('Skipping the zone creating due to createZones=false');
        }
        this.popScope(areaJSON);
        return area;
    }

    /* Used when creating area from existing levels. Uses id2level lookup table
     * to construct 2-d array of levels.*/
    getAreaLevels(areaJSON) {
        this.verify('getAreaLevels', areaJSON, ['tilesLoaded']);
        ++this._IND;
        const levels = [];
        if (areaJSON.tiles) {
            areaJSON.tiles.forEach((tileCol, x) => {
                const levelCol = [];
                tileCol.forEach((tile, y) => {
                    if (areaJSON.tilesLoaded[x][y]) {
                        this.dbg(`Tile ${x},${y} is loaded`);
                        const level = this.id2level[tile.level];
                        if (level) {
                            levelCol.push(level);
                        }
                        else {
                            RG.err('WorldFromJSON', 'getAreaLevels',
                                `No level ID ${tile.level} in id2level`);
                        }
                    }
                    else {
                        this.dbg(`Will NOT load Tile ${x},${y}`);
                    }
                });
                levels.push(levelCol);
            });
        }
        else {
            RG.err('WorldFromJSON', 'getAreaLevels',
                'areaJSON.tiles cannot be null/undefined');
        }
        --this._IND;
        return levels;
    }

    /* Adds a world ID to given world element. */
    addWorldID(conf, worldElem) {
        if (!RG.isNullOrUndef([conf.id])) {
            worldElem.setID(conf.id);
        }
        this.worldElemByID[worldElem.getID()] = worldElem;
    }

    dbg(msg) {
        if (debug.enabled) {
            const ind = ' '.repeat(this._IND);
            console.log(ind + msg);
        }
    }

    /* Verifies that given config is OK. */
    verify(funcName, conf, list) {
        this._verif.verifyConf(funcName, conf, list);
    }

    printKeys(msg, obj) {
        console.log(msg);
        console.log(Object.keys(obj));
    }

}
<|endoftext|>


<commit_before>const gulp = require('gulp');
const replace = require('gulp-replace');

const Builder = require('jspm').Builder;

const conf = require('../conf/gulp.conf');

gulp.task('systemjs', systemjs);
gulp.task('systemjs:html', updateIndexHtml);

function systemjs(done) {
  const builder = new Builder('./', 'jspm.config.js');
  builder.config({
    paths: {
      "github:*": "jspm_packages/github/*",
      "npm:*": "jspm_packages/npm/*"
    },
    packageConfigPaths: [
      'npm:@*/*.json',
      'npm:*.json',
      'github:*/*.json'
    ]
  });
  builder.buildStatic(
    <%- entry %>,
    conf.path.tmp('index.js')
  ).then(() => done(), done);
}

function updateIndexHtml() {
  return gulp.src(conf.path.src('index.html'))
    .pipe(replace(
      /<script[\s\S]*script>/,
      `<script src="index.js"></script>`
    ))
    .pipe(gulp.dest(conf.path.tmp()));
}
<commit_msg>More precise updateIndexHtml regex for build<commit_after>const gulp = require('gulp');
const replace = require('gulp-replace');

const Builder = require('jspm').Builder;

const conf = require('../conf/gulp.conf');

gulp.task('systemjs', systemjs);
gulp.task('systemjs:html', updateIndexHtml);

function systemjs(done) {
  const builder = new Builder('./', 'jspm.config.js');
  builder.config({
    paths: {
      "github:*": "jspm_packages/github/*",
      "npm:*": "jspm_packages/npm/*"
    },
    packageConfigPaths: [
      'npm:@*/*.json',
      'npm:*.json',
      'github:*/*.json'
    ]
  });
  builder.buildStatic(
    <%- entry %>,
    conf.path.tmp('index.js')
  ).then(() => done(), done);
}

function updateIndexHtml() {
  return gulp.src(conf.path.src('index.html'))
    .pipe(replace(
      /<script>\n\s*System.import.*\n\s*<\/script>/,
      `<script src="index.js"></script>`
    ))
    .pipe(gulp.dest(conf.path.tmp()));
}
<|endoftext|>


<commit_before>var fs = require("fs");
var path = require("path");

function HistoryPlugin(bot) {
	var self = this;
	self.name = "history";
	self.help = "History plugin";
	self.depend = ["cmd", "auth", "gist", "util"];

	self.basedir = null;

	self.grepRe = new RegExp(
		"(/)((?:\\\\\\1|(?!\\1).)+)" +
		"\\1([a-z]*)"); // simplified from sed plugin

	self.load = function(data) {
		if (data) {
			self.basedir = data.basedir;
		}
	};

	self.save = function() {
		return {basedir: self.basedir};
	};

	self.iterate = function(channel, lineCb, endCb, fileCb) {
		var re = /^(\d{4})-(\d{2})-(\d{2})\.log$/;

		var channelDir = path.join(self.basedir, channel);
		fs.readdir(channelDir, function(err, files) {
			if (err)
				bot.out.error("history", err);
			var logfiles = files.sort();

			var found = false;
			var func = function(logfiles) {
				if (!found && logfiles.length > 0) {
					var logfile = logfiles.pop();
					var match = logfile.match(re);

					fs.readFile(path.join(channelDir, logfile), {encoding: "utf8"}, function(err, data) {
						if (err)
							throw err;

						var lines = data.split("\n");

						for (var j = lines.length - 1 - 1; !found && j >= 0; j--) {
							if (!lineCb(lines[j]))
								found = true;
						}

						(fileCb || function(){})(logfile, match.slice(1, 3 + 1));

						func(logfiles);
					});
				}
				else {
					(endCb || function(){})(found);
				}
			};

			func(logfiles);
		});
	};

	self.makeWhoRe = function(who) {
		var escaped = bot.plugins.util.escapeRegExp(who);
		// TODO: http://stackoverflow.com/a/27191354/854540
		return new RegExp(
			"^\\[(\\d{2}:\\d{2}:\\d{2})\\] " +
			"(" +
				"<" + escaped + ">" + // PRIVMSG
			"|" +
				"-" + escaped + "-" + // NOTICE
			"|" +
				"\\* " + escaped +    // ACTION
			") (.*)$", "i");
	};

	self.makeModeRe = function(mode) {
		return new RegExp(
			"^\\[(\\d{2}:\\d{2}:\\d{2})\\] " +
			"\\*\\*\\* " +
			"(\\S+) sets mode: " +
			"(?:[+-][^\\s+-]+)*" +
			bot.plugins.util.escapeRegExp(mode[1]) + "\\S*" + bot.plugins.util.escapeRegExp(mode[2]), "");
	};

	self.events = {
		"cmd#history": function(nick, to, args) {
			var linecnt;
			var channel = to;
			var who = null;
			var mode = null;
			var re = null;
			var preSurround;
			var postSurround;
			var gist = false;
			var strip = false;

			for (var i = 1; i < args.length; i++) {
				var arg = args[i];
				var m;

				if (arg == "gist")
					gist = true;
				else if (arg.match(/^#/))
					channel = arg;
				else if (arg.match(/^\d+$/))
					linecnt = parseInt(arg);
				else if (m = arg.match(/^-(\d+)$/))
					preSurround = parseInt(m[1]);
				else if (m = arg.match(/^\+(\d+)$/))
					postSurround = parseInt(m[1]);
				else if (m = arg.match(/^([+-]?)([A-Za-z])$/))
					mode = m;
				else if (m = arg.match(/^(\w+)[,:]?$/))
					who = m[1];
				else if (m = arg.match(self.grepRe)) {
					var reFlags = m[3];
					re = new RegExp(m[2], bot.plugins.util.filterRegexFlags(reFlags));
					strip = reFlags.indexOf("c") >= 0;
				}
			}

			var whoRe = (who !== null ? self.makeWhoRe(who) : null);
			var modeRe = (mode !== null ? self.makeModeRe(mode) : null);
			preSurround = Math.min(preSurround !== undefined ? preSurround : (gist ? 5 : 3), gist ? 20 : 10);
			postSurround = Math.min(postSurround !== undefined ? postSurround : (gist ? 2 : 1), gist ? 20 : 10);

			var extra = channel == to;
			linecnt = Math.min(linecnt || (gist ? 50 : 15), re === null ? (gist ? 1000 : 50) : Math.ceil((gist ? 1000 : 50) / (preSurround + 1 + postSurround)));

			var argStr = "";
			if (who !== null) {
				argStr += who + ",";
			}
			if (re !== null) {
				argStr += (argStr ? " " : "") + "/" + re.source + "/" + re.toString().match(/[gimuy]*$/)[0]; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags
				argStr += " -" + preSurround.toString() + " +" + postSurround.toString();
			}
			argStr += (argStr ? " " : "") + linecnt.toString();

			var outlines = [];
			var context = [];
			var contextTodo = 0;
			var fileUsed = false;
			var contextEnded = false;
			self.iterate(channel, function(line) {
				if (extra) {
					extra = false;
					return true;
				}

				if (strip)
					line = bot.plugins.util.stripColors(line);

				if (linecnt > 0 &&
					(whoRe !== null ? line.match(whoRe) : true) &&
					(modeRe !== null ? line.match(modeRe) : true) &&
					(re === null || line.match(re))) {
					if (re !== null) {
						if (contextEnded) {
							outlines.unshift("\x031 --------");
							contextEnded = false;
						}
						//bot.out.debug("history", context);
						context.forEach(function(cline) {
							outlines.unshift(cline);
						});
						context = [];
						contextTodo = preSurround;
					}
					outlines.unshift(re !== null ? line.replace(re, "\x16$&\x16") : line); // highlight matches by color reversal

					linecnt--;
					fileUsed = true;
				}
				else if (re !== null) {
					if (contextTodo > 0) {
						outlines.unshift(line);
						contextTodo--;

						if (contextTodo == 0)
							contextEnded = true;
					}
					else if (context.length <= postSurround) {
						context.push(line);

						if (context.length > postSurround) // overflow -> rotate
							context.shift();
					}
				}

				return linecnt > 0 || contextTodo > 0;
			}, function() {
				if (outlines.length > 0) {
					if (gist) {
						bot.plugins.gist.create({
							"history.txt": outlines.map(bot.plugins.util.stripColors).join("\n")
						}, false, "History for " + channel + (argStr ? " (" + argStr + ")" : ""), function(data) {
							bot.say(to, nick + ": " + data.html_url);
						});
					}
					else {
						bot.say(nick, "\x031--- Begin history for " + channel + (argStr ? " (" + argStr + ")" : "") + " ---");
						for (var i = 0; i < outlines.length; i++) {
							var str = outlines[i];
							bot.say(nick, str);
						}
						bot.say(nick, "\x031--- End history for " + channel + (argStr ? " (" + argStr + ")" : "") + " ---");
					}
				}
				else {
					if (gist)
						bot.say(to, nick + ": no history");
					else
						bot.say(nick, "\x031--- No history ---");
				}
			}, function(logfile, date) {
				if (fileUsed) {
					outlines.unshift("\x031--- " + date.join("-") + " ---");
					fileUsed = false;
					contextEnded = false;
				}
			});
		},

		"cmd#gistory": function(nick, to, args) {
			bot.emit("cmd#history", nick, to, args.concat("gist")); // only appends the parsed arguments, not args[0]
		},

		"cmd#historycount": function(nick, to, args, message) {
			var channel = to;
			var re = null;

			for (var i = 1; i < args.length; i++) {
				var arg = args[i];

				if (arg.match(/^#/))
					channel = arg;
				else {
					var m = arg.match(self.grepRe);
					if (m) {
						re = new RegExp(m[2], bot.plugins.util.filterRegexFlags(m[3]));
					}
				}
			}

			message.authChannel = channel;

			bot.plugins.auth.proxy(2, message, function() {
				var cnt = 0;
				self.iterate(channel, function(line) {
					if (re !== null) {
						var m = line.match(re);
						cnt += (m || []).length;
					}
					else
						cnt++;

					return true; // continue forever
				}, function() {
					bot.say(to, nick + ": " + cnt);
				});
			});
		}
	};
}

module.exports = HistoryPlugin;
<commit_msg>history: support who and mode arguments in historycount<commit_after>var fs = require("fs");
var path = require("path");

function HistoryPlugin(bot) {
	var self = this;
	self.name = "history";
	self.help = "History plugin";
	self.depend = ["cmd", "auth", "gist", "util"];

	self.basedir = null;

	self.grepRe = new RegExp(
		"(/)((?:\\\\\\1|(?!\\1).)+)" +
		"\\1([a-z]*)"); // simplified from sed plugin

	self.load = function(data) {
		if (data) {
			self.basedir = data.basedir;
		}
	};

	self.save = function() {
		return {basedir: self.basedir};
	};

	self.iterate = function(channel, lineCb, endCb, fileCb) {
		var re = /^(\d{4})-(\d{2})-(\d{2})\.log$/;

		var channelDir = path.join(self.basedir, channel);
		fs.readdir(channelDir, function(err, files) {
			if (err)
				bot.out.error("history", err);
			var logfiles = files.sort();

			var found = false;
			var func = function(logfiles) {
				if (!found && logfiles.length > 0) {
					var logfile = logfiles.pop();
					var match = logfile.match(re);

					fs.readFile(path.join(channelDir, logfile), {encoding: "utf8"}, function(err, data) {
						if (err)
							throw err;

						var lines = data.split("\n");

						for (var j = lines.length - 1 - 1; !found && j >= 0; j--) {
							if (!lineCb(lines[j]))
								found = true;
						}

						(fileCb || function(){})(logfile, match.slice(1, 3 + 1));

						func(logfiles);
					});
				}
				else {
					(endCb || function(){})(found);
				}
			};

			func(logfiles);
		});
	};

	self.makeWhoRe = function(who) {
		var escaped = bot.plugins.util.escapeRegExp(who);
		// TODO: http://stackoverflow.com/a/27191354/854540
		return new RegExp(
			"^\\[(\\d{2}:\\d{2}:\\d{2})\\] " +
			"(" +
				"<" + escaped + ">" + // PRIVMSG
			"|" +
				"-" + escaped + "-" + // NOTICE
			"|" +
				"\\* " + escaped +    // ACTION
			") (.*)$", "i");
	};

	self.makeModeRe = function(mode) {
		return new RegExp(
			"^\\[(\\d{2}:\\d{2}:\\d{2})\\] " +
			"\\*\\*\\* " +
			"(\\S+) sets mode: " +
			"(?:[+-][^\\s+-]+)*" +
			bot.plugins.util.escapeRegExp(mode[1]) + "\\S*" + bot.plugins.util.escapeRegExp(mode[2]), "");
	};

	self.events = {
		"cmd#history": function(nick, to, args) {
			var linecnt;
			var channel = to;
			var who = null;
			var mode = null;
			var re = null;
			var preSurround;
			var postSurround;
			var gist = false;
			var strip = false;

			for (var i = 1; i < args.length; i++) {
				var arg = args[i];
				var m;

				if (arg == "gist")
					gist = true;
				else if (arg.match(/^#/))
					channel = arg;
				else if (arg.match(/^\d+$/))
					linecnt = parseInt(arg);
				else if (m = arg.match(/^-(\d+)$/))
					preSurround = parseInt(m[1]);
				else if (m = arg.match(/^\+(\d+)$/))
					postSurround = parseInt(m[1]);
				else if (m = arg.match(/^([+-]?)([A-Za-z])$/))
					mode = m;
				else if (m = arg.match(/^(\w+)[,:]?$/))
					who = m[1];
				else if (m = arg.match(self.grepRe)) {
					var reFlags = m[3];
					re = new RegExp(m[2], bot.plugins.util.filterRegexFlags(reFlags));
					strip = reFlags.indexOf("c") >= 0;
				}
			}

			var whoRe = (who !== null ? self.makeWhoRe(who) : null);
			var modeRe = (mode !== null ? self.makeModeRe(mode) : null);
			preSurround = Math.min(preSurround !== undefined ? preSurround : (gist ? 5 : 3), gist ? 20 : 10);
			postSurround = Math.min(postSurround !== undefined ? postSurround : (gist ? 2 : 1), gist ? 20 : 10);

			var extra = channel == to;
			linecnt = Math.min(linecnt || (gist ? 50 : 15), re === null ? (gist ? 1000 : 50) : Math.ceil((gist ? 1000 : 50) / (preSurround + 1 + postSurround)));

			var argStr = "";
			if (who !== null) {
				argStr += who + ",";
			}
			if (re !== null) {
				argStr += (argStr ? " " : "") + "/" + re.source + "/" + re.toString().match(/[gimuy]*$/)[0]; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags
				argStr += " -" + preSurround.toString() + " +" + postSurround.toString();
			}
			argStr += (argStr ? " " : "") + linecnt.toString();

			var outlines = [];
			var context = [];
			var contextTodo = 0;
			var fileUsed = false;
			var contextEnded = false;
			self.iterate(channel, function(line) {
				if (extra) {
					extra = false;
					return true;
				}

				if (strip)
					line = bot.plugins.util.stripColors(line);

				if (linecnt > 0 &&
					(whoRe !== null ? line.match(whoRe) : true) &&
					(modeRe !== null ? line.match(modeRe) : true) &&
					(re === null || line.match(re))) {
					if (re !== null) {
						if (contextEnded) {
							outlines.unshift("\x031 --------");
							contextEnded = false;
						}
						//bot.out.debug("history", context);
						context.forEach(function(cline) {
							outlines.unshift(cline);
						});
						context = [];
						contextTodo = preSurround;
					}
					outlines.unshift(re !== null ? line.replace(re, "\x16$&\x16") : line); // highlight matches by color reversal

					linecnt--;
					fileUsed = true;
				}
				else if (re !== null) {
					if (contextTodo > 0) {
						outlines.unshift(line);
						contextTodo--;

						if (contextTodo == 0)
							contextEnded = true;
					}
					else if (context.length <= postSurround) {
						context.push(line);

						if (context.length > postSurround) // overflow -> rotate
							context.shift();
					}
				}

				return linecnt > 0 || contextTodo > 0;
			}, function() {
				if (outlines.length > 0) {
					if (gist) {
						bot.plugins.gist.create({
							"history.txt": outlines.map(bot.plugins.util.stripColors).join("\n")
						}, false, "History for " + channel + (argStr ? " (" + argStr + ")" : ""), function(data) {
							bot.say(to, nick + ": " + data.html_url);
						});
					}
					else {
						bot.say(nick, "\x031--- Begin history for " + channel + (argStr ? " (" + argStr + ")" : "") + " ---");
						for (var i = 0; i < outlines.length; i++) {
							var str = outlines[i];
							bot.say(nick, str);
						}
						bot.say(nick, "\x031--- End history for " + channel + (argStr ? " (" + argStr + ")" : "") + " ---");
					}
				}
				else {
					if (gist)
						bot.say(to, nick + ": no history");
					else
						bot.say(nick, "\x031--- No history ---");
				}
			}, function(logfile, date) {
				if (fileUsed) {
					outlines.unshift("\x031--- " + date.join("-") + " ---");
					fileUsed = false;
					contextEnded = false;
				}
			});
		},

		"cmd#gistory": function(nick, to, args) {
			bot.emit("cmd#history", nick, to, args.concat("gist")); // only appends the parsed arguments, not args[0]
		},

		"cmd#historycount": function(nick, to, args, message) {
			var channel = to;
			var who = null;
			var mode = null;
			var re = null;
			var strip = false;

			for (var i = 1; i < args.length; i++) {
				var arg = args[i];
				var m;

				if (arg.match(/^#/))
					channel = arg;
				else if (m = arg.match(/^([+-]?)([A-Za-z])$/))
					mode = m;
				else if (m = arg.match(/^(\w+)[,:]?$/))
					who = m[1];
				else if (m = arg.match(self.grepRe)) {
					var reFlags = m[3];
					re = new RegExp(m[2], bot.plugins.util.filterRegexFlags(reFlags));
					strip = reFlags.indexOf("c") >= 0;
				}
			}

			var whoRe = (who !== null ? self.makeWhoRe(who) : null);
			var modeRe = (mode !== null ? self.makeModeRe(mode) : null);

			message.authChannel = channel;

			bot.plugins.auth.proxy(2, message, function() {
				var cnt = 0;
				self.iterate(channel, function(line) {
					if (strip)
						line = bot.plugins.util.stripColors(line);

					var m;
					if ((whoRe !== null ? line.match(whoRe) : true) &&
						(modeRe !== null ? line.match(modeRe) : true) &&
						(re === null || (m = line.match(re)))) {
						if (re !== null)
							cnt += (m || []).length;
						else
							cnt++;
					}

					return true; // continue forever
				}, function() {
					bot.say(to, nick + ": " + cnt);
				});
			});
		}
	};
}

module.exports = HistoryPlugin;
<|endoftext|>


<commit_before>Template.betItem.events({
  'click #remove' : function(){
    Bets.remove(this._id)
  }
})
<commit_msg>Template: clicking accept button updates status to pending<commit_after>Template.betItem.events({
  'click #remove' : function(){
    Bets.remove(this._id)
  },

  'click .accept_button' : function() {
    Bets.update({_id: this._id}, { $set: { status: "pending" }})
  }
})
<|endoftext|>


<commit_before>import Component from 'ember-component';
import computed from 'ember-computed';
import ghostPaths from 'ghost-admin/utils/ghost-paths';
import injectService from 'ember-service/inject';
import run from 'ember-runloop';
import {
    UnsupportedMediaTypeError,
    isRequestEntityTooLargeError,
    isUnsupportedMediaTypeError,
    isVersionMismatchError
} from 'ghost-admin/services/ajax';
import {assign} from '@ember/polyfills';
import {htmlSafe} from 'ember-string';
import {invokeAction} from 'ember-invoke-action';
import {isBlank} from 'ember-utils';
import {isEmberArray} from 'ember-array/utils';

export const IMAGE_MIME_TYPES = 'image/gif,image/jpg,image/jpeg,image/png,image/svg+xml';
export const IMAGE_EXTENSIONS = ['gif', 'jpg', 'jpeg', 'png', 'svg'];

export default Component.extend({
    ajax: injectService(),
    notifications: injectService(),
    settings: injectService(),

    tagName: 'section',
    classNames: ['gh-image-uploader'],
    classNameBindings: ['dragClass'],

    image: null,
    text: '',
    altText: '',
    saveButton: true,
    accept: null,
    extensions: null,
    uploadUrl: null,
    validate: null,
    allowUnsplash: false,

    dragClass: null,
    failureMessage: null,
    file: null,
    url: null,
    uploadPercentage: 0,

    _defaultAccept: IMAGE_MIME_TYPES,
    _defaultExtensions: IMAGE_EXTENSIONS,
    _defaultUploadUrl: '/uploads/',
    _showUnsplash: false,

    // TODO: this wouldn't be necessary if the server could accept direct
    // file uploads
    formData: computed('file', function () {
        let file = this.get('file');
        let formData = new FormData();

        formData.append('uploadimage', file);

        return formData;
    }),

    description: computed('text', 'altText', function () {
        let altText = this.get('altText');

        return this.get('text') || (altText ? `Upload image of "${altText}"` : 'Upload an image');
    }),

    progressStyle: computed('uploadPercentage', function () {
        let percentage = this.get('uploadPercentage');
        let width = '';

        if (percentage > 0) {
            width = `${percentage}%`;
        } else {
            width = '0';
        }

        return htmlSafe(`width: ${width}`);
    }),

    // HACK: this settings/config dance is needed because the "override" only
    // happens when visiting the unsplash app settings route
    // TODO: move the override logic to the server, client knows too much
    // about which values should override others
    unsplash: computed('config.unsplashAPI', 'settings.unsplash', function () {
        let unsplashConfig = this.get('config.unsplashAPI');
        let unsplashSettings = this.get('settings.unsplash');
        let unsplash = assign({}, unsplashConfig, unsplashSettings);

        return unsplash;
    }),

    didReceiveAttrs() {
        let image = this.get('image');
        this.set('url', image);

        if (!this.get('accept')) {
            this.set('accept', this.get('_defaultAccept'));
        }
        if (!this.get('extensions')) {
            this.set('extensions', this.get('_defaultExtensions'));
        }
        if (!this.get('uploadUrl')) {
            this.set('uploadUrl', this.get('_defaultUploadUrl'));
        }
    },

    dragOver(event) {
        if (!event.dataTransfer) {
            return;
        }

        // this is needed to work around inconsistencies with dropping files
        // from Chrome's downloads bar
        let eA = event.dataTransfer.effectAllowed;
        event.dataTransfer.dropEffect = (eA === 'move' || eA === 'linkMove') ? 'move' : 'copy';

        event.stopPropagation();
        event.preventDefault();

        this.set('dragClass', '-drag-over');
    },

    dragLeave(event) {
        event.preventDefault();
        this.set('dragClass', null);
    },

    drop(event) {
        event.preventDefault();

        this.set('dragClass', null);

        if (event.dataTransfer.files) {
            this.send('fileSelected', event.dataTransfer.files);
        }
    },

    _uploadStarted() {
        invokeAction(this, 'uploadStarted');
    },

    _uploadProgress(event) {
        if (event.lengthComputable) {
            run(() => {
                let percentage = Math.round((event.loaded / event.total) * 100);
                this.set('uploadPercentage', percentage);
            });
        }
    },

    _uploadFinished() {
        invokeAction(this, 'uploadFinished');
    },

    _uploadSuccess(response) {
        this.set('url', response);
        this.send('saveUrl');
        this.send('reset');
        invokeAction(this, 'uploadSuccess', response);
    },

    _uploadFailed(error) {
        let message;

        if (isVersionMismatchError(error)) {
            this.get('notifications').showAPIError(error);
        }

        if (isUnsupportedMediaTypeError(error)) {
            let validExtensions = this.get('extensions').join(', .').toUpperCase();
            validExtensions = `.${validExtensions}`;

            message = `The image type you uploaded is not supported. Please use ${validExtensions}`;
        } else if (isRequestEntityTooLargeError(error)) {
            message = 'The image you uploaded was larger than the maximum file size your server allows.';
        } else if (error.errors && !isBlank(error.errors[0].message)) {
            message = error.errors[0].message;
        } else {
            message = 'Something went wrong :(';
        }

        this.set('failureMessage', message);
        invokeAction(this, 'uploadFailed', error);
    },

    generateRequest() {
        let ajax = this.get('ajax');
        let formData = this.get('formData');
        let uploadUrl = this.get('uploadUrl');
        // CASE: we want to upload an icon and we have to POST it to a different endpoint, expecially for icons
        let url = `${ghostPaths().apiRoot}${uploadUrl}`;

        this._uploadStarted();

        ajax.post(url, {
            data: formData,
            processData: false,
            contentType: false,
            dataType: 'text',
            xhr: () => {
                let xhr = new window.XMLHttpRequest();

                xhr.upload.addEventListener('progress', (event) => {
                    this._uploadProgress(event);
                }, false);

                return xhr;
            }
        }).then((response) => {
            let url = JSON.parse(response);
            this._uploadSuccess(url);
        }).catch((error) => {
            this._uploadFailed(error);
        }).finally(() => {
            this._uploadFinished();
        });
    },

    _validate(file) {
        if (this.get('validate')) {
            return invokeAction(this, 'validate', file);
        } else {
            return this._defaultValidator(file);
        }
    },

    _defaultValidator(file) {
        let extensions = this.get('extensions');
        let [, extension] = (/(?:\.([^.]+))?$/).exec(file.name);

        if (!isEmberArray(extensions)) {
            extensions = extensions.split(',');
        }

        if (!extension || extensions.indexOf(extension.toLowerCase()) === -1) {
            return new UnsupportedMediaTypeError();
        }

        return true;
    },

    actions: {
        fileSelected(fileList) {
            // can't use array destructuring here as FileList is not a strict
            // array and fails in Safari
            // eslint-disable-next-line ember-suave/prefer-destructuring
            let file = fileList[0];
            let validationResult = this._validate(file);

            this.set('file', file);
            invokeAction(this, 'fileSelected', file);

            if (validationResult === true) {
                run.schedule('actions', this, function () {
                    this.generateRequest();
                });
            } else {
                this._uploadFailed(validationResult);
            }
        },

        addUnsplashPhoto(photo) {
            this.set('url', photo.urls.regular);
            this.send('saveUrl');
        },

        reset() {
            this.set('file', null);
            this.set('uploadPercentage', 0);
        },

        saveUrl() {
            let url = this.get('url');
            invokeAction(this, 'update', url);
        }
    }
});
<commit_msg>🐛 Fix missing Unsplash icons in uploaders when using config override (#829)<commit_after>import Component from 'ember-component';
import computed from 'ember-computed';
import ghostPaths from 'ghost-admin/utils/ghost-paths';
import injectService from 'ember-service/inject';
import run from 'ember-runloop';
import {
    UnsupportedMediaTypeError,
    isRequestEntityTooLargeError,
    isUnsupportedMediaTypeError,
    isVersionMismatchError
} from 'ghost-admin/services/ajax';
import {assign} from '@ember/polyfills';
import {htmlSafe} from 'ember-string';
import {invokeAction} from 'ember-invoke-action';
import {isBlank} from 'ember-utils';
import {isEmberArray} from 'ember-array/utils';

export const IMAGE_MIME_TYPES = 'image/gif,image/jpg,image/jpeg,image/png,image/svg+xml';
export const IMAGE_EXTENSIONS = ['gif', 'jpg', 'jpeg', 'png', 'svg'];

export default Component.extend({
    ajax: injectService(),
    config: injectService(),
    notifications: injectService(),
    settings: injectService(),

    tagName: 'section',
    classNames: ['gh-image-uploader'],
    classNameBindings: ['dragClass'],

    image: null,
    text: '',
    altText: '',
    saveButton: true,
    accept: null,
    extensions: null,
    uploadUrl: null,
    validate: null,
    allowUnsplash: false,

    dragClass: null,
    failureMessage: null,
    file: null,
    url: null,
    uploadPercentage: 0,

    _defaultAccept: IMAGE_MIME_TYPES,
    _defaultExtensions: IMAGE_EXTENSIONS,
    _defaultUploadUrl: '/uploads/',
    _showUnsplash: false,

    // TODO: this wouldn't be necessary if the server could accept direct
    // file uploads
    formData: computed('file', function () {
        let file = this.get('file');
        let formData = new FormData();

        formData.append('uploadimage', file);

        return formData;
    }),

    description: computed('text', 'altText', function () {
        let altText = this.get('altText');

        return this.get('text') || (altText ? `Upload image of "${altText}"` : 'Upload an image');
    }),

    progressStyle: computed('uploadPercentage', function () {
        let percentage = this.get('uploadPercentage');
        let width = '';

        if (percentage > 0) {
            width = `${percentage}%`;
        } else {
            width = '0';
        }

        return htmlSafe(`width: ${width}`);
    }),

    // HACK: this settings/config dance is needed because the "override" only
    // happens when visiting the unsplash app settings route
    // TODO: move the override logic to the server, client knows too much
    // about which values should override others
    unsplash: computed('config.unsplashAPI', 'settings.unsplash', function () {
        let unsplashConfig = this.get('config.unsplashAPI');
        let unsplashSettings = this.get('settings.unsplash');
        let unsplash = assign({}, unsplashConfig, unsplashSettings);

        return unsplash;
    }),

    didReceiveAttrs() {
        let image = this.get('image');
        this.set('url', image);

        if (!this.get('accept')) {
            this.set('accept', this.get('_defaultAccept'));
        }
        if (!this.get('extensions')) {
            this.set('extensions', this.get('_defaultExtensions'));
        }
        if (!this.get('uploadUrl')) {
            this.set('uploadUrl', this.get('_defaultUploadUrl'));
        }
    },

    dragOver(event) {
        if (!event.dataTransfer) {
            return;
        }

        // this is needed to work around inconsistencies with dropping files
        // from Chrome's downloads bar
        let eA = event.dataTransfer.effectAllowed;
        event.dataTransfer.dropEffect = (eA === 'move' || eA === 'linkMove') ? 'move' : 'copy';

        event.stopPropagation();
        event.preventDefault();

        this.set('dragClass', '-drag-over');
    },

    dragLeave(event) {
        event.preventDefault();
        this.set('dragClass', null);
    },

    drop(event) {
        event.preventDefault();

        this.set('dragClass', null);

        if (event.dataTransfer.files) {
            this.send('fileSelected', event.dataTransfer.files);
        }
    },

    _uploadStarted() {
        invokeAction(this, 'uploadStarted');
    },

    _uploadProgress(event) {
        if (event.lengthComputable) {
            run(() => {
                let percentage = Math.round((event.loaded / event.total) * 100);
                this.set('uploadPercentage', percentage);
            });
        }
    },

    _uploadFinished() {
        invokeAction(this, 'uploadFinished');
    },

    _uploadSuccess(response) {
        this.set('url', response);
        this.send('saveUrl');
        this.send('reset');
        invokeAction(this, 'uploadSuccess', response);
    },

    _uploadFailed(error) {
        let message;

        if (isVersionMismatchError(error)) {
            this.get('notifications').showAPIError(error);
        }

        if (isUnsupportedMediaTypeError(error)) {
            let validExtensions = this.get('extensions').join(', .').toUpperCase();
            validExtensions = `.${validExtensions}`;

            message = `The image type you uploaded is not supported. Please use ${validExtensions}`;
        } else if (isRequestEntityTooLargeError(error)) {
            message = 'The image you uploaded was larger than the maximum file size your server allows.';
        } else if (error.errors && !isBlank(error.errors[0].message)) {
            message = error.errors[0].message;
        } else {
            message = 'Something went wrong :(';
        }

        this.set('failureMessage', message);
        invokeAction(this, 'uploadFailed', error);
    },

    generateRequest() {
        let ajax = this.get('ajax');
        let formData = this.get('formData');
        let uploadUrl = this.get('uploadUrl');
        // CASE: we want to upload an icon and we have to POST it to a different endpoint, expecially for icons
        let url = `${ghostPaths().apiRoot}${uploadUrl}`;

        this._uploadStarted();

        ajax.post(url, {
            data: formData,
            processData: false,
            contentType: false,
            dataType: 'text',
            xhr: () => {
                let xhr = new window.XMLHttpRequest();

                xhr.upload.addEventListener('progress', (event) => {
                    this._uploadProgress(event);
                }, false);

                return xhr;
            }
        }).then((response) => {
            let url = JSON.parse(response);
            this._uploadSuccess(url);
        }).catch((error) => {
            this._uploadFailed(error);
        }).finally(() => {
            this._uploadFinished();
        });
    },

    _validate(file) {
        if (this.get('validate')) {
            return invokeAction(this, 'validate', file);
        } else {
            return this._defaultValidator(file);
        }
    },

    _defaultValidator(file) {
        let extensions = this.get('extensions');
        let [, extension] = (/(?:\.([^.]+))?$/).exec(file.name);

        if (!isEmberArray(extensions)) {
            extensions = extensions.split(',');
        }

        if (!extension || extensions.indexOf(extension.toLowerCase()) === -1) {
            return new UnsupportedMediaTypeError();
        }

        return true;
    },

    actions: {
        fileSelected(fileList) {
            // can't use array destructuring here as FileList is not a strict
            // array and fails in Safari
            // eslint-disable-next-line ember-suave/prefer-destructuring
            let file = fileList[0];
            let validationResult = this._validate(file);

            this.set('file', file);
            invokeAction(this, 'fileSelected', file);

            if (validationResult === true) {
                run.schedule('actions', this, function () {
                    this.generateRequest();
                });
            } else {
                this._uploadFailed(validationResult);
            }
        },

        addUnsplashPhoto(photo) {
            this.set('url', photo.urls.regular);
            this.send('saveUrl');
        },

        reset() {
            this.set('file', null);
            this.set('uploadPercentage', 0);
        },

        saveUrl() {
            let url = this.get('url');
            invokeAction(this, 'update', url);
        }
    }
});
<|endoftext|>