<commit_before>(function () {
    'use strict';

    /**
     * @param Base
     * @param {JQuery} $element
     * @return {ChartPlate}
     */
    const controller = function (Base, $element) {

        const SELECTORS = {
            plate: '.chart-plate',
            marker: '.chart-plate__marker'
        };

        class ChartPlate extends Base {

            /**
             * @public
             * @type {object}
             */
            data;
            /**
             * @private
             */
            markerColor;

            $postLink() {
                this.plate = $element.find(SELECTORS.plate);
                this.marker = $element.find(SELECTORS.marker);
                this.receive(this.wChart.signals.mouseMove, this._onMove, this);
                this.receive(this.wChart.signals.mouseLeave, this._onLeave, this);
            }

            /**
             * @private
             */
            _onMove(data) {
                this._setMarkerAndPlatePosition(data);
            }

            /**
             * @private
             */
            _onLeave() {
                this.plate.removeClass('visible');
                this.marker.removeClass('visible');
            }

            /**
             * @param data @type {Object}
             * @param data.event @type {Object}
             * @param data.x @type {number}
             * @param data.y @type {number}
             * @private
             */
            _setMarkerAndPlatePosition({ event, point, id }) {
                const { x, y } = point;
                const PLATE_ARROW_WIDTH = 5;
                const markerX = x - (this.marker.outerWidth() / 2);
                const markerY = y - (this.marker.outerHeight() / 2);
                let plateX;
                if (event.offsetX < ($element.closest('w-chart').innerWidth() / 2)) {
                    plateX = x + (this.marker.outerWidth() / 2) + PLATE_ARROW_WIDTH;
                    this.plate.addClass('to-right');
                } else {
                    plateX = markerX - this.plate.outerWidth() - PLATE_ARROW_WIDTH;
                    this.plate.removeClass('to-right');
                }
                const plateY = y - (this.plate.outerHeight() / 2);
                this.plate.css('transform', `translate(${plateX}px,${plateY}px)`);
                this.marker.css('transform', `translate(${markerX}px,${markerY}px)`);
                this.plate.addClass('visible');
                this.marker.addClass('visible');

                const color = typeof this.markerColor === 'string' && this.markerColor || this.markerColor[id];
                if (color) {
                    this.marker.css('border-color', color);
                }
            }

        }

        return new ChartPlate();
    };

    controller.$inject = ['Base', '$element'];

    angular.module('app.ui').component('wChartPlate', {
        transclude: true,
        require: {
            wChart: '^wChart'
        },
        bindings: {
            markerColor: '<'
        },
        templateUrl: 'modules/ui/directives/chartPlate/chartPlate.html',
        controller
    });
})();
<commit_msg>DEXW-1931: fix marker color apply<commit_after>(function () {
    'use strict';

    /**
     * @param Base
     * @param {JQuery} $element
     * @return {ChartPlate}
     */
    const controller = function (Base, $element) {

        const SELECTORS = {
            plate: '.chart-plate',
            marker: '.chart-plate__marker'
        };

        class ChartPlate extends Base {

            /**
             * @public
             * @type {object}
             */
            data;
            /**
             * @private
             */
            markerColor;

            $postLink() {
                this.plate = $element.find(SELECTORS.plate);
                this.marker = $element.find(SELECTORS.marker);
                this.receive(this.wChart.signals.mouseMove, this._onMove, this);
                this.receive(this.wChart.signals.mouseLeave, this._onLeave, this);
            }

            /**
             * @private
             */
            _onMove(data) {
                this._setMarkerAndPlatePosition(data);
            }

            /**
             * @private
             */
            _onLeave() {
                this.plate.removeClass('visible');
                this.marker.removeClass('visible');
            }

            /**
             * @param data @type {Object}
             * @param data.event @type {Object}
             * @param data.x @type {number}
             * @param data.y @type {number}
             * @private
             */
            _setMarkerAndPlatePosition({ event, point, id }) {
                const { x, y } = point;
                const PLATE_ARROW_WIDTH = 5;
                const markerX = x - (this.marker.outerWidth() / 2);
                const markerY = y - (this.marker.outerHeight() / 2);
                let plateX;
                if (event.offsetX < ($element.closest('w-chart').innerWidth() / 2)) {
                    plateX = x + (this.marker.outerWidth() / 2) + PLATE_ARROW_WIDTH;
                    this.plate.addClass('to-right');
                } else {
                    plateX = markerX - this.plate.outerWidth() - PLATE_ARROW_WIDTH;
                    this.plate.removeClass('to-right');
                }
                const plateY = y - (this.plate.outerHeight() / 2);
                this.plate.css('transform', `translate(${plateX}px,${plateY}px)`);
                this.marker.css('transform', `translate(${markerX}px,${markerY}px)`);
                this.plate.addClass('visible');
                this.marker.addClass('visible');

                if (this.markerColor) {
                    const color = typeof this.markerColor === 'string' && this.markerColor || this.markerColor[id];
                    this.marker.css('border-color', color);
                }
            }

        }

        return new ChartPlate();
    };

    controller.$inject = ['Base', '$element'];

    angular.module('app.ui').component('wChartPlate', {
        transclude: true,
        require: {
            wChart: '^wChart'
        },
        bindings: {
            markerColor: '<'
        },
        templateUrl: 'modules/ui/directives/chartPlate/chartPlate.html',
        controller
    });
})();
<|endoftext|>


<commit_before>//Translated from heuristic.rb using babyruby2js
'use strict';

var main = require('../../main');
var Grid = require('../../Grid');
var Stone = require('../../Stone');

var sOK = main.sOK, ALWAYS = main.ALWAYS;
var EMPTY = main.EMPTY, BORDER = main.BORDER;
var XY_AROUND = Stone.XY_AROUND;
var DIR0 = main.DIR0, DIR3 = main.DIR3;

/** @class Base class for all heuristics.
 *  Anything useful for all of them should be stored as data member here.
 */
function Heuristic(player) {
    this.player = player;
    this.goban = player.goban;
    this.gsize = player.goban.gsize;
    this.inf = player.inf;
    this.pot = player.pot;
    this.boan = player.boan;
    this.scoreGrid = new Grid(this.gsize);
    this.minimumScore = player.minimumScore;

    this.spaceInvasionCoeff = this.getGene('spaceInvasion', 2.0, 0.01, 4.0);

    this.color = this.enemyColor = null;
}
module.exports = Heuristic;

Heuristic.prototype.initColor = function () {
    this.color = this.player.color;
    this.enemyColor = this.player.enemyColor;
};

// For heuristics which do not handle evalBoard (but _evalMove)
// NB: _evalMove is "private": only called from here (base class), and from inside a heuristic
Heuristic.prototype.evalBoard = function (stateYx, scoreYx) {
    var color = this.player.color;
    var myScoreYx = this.scoreGrid.yx;
    for (var j = 1; j <= this.gsize; j++) {
        for (var i = 1; i <= this.gsize; i++) {
            if (stateYx[j][i] < sOK) continue;
            var score = myScoreYx[j][i] = this._evalMove(i, j, color);
            scoreYx[j][i] += score;
        }
    }
};

Heuristic.prototype.getGene = function (name, defVal, lowLimit, highLimit) {
    return this.player.genes.get(this.constructor.name + '-' + name, defVal, lowLimit, highLimit);
};

Heuristic.prototype.territoryScore = function (i, j, color) {
    var ter = this.pot.territory.yx;
    return ter[j][i] * (color === main.BLACK ? 1 : -1);
};

Heuristic.prototype.enemyTerritoryScore = function (i, j, color) {
    var score = Grid.territory2owner[2 + this.pot.grids[1 - color].yx[j][i]];
    return score * (color === main.BLACK ? 1 : -1);
};

/** Pass saved as true if g is an ally group (we evaluate how much we save) */
Heuristic.prototype.groupThreat = function (g, saved) {
    var threat = 2 * g.stones.length; // 2 points are pretty much granted for the prisonners

    // TODO: instead of below, evaluate the damage caused by an *invasion* by taking group g
    var lives = g.allLives();
    var numEmpties = 0;
    for (var i = lives.length - 1; i >= 0; i--) {
        numEmpties += lives[i].numEmpties();
    }
    threat += this.spaceInvasionCoeff * Math.max(0, numEmpties - 1); //...and the "open gate" to territory will count a lot

    if (saved) return threat;
    return threat + this._countSavedAllies(g);
};

// Count indirectly saved groups
Heuristic.prototype._countSavedAllies = function (killedEnemyGroup) {
    // do not count any saved allies if we gave them a single life in corner
    if (killedEnemyGroup.stones.length === 1 &&
        this.distanceFromStoneToCorner(killedEnemyGroup.stones[0]) === 0) {
        return 0;
    }
    var saving = 0;
    var allies = killedEnemyGroup.allEnemies();
    for (var a = allies.length - 1; a >= 0; a--) {
        if (allies[a].lives > 1) continue;
        saving += this.groupThreat(allies[a], /*saved=*/true);
    }
    return saving;
};

Heuristic.prototype._invasionCost = function (i, j, dir, color, level) {
    if (level-- === 0) return 0;
    var s = this.goban.stoneAt(i, j);
    if (s === BORDER || s.color !== EMPTY) return 0;
    var cost = this.enemyTerritoryScore(i, j, color);
    if (cost <= 0) return 0;

    var dx = XY_AROUND[dir][0], dy = XY_AROUND[dir][1];
    var spread = XY_AROUND[(dir + 3) % 4];
    var vx = spread[0], vy = spread[1];

    cost += this._invasionCost(i + dx + vx, j + dy + vy, dir, color, level);
    cost += this._invasionCost(i + dx - vx, j + dy - vy, dir, color, level);
    return cost;
};

var INVASION_DEEPNESS = 0; // TODO: better algo for this

Heuristic.prototype.invasionCost = function (i, j, color) {
    var cost = Math.max(0, this.enemyTerritoryScore(i, j, color));
    for (var dir = DIR0; dir <= DIR3; dir++) {
        cost += this._invasionCost(i + XY_AROUND[dir][0], j + XY_AROUND[dir][1], dir, color, INVASION_DEEPNESS);
    }
    return cost;
};

Heuristic.prototype.markMoveAsBlunder = function (i, j, reason) {
    this.player.markMoveAsBlunder(i, j, this.constructor.name + ':' + reason);
};

Heuristic.prototype.distanceFromStoneToBorder = function (stone) {
    var gsize = this.gsize;
    var i = stone.i, j = stone.j;
    return Math.min(Math.min(i - 1, gsize - i), Math.min(j - 1, gsize - j));
};

Heuristic.prototype.distanceFromStoneToCorner = function (stone) {
    var gsize = this.gsize;
    var i = stone.i, j = stone.j;
    return Math.min(i - 1, gsize - i) + Math.min(j - 1, gsize - j);
};

Heuristic.prototype.diagonalStones = function (s1, s2) {
    return [this.goban.stoneAt(s1.i, s2.j), this.goban.stoneAt(s2.i, s1.j)];
};

Heuristic.prototype.distanceBetweenStones = function (s1, s2, color) {
    var dx = Math.abs(s2.i - s1.i), dy = Math.abs(s2.j - s1.j);
    if (dx + dy === 1) return 0; // already connected
    var enemy = 1 - color;
    var numEnemies = 0, between;
    if (dx === 1 && dy === 1) { // hane
        var diags = this.diagonalStones(s1, s2), c1 = diags[0], c2 = diags[1];
        if (c1.color === color || c2.color === color) return 0; // already connected
        if (c1.color === enemy) numEnemies++;
        if (c2.color === enemy) numEnemies++;
        if (numEnemies === 0) return 0; // safe hane
        if (numEnemies === 2) return 99; // cut!
        var connPoint = c1.color === enemy ? c2 : c1;
        if (this.distanceFromStoneToBorder(s1) === 0 || this.distanceFromStoneToBorder(s2) === 0) {
            if (this.distanceFromStoneToBorder(connPoint) === 1) return 1; // enemy cut-stone on border
            if (connPoint.allyStones(enemy) !== 0) return 1; // other enemy next to conn point
            return 0;
        } else if (this.distanceFromStoneToBorder(connPoint) === 1) {
            if (connPoint.allyStones(enemy) !== 0) return 1;
            return 0;
        }
        return 1;
    }
    if (dx + dy === 2) {
        between = this.goban.stoneAt((s1.i + s2.i) / 2, (s1.j + s2.j) /2);
        if (between.color === color) return 0; // already connected
        if (between.color === enemy) return between.group.lives; // REVIEW ME
        for (var i = between.neighbors.length - 1; i >= 0; i--) {
            if (between.neighbors[i].color === enemy) numEnemies++;
        }
        if (numEnemies >= 1) return 1; // needs 1 move to connect (1 or 2 enemies is same)
        if (this.distanceFromStoneToBorder(s1) + this.distanceFromStoneToBorder(s2) === 0) {
            return 0; // along border with 0 enemy around is safe
        }
        return 0.5; // REVIEW ME
    }
    var d1 = this.distanceFromStoneToBorder(s1), d2 = this.distanceFromStoneToBorder(s2);
    if (dx + dy === 3 && d1 === 0 && d2 === 0) {
        // TODO code betweenStones and test it
        var betweens = this.betweenStones(s1, s2);
        var dist = 0;
        for (var b = betweens.length - 1; b >= 0; b--) {
            between = betweens[b];
            if (between.color === enemy) dist += between.group.lives;
            if (between.allyStones(enemy) !== 0) dist += 1;
        }
        return dist;
    }
    //TODO: add other cases like monkey-jump
    return dx + dy;
};

/** Evaluates if a new stone at i,j will be able to connect with a "color" group around.
 *  Basically this is to make sure i,j is not alone (and not to see if i,j is a connector!) */
// +@+
// O+O
// @*@ <-- TODO review this case; looks like white here cannot connect
Heuristic.prototype.canConnect = function (i, j, color) {
    var stone = this.goban.stoneAt(i,j);

    // first look around for empties and allies (a single ally means we connect!)
    var empties = [];
    for (var nNdx = stone.neighbors.length - 1; nNdx >= 0; nNdx--) {
        var n = stone.neighbors[nNdx];
        if (n.color === color && n.group.isDead < ALWAYS) return n;
        if (n.color === main.EMPTY) empties.push(n);
    }
    // look around each empty for allies
    var moveNeeded = 2;
    for(var eNdx = empties.length - 1; eNdx >= 0; eNdx--) {
        var empty = empties[eNdx];
        for (var n2Ndx = empty.neighbors.length - 1; n2Ndx >= 0; n2Ndx--) {
            var en = empty.neighbors[n2Ndx];
            if (en === stone) continue; // same stone
            if (en.color !== color) continue; // empty or enemy
            if (en.group.isDead === ALWAYS) continue; // TODO: look better at group's health
            var dist = this.distanceBetweenStones(stone, en, color);
            if (dist >= 2) continue;
            moveNeeded -= (2 - dist);
            if (moveNeeded <= 0.5) return en; // REVIEW ME
        }
    }
    return null;
};

// Cannot start from corner!
Heuristic.prototype.canConnectAlongBorder = function (i, j, color) {
    // decide direction
    var gsize = this.gsize;
    var dx = 0, dy = 0;
    if (i === 1 || i === gsize) dy = 1;
    else if (j === 1 || j === gsize) dx = 1;
    else return null;
    // check 1 stone to see if we should reverse direction
    var s = this.goban.stoneAt(i + dx, j + dy);
    if (s === BORDER) return null;
    if (s.color !== EMPTY) { dx = -dx; dy = -dy; }

    for(;;) {
        i += dx; j += dy;
        s = this.goban.stoneAt(i, j);
        if (s === BORDER) return null;
        if (s.color === color && s.group.lives > 2) return s.group;
    }
};
<commit_msg>new Heuristic#isOwned<commit_after>//Translated from heuristic.rb using babyruby2js
'use strict';

var main = require('../../main');
var Grid = require('../../Grid');
var Stone = require('../../Stone');

var BLACK = main.BLACK, WHITE = main.WHITE, EMPTY = main.EMPTY, BORDER = main.BORDER;
var sOK = main.sOK, ALWAYS = main.ALWAYS;
var XY_AROUND = Stone.XY_AROUND;
var DIR0 = main.DIR0, DIR3 = main.DIR3;

/** @class Base class for all heuristics.
 *  Anything useful for all of them should be stored as data member here.
 */
function Heuristic(player) {
    this.player = player;
    this.goban = player.goban;
    this.gsize = player.goban.gsize;
    this.inf = player.inf;
    this.pot = player.pot;
    this.boan = player.boan;
    this.scoreGrid = new Grid(this.gsize);
    this.minimumScore = player.minimumScore;

    this.spaceInvasionCoeff = this.getGene('spaceInvasion', 2.0, 0.01, 4.0);

    this.color = this.enemyColor = null;
}
module.exports = Heuristic;

Heuristic.prototype.initColor = function () {
    this.color = this.player.color;
    this.enemyColor = this.player.enemyColor;
};

// For heuristics which do not handle evalBoard (but _evalMove)
// NB: _evalMove is "private": only called from here (base class), and from inside a heuristic
Heuristic.prototype.evalBoard = function (stateYx, scoreYx) {
    var color = this.player.color;
    var myScoreYx = this.scoreGrid.yx;
    for (var j = 1; j <= this.gsize; j++) {
        for (var i = 1; i <= this.gsize; i++) {
            if (stateYx[j][i] < sOK) continue;
            var score = myScoreYx[j][i] = this._evalMove(i, j, color);
            scoreYx[j][i] += score;
        }
    }
};

Heuristic.prototype.getGene = function (name, defVal, lowLimit, highLimit) {
    return this.player.genes.get(this.constructor.name + '-' + name, defVal, lowLimit, highLimit);
};

Heuristic.prototype.territoryScore = function (i, j, color) {
    return this.pot.territory.yx[j][i] * (color === main.BLACK ? 1 : -1);
};

/** Returns NEVER, SOMETIMES, ALWAYS */
Heuristic.prototype.isOwned = function (i, j, color) {
    var myColor = color === main.BLACK ? -1 : +1;
    var score = 0;
    if (Grid.territory2owner[2 + this.pot.grids[BLACK].yx[j][i]] === myColor) score++;
    if (Grid.territory2owner[2 + this.pot.grids[WHITE].yx[j][i]] === myColor) score++;
    return score;
};

//TODO review this - why 1-color and not both grids?
Heuristic.prototype.enemyTerritoryScore = function (i, j, color) {
    var score = Grid.territory2owner[2 + this.pot.grids[1 - color].yx[j][i]];
    return score * (color === main.BLACK ? 1 : -1);
};

/** Pass saved as true if g is an ally group (we evaluate how much we save) */
Heuristic.prototype.groupThreat = function (g, saved) {
    var threat = 2 * g.stones.length; // 2 points are pretty much granted for the prisonners

    // TODO: instead of below, evaluate the damage caused by an *invasion* by taking group g
    var lives = g.allLives();
    var numEmpties = 0;
    for (var i = lives.length - 1; i >= 0; i--) {
        numEmpties += lives[i].numEmpties();
    }
    threat += this.spaceInvasionCoeff * Math.max(0, numEmpties - 1); //...and the "open gate" to territory will count a lot

    if (saved) return threat;
    return threat + this._countSavedAllies(g);
};

// Count indirectly saved groups
Heuristic.prototype._countSavedAllies = function (killedEnemyGroup) {
    // do not count any saved allies if we gave them a single life in corner
    if (killedEnemyGroup.stones.length === 1 &&
        this.distanceFromStoneToCorner(killedEnemyGroup.stones[0]) === 0) {
        return 0;
    }
    var saving = 0;
    var allies = killedEnemyGroup.allEnemies();
    for (var a = allies.length - 1; a >= 0; a--) {
        if (allies[a].lives > 1) continue;
        saving += this.groupThreat(allies[a], /*saved=*/true);
    }
    return saving;
};

Heuristic.prototype._invasionCost = function (i, j, dir, color, level) {
    if (level-- === 0) return 0;
    var s = this.goban.stoneAt(i, j);
    if (s === BORDER || s.color !== EMPTY) return 0;
    var cost = this.enemyTerritoryScore(i, j, color);
    if (cost <= 0) return 0;

    var dx = XY_AROUND[dir][0], dy = XY_AROUND[dir][1];
    var spread = XY_AROUND[(dir + 3) % 4];
    var vx = spread[0], vy = spread[1];

    cost += this._invasionCost(i + dx + vx, j + dy + vy, dir, color, level);
    cost += this._invasionCost(i + dx - vx, j + dy - vy, dir, color, level);
    return cost;
};

var INVASION_DEEPNESS = 0; // TODO: better algo for this

Heuristic.prototype.invasionCost = function (i, j, color) {
    var cost = Math.max(0, this.enemyTerritoryScore(i, j, color));
    for (var dir = DIR0; dir <= DIR3; dir++) {
        cost += this._invasionCost(i + XY_AROUND[dir][0], j + XY_AROUND[dir][1], dir, color, INVASION_DEEPNESS);
    }
    return cost;
};

Heuristic.prototype.markMoveAsBlunder = function (i, j, reason) {
    this.player.markMoveAsBlunder(i, j, this.constructor.name + ':' + reason);
};

Heuristic.prototype.distanceFromStoneToBorder = function (stone) {
    var gsize = this.gsize;
    var i = stone.i, j = stone.j;
    return Math.min(Math.min(i - 1, gsize - i), Math.min(j - 1, gsize - j));
};

Heuristic.prototype.distanceFromStoneToCorner = function (stone) {
    var gsize = this.gsize;
    var i = stone.i, j = stone.j;
    return Math.min(i - 1, gsize - i) + Math.min(j - 1, gsize - j);
};

Heuristic.prototype.diagonalStones = function (s1, s2) {
    return [this.goban.stoneAt(s1.i, s2.j), this.goban.stoneAt(s2.i, s1.j)];
};

Heuristic.prototype.distanceBetweenStones = function (s1, s2, color) {
    var dx = Math.abs(s2.i - s1.i), dy = Math.abs(s2.j - s1.j);
    if (dx + dy === 1) return 0; // already connected
    var enemy = 1 - color;
    var numEnemies = 0, between;
    if (dx === 1 && dy === 1) { // hane
        var diags = this.diagonalStones(s1, s2), c1 = diags[0], c2 = diags[1];
        if (c1.color === color || c2.color === color) return 0; // already connected
        if (c1.color === enemy) numEnemies++;
        if (c2.color === enemy) numEnemies++;
        if (numEnemies === 0) return 0; // safe hane
        if (numEnemies === 2) return 99; // cut!
        var connPoint = c1.color === enemy ? c2 : c1;
        if (this.distanceFromStoneToBorder(s1) === 0 || this.distanceFromStoneToBorder(s2) === 0) {
            if (this.distanceFromStoneToBorder(connPoint) === 1) return 1; // enemy cut-stone on border
            if (connPoint.allyStones(enemy) !== 0) return 1; // other enemy next to conn point
            return 0;
        } else if (this.distanceFromStoneToBorder(connPoint) === 1) {
            if (connPoint.allyStones(enemy) !== 0) return 1;
            return 0;
        }
        return 1;
    }
    if (dx + dy === 2) {
        between = this.goban.stoneAt((s1.i + s2.i) / 2, (s1.j + s2.j) /2);
        if (between.color === color) return 0; // already connected
        if (between.color === enemy) return between.group.lives; // REVIEW ME
        for (var i = between.neighbors.length - 1; i >= 0; i--) {
            if (between.neighbors[i].color === enemy) numEnemies++;
        }
        if (numEnemies >= 1) return 1; // needs 1 move to connect (1 or 2 enemies is same)
        if (this.distanceFromStoneToBorder(s1) + this.distanceFromStoneToBorder(s2) === 0) {
            return 0; // along border with 0 enemy around is safe
        }
        return 0.5; // REVIEW ME
    }
    var d1 = this.distanceFromStoneToBorder(s1), d2 = this.distanceFromStoneToBorder(s2);
    if (dx + dy === 3 && d1 === 0 && d2 === 0) {
        // TODO code betweenStones and test it
        var betweens = this.betweenStones(s1, s2);
        var dist = 0;
        for (var b = betweens.length - 1; b >= 0; b--) {
            between = betweens[b];
            if (between.color === enemy) dist += between.group.lives;
            if (between.allyStones(enemy) !== 0) dist += 1;
        }
        return dist;
    }
    //TODO: add other cases like monkey-jump
    return dx + dy;
};

/** Evaluates if a new stone at i,j will be able to connect with a "color" group around.
 *  Basically this is to make sure i,j is not alone (and not to see if i,j is a connector!) */
// +@+
// O+O
// @*@ <-- TODO review this case; looks like white here cannot connect
Heuristic.prototype.canConnect = function (i, j, color) {
    var stone = this.goban.stoneAt(i,j);

    // first look around for empties and allies (a single ally means we connect!)
    var empties = [];
    for (var nNdx = stone.neighbors.length - 1; nNdx >= 0; nNdx--) {
        var n = stone.neighbors[nNdx];
        if (n.color === color && n.group.isDead < ALWAYS) return n;
        if (n.color === main.EMPTY) empties.push(n);
    }
    // look around each empty for allies
    var moveNeeded = 2;
    for(var eNdx = empties.length - 1; eNdx >= 0; eNdx--) {
        var empty = empties[eNdx];
        for (var n2Ndx = empty.neighbors.length - 1; n2Ndx >= 0; n2Ndx--) {
            var en = empty.neighbors[n2Ndx];
            if (en === stone) continue; // same stone
            if (en.color !== color) continue; // empty or enemy
            if (en.group.isDead === ALWAYS) continue; // TODO: look better at group's health
            var dist = this.distanceBetweenStones(stone, en, color);
            if (dist >= 2) continue;
            moveNeeded -= (2 - dist);
            if (moveNeeded <= 0.5) return en; // REVIEW ME
        }
    }
    return null;
};

// Cannot start from corner!
Heuristic.prototype.canConnectAlongBorder = function (i, j, color) {
    // decide direction
    var gsize = this.gsize;
    var dx = 0, dy = 0;
    if (i === 1 || i === gsize) dy = 1;
    else if (j === 1 || j === gsize) dx = 1;
    else return null;
    // check 1 stone to see if we should reverse direction
    var s = this.goban.stoneAt(i + dx, j + dy);
    if (s === BORDER) return null;
    if (s.color !== EMPTY) { dx = -dx; dy = -dy; }

    for(;;) {
        i += dx; j += dy;
        s = this.goban.stoneAt(i, j);
        if (s === BORDER) return null;
        if (s.color === color && s.group.lives > 2) return s.group;
    }
};
<|endoftext|>


<commit_before>(function () {
    'use strict';

    /**
     * @param Base
     * @param {stateManager} stateManager
     * @param {ModalManager} modalManager
     * @param {app.utils} utils
     * @param $scope
     * @param {User} user
     * @param {$state} $state
     * @param {JQuery} $document
     * @param {JQuery} $element
     * @param {UserNameService} userNameService
     * @return {MainHeaderCtrl}
     */
    const controller = function (Base,
                                 stateManager,
                                 modalManager,
                                 user,
                                 $state,
                                 $element,
                                 $document,
                                 utils,
                                 $scope,
                                 userNameService) {

        const PATH = 'modules/ui/directives/mainHeader/templates';
        class MainHeaderCtrl extends Base {

            /**
             * @public
             * @type {string}
             */
            userName;
            /**
             * @public
             * @type {Array}
             */
            userList = [];
            /**
             * @public
             * @type {boolean}
             */
            isUniqueUserName = true;
            /**
             * @type {boolean}
             */
            showInput = false;

            constructor() {
                super($scope);

                $scope.ERROR_DISPLAY_INTERVAL = 3;
                $scope.user = user;

                $scope.MAX_USER_NAME_LENGTH = userNameService.MAX_USER_NAME_LENGTH;
                this.userName = userNameService.name;

                this.hovered = false;
                this.address = user.address || '3PHBX4uXhCyaANUxccLHNXw3sqyksV7YnDz';
                this.isLogined = !!user.address;
                this.userType = user.userType;
                this.isDesktop = WavesApp.isDesktop();

                this.isScript = user.hasScript();
                this.isKeeper = user.userType === 'wavesKeeper';
                this.isLedger = user.userType === 'ledger';

                this.hasTypeHelp = this.isScript && (this.isLedger || this.isKeeper);

                user.getFilteredUserList().then(list => {
                    this.userList = list;
                    utils.postDigest($scope).then(() => {
                        this._initFader();
                        this._initClickHandlers();
                        $scope.$apply();
                    });
                });

                this.largeTemplate = `${PATH}/largeHeader.html`;
                this.mobileTemplate = `${PATH}/mobileHeader.html`;

                this.observe('userName', () => {
                    userNameService.setName(this.userName);
                    this.isUniqueUserName = userNameService.isUniqueName();
                });

                this.receive(utils.observe(userNameService, 'name'), function () {
                    this.userName = userNameService.name;
                }, this);
            }

            $postLink() {
                this._initClickHandlers();
            }

            /**
             * @public
             */
            hideTooltip() {
                $element.find('.account-name-wrapper w-info-tooltip').hide();
            }

            /**
             * @public
             */
            onFocus() {
                this.hideTooltip();
            }

            /**
             * @public
             */
            showTooltip() {
                $element.find('.account-name-wrapper w-info-tooltip').show();
            }

            /**
             * @public
             */
            onBlur() {
                this.showTooltip();
                this._saveUserName();
                this.toggleNameView();
            }

            $onDestroy() {
                super.$onDestroy();
                $element.find('.mobile-menu-fader, .mobile-menu-toggler').off();
            }

            /**
             * @public
             */
            logout() {
                user.logout();
            }

            /**
             * @public
             */
            avatarClick() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showAccountInfo();
                } else {
                    this._getDialogModal('account', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * @public
             */
            changeNameClick() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showAccountChangeName();
                } else {
                    this._getDialogModal('account', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * @public
             */
            showAddressClick() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showAccountAddress();
                } else {
                    this._getDialogModal('account', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * @public
             */
            settings() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showSettings();
                } else {
                    this._getDialogModal('settings', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * public
             */
            removeInnerMenu() {
                $document.find('w-main-header header').removeClass('show-wallet show-aliases show-downloads');
            }

            /**
             * public
             */
            removeBodyClass() {
                $document.find('body').removeClass('menu-is-shown');
            }

            /**
             *
             */
            toggleNameView() {
                this.showInput = !this.showInput;
                utils.postDigest($scope).then(() => {
                    if (this.showInput) {
                        this.setUserName.userName.$$element.focus();
                    }
                });
            }

            /**
             * @param type
             * @param success
             * @param error
             * @return {Promise}
             * @private
             */
            _getDialogModal(type, success, error) {
                return modalManager.showDialogModal({
                    iconClass: `${type.replace(/\./g, '-')}-account-info`,
                    message: { literal: `modal.${type}.message` },
                    buttons: [
                        {
                            success: false,
                            classes: 'big',
                            text: { literal: `modal.${type}.cancel` },
                            click: error
                        },
                        {
                            success: true,
                            classes: 'big submit',
                            text: { literal: `modal.${type}.ok` },
                            click: success
                        }
                    ]
                });
            }

            /**
             * @private
             */
            _initClickHandlers() {
                $element.find('.mobile-menu-toggler').on('click', () => {
                    $element.find('.main-header__header').toggleClass('expanded');
                    $document.find('body').toggleClass('menu-is-shown');
                });
                $element.find('.mobile-menu-fader').on('click', () => {
                    $element.find('.main-header__header').removeClass('expanded');
                    $document.find('body').removeClass('menu-is-shown');
                });
            }

            /**
             * @private
             */
            _initFader() {
                $element.find('.dropdown-toggler').on('mouseover', () => {
                    $element.find('.main-header__fader').addClass('show-fader');
                });
                $element.find('.dropdown-toggler').on('mouseleave', () => {
                    $element.find('.main-header__fader').removeClass('show-fader');
                });
            }

            /**
             * @private
             */
            _saveUserName() {
                userNameService.save();
            }

        }

        return new MainHeaderCtrl();
    };

    controller.$inject = [
        'Base',
        'stateManager',
        'modalManager',
        'user',
        '$state',
        '$element',
        '$document',
        'utils',
        '$scope',
        'userNameService'
    ];

    angular.module('app.ui').component('wMainHeader', {
        bindings: {
            userList: '<'
        },
        templateUrl: 'modules/ui/directives/mainHeader/templates/mainHeader.html',
        transclude: false,
        controller
    });
})();
<commit_msg>DEXW-1790: fix init events<commit_after>(function () {
    'use strict';

    /**
     * @param Base
     * @param {stateManager} stateManager
     * @param {ModalManager} modalManager
     * @param {app.utils} utils
     * @param $scope
     * @param {User} user
     * @param {$state} $state
     * @param {JQuery} $document
     * @param {JQuery} $element
     * @param {UserNameService} userNameService
     * @return {MainHeaderCtrl}
     */
    const controller = function (Base,
                                 stateManager,
                                 modalManager,
                                 user,
                                 $state,
                                 $element,
                                 $document,
                                 utils,
                                 $scope,
                                 userNameService) {

        const PATH = 'modules/ui/directives/mainHeader/templates';
        class MainHeaderCtrl extends Base {

            /**
             * @public
             * @type {string}
             */
            userName;
            /**
             * @public
             * @type {Array}
             */
            userList = [];
            /**
             * @public
             * @type {boolean}
             */
            isUniqueUserName = true;
            /**
             * @type {boolean}
             */
            showInput = false;

            constructor() {
                super($scope);

                $scope.ERROR_DISPLAY_INTERVAL = 3;
                $scope.user = user;

                $scope.MAX_USER_NAME_LENGTH = userNameService.MAX_USER_NAME_LENGTH;
                this.userName = userNameService.name;

                this.hovered = false;
                this.address = user.address || '3PHBX4uXhCyaANUxccLHNXw3sqyksV7YnDz';
                this.isLogined = !!user.address;
                this.userType = user.userType;
                this.isDesktop = WavesApp.isDesktop();

                this.isScript = user.hasScript();
                this.isKeeper = user.userType === 'wavesKeeper';
                this.isLedger = user.userType === 'ledger';

                this.hasTypeHelp = this.isScript && (this.isLedger || this.isKeeper);

                user.getFilteredUserList().then(list => {
                    this.userList = list;
                });

                $scope.$on('$includeContentLoaded', () => {
                    this._initFader();
                    this._initClickHandlers();
                });

                this.largeTemplate = `${PATH}/largeHeader.html`;
                this.mobileTemplate = `${PATH}/mobileHeader.html`;

                this.observe('userName', () => {
                    userNameService.setName(this.userName);
                    this.isUniqueUserName = userNameService.isUniqueName();
                });

                this.receive(utils.observe(userNameService, 'name'), function () {
                    this.userName = userNameService.name;
                }, this);
            }

            /**
             * @public
             */
            hideTooltip() {
                $element.find('.account-name-wrapper w-info-tooltip').hide();
            }

            /**
             * @public
             */
            onFocus() {
                this.hideTooltip();
            }

            /**
             * @public
             */
            showTooltip() {
                $element.find('.account-name-wrapper w-info-tooltip').show();
            }

            /**
             * @public
             */
            onBlur() {
                this.showTooltip();
                this._saveUserName();
                this.toggleNameView();
            }

            $onDestroy() {
                super.$onDestroy();
                $element.find('.mobile-menu-fader, .mobile-menu-toggler').off();
            }

            /**
             * @public
             */
            logout() {
                user.logout();
            }

            /**
             * @public
             */
            avatarClick() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showAccountInfo();
                } else {
                    this._getDialogModal('account', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * @public
             */
            changeNameClick() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showAccountChangeName();
                } else {
                    this._getDialogModal('account', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * @public
             */
            showAddressClick() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showAccountAddress();
                } else {
                    this._getDialogModal('account', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * @public
             */
            settings() {
                $document.find('body').removeClass('menu-is-shown');
                if (this.isLogined) {
                    modalManager.showSettings();
                } else {
                    this._getDialogModal('settings', () => $state.go('welcome'), () => $state.go('create'));
                }
            }

            /**
             * public
             */
            removeInnerMenu() {
                $document.find('w-main-header header').removeClass('show-wallet show-aliases show-downloads');
            }

            /**
             * public
             */
            removeBodyClass() {
                $document.find('body').removeClass('menu-is-shown');
            }

            /**
             *
             */
            toggleNameView() {
                this.showInput = !this.showInput;
                utils.postDigest($scope).then(() => {
                    if (this.showInput) {
                        this.setUserName.userName.$$element.focus();
                    }
                });
            }

            /**
             * @param type
             * @param success
             * @param error
             * @return {Promise}
             * @private
             */
            _getDialogModal(type, success, error) {
                return modalManager.showDialogModal({
                    iconClass: `${type.replace(/\./g, '-')}-account-info`,
                    message: { literal: `modal.${type}.message` },
                    buttons: [
                        {
                            success: false,
                            classes: 'big',
                            text: { literal: `modal.${type}.cancel` },
                            click: error
                        },
                        {
                            success: true,
                            classes: 'big submit',
                            text: { literal: `modal.${type}.ok` },
                            click: success
                        }
                    ]
                });
            }

            /**
             * @private
             */
            _initClickHandlers() {
                $element.find('.mobile-menu-toggler').on('click', () => {
                    $element.find('.main-header__header').toggleClass('expanded');
                    $document.find('body').toggleClass('menu-is-shown');
                });
                $element.find('.mobile-menu-fader').on('click', () => {
                    $element.find('.main-header__header').removeClass('expanded');
                    $document.find('body').removeClass('menu-is-shown');
                });
            }

            /**
             * @private
             */
            _initFader() {
                $element.find('.dropdown-toggler').on('mouseover', () => {
                    $element.find('.main-header__fader').addClass('show-fader');
                });
                $element.find('.dropdown-toggler').on('mouseleave', () => {
                    $element.find('.main-header__fader').removeClass('show-fader');
                });
            }

            /**
             * @private
             */
            _saveUserName() {
                userNameService.save();
            }

        }

        return new MainHeaderCtrl();
    };

    controller.$inject = [
        'Base',
        'stateManager',
        'modalManager',
        'user',
        '$state',
        '$element',
        '$document',
        'utils',
        '$scope',
        'userNameService'
    ];

    angular.module('app.ui').component('wMainHeader', {
        bindings: {
            userList: '<'
        },
        templateUrl: 'modules/ui/directives/mainHeader/templates/mainHeader.html',
        transclude: false,
        controller
    });
})();
<|endoftext|>


<commit_before>define(['jquery'], function ($) {
  var Utility = {
    DOM:{
      serializeObject:function (el) {
        var o = {};
        var a = $(el).serializeArray();
        $.each(a, function () {
          if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
              o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
          } else {
            o[this.name] = this.value || '';
          }
        });
        return o;
      }
    }
  };

  return Utility;
});<commit_msg>Adding table and form template helpers to utility<commit_after>define(['jquery', 'underscore'], function ($, _) {

  var Utility = {
    DOM:{},
    Templates:{}
  };

  Utility.DOM.serializeObject = function (el) {
    var o = {};
    var a = $(el).serializeArray();
    $.each(a, function () {
      if (o[this.name] !== undefined) {
        if (!o[this.name].push) {
          o[this.name] = [o[this.name]];
        }
        o[this.name].push(this.value || '');
      } else {
        o[this.name] = this.value || '';
      }
    });
    return o;
  };

  Utility.Templates.TABLE_STRUCTURE = '
' +
      '
' +
      '<% _.each(columns, function(c){ %>' +
      '<th class="<%= c.value %>"><%= c.name %>	' +
      '<% }); %>' +
      '
' +
      '
' +
      '

';

  Utility.Templates.FORM_STRUCTURE = '<form action="<%= action %>" method="<%= method %>"><fieldset>' +
      '<% _.each(fields, function(field){ %>' +
      '<% if(field.type == "hidden"){ %>' +
      '<input class="<%= field.inputClass %>" id="<%= field.idPrefix %>-<%= recordId %>-<%= field.name %>" value="<%= field.value %>" name="<%= field.name %>" size="<%= field.size %>" type="<%= field.type %>" /> ' +
      '<% } else { %>' +
      '<div class="clearfix input-outer-container <%= field.outerClass %>">' +
      '<label for="<%= field.idPrefix %>-<%= recordId %>-<%= field.name%>"><%= field.humanName %>' +
      '<div class="input <%= field.inputOuterClass %>">' +

      '<% if(field.type == "text") { %>' +
      '<input class="<%= field.inputClass %>" id="<%= field.idPrefix %>-<%= recordId %>-<%= field.name %>" value="<%= field.value %>" name="<%= field.name %>" size="<%= field.size %>" type="<%= field.type %>"/> ' +
      '<% } else if (field.type == "textarea") { %>' +
      '<textarea class="<%= field.inputClass %>" id="<%= field.idPrefix %>-<%= recordId %>-<%= field.name %>" rows="<%= field.rows %>" name="<%= field.name %>"><%= field.value %></textarea>' +
      '<% } %>' +

      '' +

      '
' +
      '
' +
      '<% } %>' + // End the if type=='hidden'
      '<% }); %>'  +

      '
' +
      '<% _.each(buttons, function(button){ %>' +
      '<% if(button.type == "link"){ %>' +
      '<a class="btn <%= button.class %>" href="<%= button.href %>"><%= button.humanName %> ' +
      '<% } else { %>' +
      '<button class="btn <%= button.class %>" type="<%= button.type %>"><%= button.humanName %></button> ' +
      '<% }}); %>' +
      '
' +
      '</fieldset></form>';

  /**
   * Renders an underscore.js template with the provided structure data.
   * The default template is the Utility.Templates.TABLE_STRUCTURE.
   *
   * structureData example:
   * { columns: [{name: 'ID', value: 'id'},{name: 'Name', value: 'name'}] }
   *
   * @param structureData
   * @param template
   */
  Utility.Templates.renderTableStructure = function (structureData, template) {

    if (!template){
      template = Utility.Templates.TABLE_STRUCTURE;
    }

    return _.template(template, structureData);

  };

  /**
   * Renders a standard form layout given the form structure provided.
   *
   * Here is an example of a valid form structure:
   * var formStructure = {
       action: '#/prescriptions/new',
       method: 'POST',
       recordId: this.model.get('id'),
       fields: [
         {
           idPrefix: 'field-type',
           name: 'id',
           humanName: 'Id',
           outerClass: '',
           inputOuterClass: '',
           value: this.model.get('id'),
           type: 'hidden'
         },
         {
           name: 'name',
           humanName: 'Name',
           value: this.model.get('name'),
           type: 'text'
         }
       ],
       buttons: [
         {'class': 'primary', type: 'submit', humanName: 'Submit'},
         {type: 'reset', humanName: 'Reset'}
       ]
     };
   *
   * @param formStructure
   * @param template
   */
  Utility.Templates.renderForm = function(formStructure, template){

    if (!template){
      template = Utility.Templates.FORM_STRUCTURE;
    }

    // Prep the defaults for the form structure
    _.defaults(formStructure, {
      action: '',
      method: 'POST',
      recordId: new Date().getTime(),
      fields: [],
      buttons: []
    });

    _.each(formStructure.fields, function(field){
      _.defaults(field, {
        idPrefix: 'field-' + new Date().getTime(),
        outerClass: '',
        name: '',
        humanName: '',
        inputOuterClass: '',
        value: '',
        inputClass: '',
        type: 'text'
      });

      if (field.type == 'text' && !field.size){
        field.size = 30;
      } else if (field.type == 'textarea' && !field.rows){
        field.rows = 4;
      }
    });

    _.each(formStructure.buttons, function(button){
      _.defaults(button, {
        'class': '',
        type: 'button',
        humanName: 'Button'
      });
    });

    return _.template(template, formStructure);

  };

  return Utility;
});<|endoftext|>


<commit_before>;(function (root) {
    'use strict';
    var modMap = [];
    var exportsMap = [];
    var toString = {}.toString;
    var slice = [].slice;
    var baseSrc = document.currentScript.src;
    var docSrc = location.href.slice(0, location.href.indexOf('?'));
    var docUrl = docSrc.slice(0, docSrc.lastIndexOf('/') + 1);
    var baseUrl = baseSrc && baseSrc.slice(0, baseSrc.lastIndexOf('/') + 1) || docUrl;
    var gid = 0;
    var o = {
        baseUrl: baseUrl
    };
    console.log('baseUrl:' +baseUrl);
    function getGid() {
        return gid++;
    }
    function isArr(arr) {
        return toString.call(arr) === '[object Array]';
    }
    function isObj(obj) {
        return toString.call(obj) === '[object Object]';
    }
    function isFn(fn) {
        return toString.call(fn) === '[object Function]';
    }
    function extendDeep() {
        var target = arguments[0] || {};
        var arrs = slice.call(arguments, 1);
        var len = arrs.length;
        var copyIsArr;
        var clone;

        for (var i = 0; i < len; i++) {
            var arr = arrs[i];
            for (var name in arr) {
                var src = target[name];
                var copy = arr[name];

                //避免无限循环
                if (target === copy) {
                    continue;
                }

                if (copy && (isObj(copy) || (copyIsArr = isArr(copy)))) {
                    if (copyIsArr) {
                        copyIsArr = false;
                        clone = src && isArr(src) ? src : [];

                    } else {
                        clone = src && isObj(src) ? src : {};
                    }
                    target[ name ] = extendDeep(clone, copy);
                } else if (typeof copy !== 'undefined'){
                    target[name] = copy;
                }
            }

        }

        return target;
    }
    function loadjs(src, success, error) {
        var js = document.createElement('script');
        js.src = src;
        js.id = 'lodjs-' + getGid();
        js.onload = success;
        js.onerror = error;
        (document.getElementsByTagName('head')[0] || document.body).appendChild(js);
    }
    function loadcss(src, success, error) {
        var css = document.createElement('link');
        css.rel = "stylesheet";
        css.href = src;
        css.onload = success;
        css.onerror = error;
        (document.getElementsByTagName('head')[0] || document.body).appendChild(css);
    }
    function getUrl(path, url) {
        //绝对网址
        if (path.search(/^(http:\/\/|https:\/\/|\/\/)/) !== -1) {
            return path;
        }
        // /开头
        if (path.search(/^\//) !== -1) {
            return (url.match(/[^\/]*\/\/[^\/]*\//)[0] || url + '/') + path;
        }

        // ../开头
        if (path.search(/^\.\.\//) !== -1) {
            url = url.slice(0, url.lastIndexOf('/') + 1);
            while(path.search(/^\.\.\//) !== -1) {
                if (url.lastIndexOf('/') !== -1) {
                    path = path.slice(3);
                    url = url.slice(0, url.lastIndexOf('/', url.length - 2) + 1);
                } else {
                    throw new Error('loadjs geturl error, cannot find path in url');
                }
            }

            return url + path;
        }
        // ./
        if (path.search(/^\.\//) !== -1) {
            path = path.slice(2);
        }

        return url.slice(0, url.lastIndexOf('/') + 1) + path;
    }
    function getDepUrl(id, url) {
        url = getUrl(id, url || o.baseUrl);
        console.log('getdepurl: ' + url + '.js');
        return url.search(/\.js$/) !== -1 ? url : url + '.js';
    }
    function getIdUrl(id){
        //没有id的情况
        if (!id) {
            return document.currentScript.src;
        }
        //id不能为相对路径
        if (id.search(/^\./) !== -1 || id.search(/\.js$/) !== -1) {
            throw new Error('loadjs define id' + id + 'must absolute and no .js');
        }

        var url = getUrl(id, o.baseUrl);
        console.log(id + ' idurl:' + url + '.js');
        return url + '.js';
    }
    var define = function (name, deps, callback) {
        //省略模块名
        if (typeof name !== 'string') {
            callback = deps;
            deps = name;
            name = null;
        }

        //无依赖
        if (!isArr(deps)) {
            callback = deps;
            deps = [];
        }

        var modName = getIdUrl(name);

        modMap[modName] = modMap[modName] || {};
        modMap[modName].deps = deps;
        modMap[modName].callback = callback;
        modMap[modName].status = 'loaded';

        return 0;
    };
    define.amd = {};
    function loadMod(id, callback, option) {
        var modName = getDepUrl(id, option.baseUrl);
        //未加载
        if (!modMap[modName]) {
            modMap[modName] = {
                status: 'loading',
                onload: [callback]
            };
            loadjs(modName, function () {
                //如果define的不是函数
                if (!isFn(modMap[modName].callback)) {
                    exportsMap[modName] = modMap[modName].callback;
                    callback(exportsMap[modName]);
                    //模块定义完毕 执行load函数
                    for (var i = 0; i < modMap[modName].onload.length; i++) {
                        modMap[modName].onload[i](exportsMap[modName]);
                    }
                    return 0;
                }

                //define的是函数
                use(modMap[modName].deps, function () {
                    exportsMap[modName] = modMap[modName].callback.apply(null, arguments);
                    //模块定义完毕 执行load函数
                    for (var i = 0; i < modMap[modName].onload.length; i++) {
                        modMap[modName].onload[i](exportsMap[modName]);
                    }
                }, {baseUrl: modName});
                return 1;
            }, function () {
                modMap[modName].status === 'error';
            });
            return 0;
        }

        //加载失败
        if (modMap[modName].status === 'error') {
            callback();
            return 1;
        }
        //正在加载
        if (modMap[modName].status === 'loading') {
            modMap[modName].onload.push(callback);
            return 1;
        }

        //加载完成
        //尚未执行完成
        if (!exportsMap[modName]) {
            //如果define的不是函数
            if (!isFn(modMap[modName].callback)) {
                exportsMap[modName] = modMap[modName].callback;
                callback(exportsMap[modName]);
                return 2;
            }

            //define的是函数
            use(modMap[modName].deps, function () {
                exportsMap[modName] = modMap[modName].callback.apply(null, arguments);
                callback(exportsMap[modName]);
            }, {baseUrl: modName});
            return 3;
        }

        //已经执行过
        callback(exportsMap[modName]);
        return 4;
    }
    function use(deps, callback, option) {
        if (!deps || !callback) {
            throw new Error('lodjs.use arguments error');
            return 0;
        }

        if (typeof deps === 'string') {
            deps = [deps];
        }

        if (!isArr(deps) || !isFn(callback)) {
            throw new Error('lodjs.use arguments error');
            return 1;
        }
        if (!isObj(option)) {
            option = {
                baseUrl: o.baseUrl
            };
        }
        if (deps.length === 0) {
            callback();
            return 2;
        }
        var depsCount = deps.length;
        var params = [];
        for(var i = 0; i < deps.length; i++) {
            (function (j) {
                loadMod(deps[j], function (param) {
                    depsCount--;
                    params[j] = param;
                    if (depsCount === 0) {
                        callback.apply(null, params);
                    }
                }, option);
            }(i));
        }

        return 3;
    }
    var lodjs = {
        version: '0.1.0',
        use: use,
        loadjs: loadjs,
        loadcss: loadcss
    };
    lodjs.config = function (option) {
        if (option.baseUrl) {
            option.baseUrl = getUrl(option.baseUrl, docUrl);
        }
        o = extendDeep(o, option);
        console.log(o);
        return extendDeep(o);
    };
    root.define = define;
    root.lodjs = lodjs;
}(window));<commit_msg>fix bug 1.fix 载入失败时无法触发载入事件<commit_after>;(function (root) {
    'use strict';
    var modMap = [];
    var exportsMap = [];
    var toString = {}.toString;
    var slice = [].slice;
    var baseSrc = document.currentScript.src;
    var docSrc = location.href.slice(0, location.href.indexOf('?'));
    var docUrl = docSrc.slice(0, docSrc.lastIndexOf('/') + 1);
    var baseUrl = baseSrc && baseSrc.slice(0, baseSrc.lastIndexOf('/') + 1) || docUrl;
    var gid = 0;
    var o = {
        baseUrl: baseUrl
    };
    console.log('baseUrl:' +baseUrl);
    function getGid() {
        return gid++;
    }
    function isArr(arr) {
        return toString.call(arr) === '[object Array]';
    }
    function isObj(obj) {
        return toString.call(obj) === '[object Object]';
    }
    function isFn(fn) {
        return toString.call(fn) === '[object Function]';
    }
    function extendDeep() {
        var target = arguments[0] || {};
        var arrs = slice.call(arguments, 1);
        var len = arrs.length;
        var copyIsArr;
        var clone;

        for (var i = 0; i < len; i++) {
            var arr = arrs[i];
            for (var name in arr) {
                var src = target[name];
                var copy = arr[name];

                //避免无限循环
                if (target === copy) {
                    continue;
                }

                if (copy && (isObj(copy) || (copyIsArr = isArr(copy)))) {
                    if (copyIsArr) {
                        copyIsArr = false;
                        clone = src && isArr(src) ? src : [];

                    } else {
                        clone = src && isObj(src) ? src : {};
                    }
                    target[ name ] = extendDeep(clone, copy);
                } else if (typeof copy !== 'undefined'){
                    target[name] = copy;
                }
            }

        }

        return target;
    }
    function loadjs(src, success, error) {
        var js = document.createElement('script');
        js.src = src;
        js.id = 'lodjs-' + getGid();
        js.onload = success;
        js.onerror = error;
        (document.getElementsByTagName('head')[0] || document.body).appendChild(js);
    }
    function loadcss(src, success, error) {
        var css = document.createElement('link');
        css.rel = "stylesheet";
        css.href = src;
        css.onload = success;
        css.onerror = error;
        (document.getElementsByTagName('head')[0] || document.body).appendChild(css);
    }
    function getUrl(path, url) {
        //绝对网址
        if (path.search(/^(http:\/\/|https:\/\/|\/\/)/) !== -1) {
            return path;
        }
        // /开头
        if (path.search(/^\//) !== -1) {
            return (url.match(/[^\/]*\/\/[^\/]*\//)[0] || url + '/') + path;
        }

        // ../开头
        if (path.search(/^\.\.\//) !== -1) {
            url = url.slice(0, url.lastIndexOf('/') + 1);
            while(path.search(/^\.\.\//) !== -1) {
                if (url.lastIndexOf('/') !== -1) {
                    path = path.slice(3);
                    url = url.slice(0, url.lastIndexOf('/', url.length - 2) + 1);
                } else {
                    throw new Error('loadjs geturl error, cannot find path in url');
                }
            }

            return url + path;
        }
        // ./
        if (path.search(/^\.\//) !== -1) {
            path = path.slice(2);
        }

        return url.slice(0, url.lastIndexOf('/') + 1) + path;
    }
    function getDepUrl(id, url) {
        url = getUrl(id, url || o.baseUrl);
        console.log('getdepurl: ' + url + '.js');
        return url.search(/\.js$/) !== -1 ? url : url + '.js';
    }
    function getIdUrl(id){
        //没有id的情况
        if (!id) {
            return document.currentScript.src;
        }
        //id不能为相对路径
        if (id.search(/^\./) !== -1 || id.search(/\.js$/) !== -1) {
            throw new Error('loadjs define id' + id + 'must absolute and no .js');
        }

        var url = getUrl(id, o.baseUrl);
        console.log(id + ' idurl:' + url + '.js');
        return url + '.js';
    }
    var define = function (name, deps, callback) {
        //省略模块名
        if (typeof name !== 'string') {
            callback = deps;
            deps = name;
            name = null;
        }

        //无依赖
        if (!isArr(deps)) {
            callback = deps;
            deps = [];
        }

        var modName = getIdUrl(name);

        modMap[modName] = modMap[modName] || {};
        modMap[modName].deps = deps;
        modMap[modName].callback = callback;
        modMap[modName].status = 'loaded';

        return 0;
    };
    define.amd = {};
    function loadMod(id, callback, option) {
        var modName = getDepUrl(id, option.baseUrl);
        //未加载
        if (!modMap[modName]) {
            modMap[modName] = {
                status: 'loading',
                onload: [callback]
            };
            loadjs(modName, function () {
                //如果define的不是函数
                if (!isFn(modMap[modName].callback)) {
                    exportsMap[modName] = modMap[modName].callback;
                    callback(exportsMap[modName]);
                    //模块定义完毕 执行load函数
                    for (var i = 0; i < modMap[modName].onload.length; i++) {
                        modMap[modName].onload[i](exportsMap[modName]);
                    }
                    return 0;
                }

                //define的是函数
                use(modMap[modName].deps, function () {
                    exportsMap[modName] = modMap[modName].callback.apply(null, arguments);
                    //模块定义完毕 执行load函数
                    for (var i = 0; i < modMap[modName].onload.length; i++) {
                        modMap[modName].onload[i](exportsMap[modName]);
                    }
                }, {baseUrl: modName});
                return 1;
            }, function () {
                modMap[modName].status === 'error';
                callback();
            });
            return 0;
        }

        //加载失败
        if (modMap[modName].status === 'error') {
            callback();
            return 1;
        }
        //正在加载
        if (modMap[modName].status === 'loading') {
            modMap[modName].onload.push(callback);
            return 1;
        }

        //加载完成
        //尚未执行完成
        if (!exportsMap[modName]) {
            //如果define的不是函数
            if (!isFn(modMap[modName].callback)) {
                exportsMap[modName] = modMap[modName].callback;
                callback(exportsMap[modName]);
                return 2;
            }

            //define的是函数
            use(modMap[modName].deps, function () {
                exportsMap[modName] = modMap[modName].callback.apply(null, arguments);
                callback(exportsMap[modName]);
            }, {baseUrl: modName});
            return 3;
        }

        //已经执行过
        callback(exportsMap[modName]);
        return 4;
    }
    function use(deps, callback, option) {
        if (!deps || !callback) {
            throw new Error('lodjs.use arguments error');
            return 0;
        }

        if (typeof deps === 'string') {
            deps = [deps];
        }

        if (!isArr(deps) || !isFn(callback)) {
            throw new Error('lodjs.use arguments error');
            return 1;
        }
        if (!isObj(option)) {
            option = {
                baseUrl: o.baseUrl
            };
        }
        if (deps.length === 0) {
            callback();
            return 2;
        }
        var depsCount = deps.length;
        var params = [];
        for(var i = 0; i < deps.length; i++) {
            (function (j) {
                loadMod(deps[j], function (param) {
                    depsCount--;
                    params[j] = param;
                    if (depsCount === 0) {
                        callback.apply(null, params);
                    }
                }, option);
            }(i));
        }

        return 3;
    }
    var lodjs = {
        version: '0.1.0',
        use: use,
        loadjs: loadjs,
        loadcss: loadcss
    };
    lodjs.config = function (option) {
        if (option.baseUrl) {
            option.baseUrl = getUrl(option.baseUrl, docUrl);
        }
        o = extendDeep(o, option);
        console.log(o);
        return extendDeep(o);
    };
    root.define = define;
    root.lodjs = lodjs;
}(window));<|endoftext|>


<commit_before>var sys = require('sys')
var exec = require('child_process').exec;
var execSync = require('execSync').run;
var fs = require('fs');

//first update json data
var convertData = execSync("node parser/parser.js");
console.log("converting data to json:\n",convertData);
//move files
console.log("moving generated files to data folder");
fs.renameSync("rooms.json"          , "data/rooms.json");
fs.renameSync("roomsByBuilding.json", "data/roomsByBuilding.json");
fs.renameSync("buildings.json"      , "data/buildings.json");

//vulcanize custom element, just in case
var vulcanize = execSync("vulcanize --inline index.html");
console.log("vulcanizing:\n",vulcanize);

//do some git magic
var addGit = execSync("git add data locales vulcanized.html accessibility-infos.html accessibility-infos.css index.html");
var commitGit = execSync("git commit -m '- autoUpdated data/repository on "+new Date() +"'");
var publishGitMaster = execSync("git push origin master");
var publishGitPages  = execSync("git push -f origin master:gh-pages");
var publishOk = addGit && commitGit && publishGitMaster && publishGitPages;
console.log("Publishing to github:\n",publishOk);

/*var gitCheckoutGhPages = execSync("git checkout gh-pages");
console.log("Checking out gh-pages branch:\n",gitCheckoutGhPages);

var gitRebaseFromMaster = execSync("git rebase master");
console.log("Rebase from master:\n",gitRebaseFromMaster);

var gitPushToGhPages = execSync("git push origin gh-pages");
console.log("Pushing pages:\n",gitPushToGhPages);

var gitCheckoutMaster = execSync("git checkout master");
console.log("Returning to master branch:\n",gitCheckoutMaster);*/
<commit_msg>-removed some clutter from publish.js<commit_after>var sys = require('sys')
var exec = require('child_process').exec;
var execSync = require('execSync').run;
var fs = require('fs');

//first update json data
var convertData = execSync("node parser/parser.js");
console.log("converting data to json:\n",convertData);
//move files
console.log("moving generated files to data folder");
fs.renameSync("rooms.json"          , "data/rooms.json");
fs.renameSync("roomsByBuilding.json", "data/roomsByBuilding.json");
fs.renameSync("buildings.json"      , "data/buildings.json");

//vulcanize custom element, just in case
var vulcanize = execSync("vulcanize --inline index.html");
console.log("vulcanizing:\n",vulcanize);

//do some git magic
var addGit = execSync("git add data locales vulcanized.html accessibility-infos.html accessibility-infos.css index.html");
var commitGit = execSync("git commit -m '- autoUpdated data/repository on "+new Date() +"'");
var publishGitMaster = execSync("git push origin master");
var publishGitPages  = execSync("git push -f origin master:gh-pages");
var publishOk = addGit && commitGit && publishGitMaster && publishGitPages;
console.log("Publishing to github:\n",publishOk);

<|endoftext|>


<commit_before>(function(exports){
    function assemble_dbpedia_url(query){
       return "http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&query=" +
                   escape(query) + "&format=json";
    }
    exports.assemble_dbpedia_url = assemble_dbpedia_url;

    exports.assembles_area_query = function(positionSW, positionNE, options){
        // assembles a SPARQL query for resources in the specified area.
        // options:
        // - not_here: list(areas): areas to exclude in the query, format [obj, obj]:
        //             obj must have the following format:
        //                {SW:{lat:NN.NN, lng:NN.NN,
        //                 NE:{lat:NN.NN, lng: NN.NN}}
        // - language: string, default: 'en'
        // - include_cities: bool, default: false
        //      NB: by default populated places (dbpedia-owl:PopulatedPlace) are excluded from the query
        // - type_url: SPARQL-URL-string (e.g. <http://queries for: 'rdf:type')
        options = options || {};
        var lang = options.language || 'en';
        var type_query_head = options.type_url ? "" : " (GROUP_CONCAT(?type; separator=',') as ?types) ";
        var q = "SELECT DISTINCT (str(?label) as ?label) ?lng ?lat ?link ?thumbnail " + type_query_head + " WHERE {"
        q += "       ?res <http://www.w3.org/2003/01/geo/wgs84_pos#long> ?lng."
        q += "       ?res <http://www.w3.org/2003/01/geo/wgs84_pos#lat> ?lat."
        q += "       ?res rdfs:label ?label ."
        q += "       ?res foaf:isPrimaryTopicOf ?link."
        q += "       ?res <http://dbpedia.org/ontology/thumbnail> ?thumbnail."
        if (options.type_url){
            q += "      ?res rdf:type " + type_url
        } else {
            q += "      ?res rdf:type  ?type_url ."
            q += "      ?type_url rdfs:label ?type ."
        }
        if (!options.include_cities && !options.type_url){
            q += "      MINUS {?res a <http://dbpedia.org/ontology/PopulatedPlace>}."
        }
        q += "      FILTER ((?lng > " + positionSW.lng + "  AND ?lng < " + positionNE.lng
        q += "      AND ?lat > " + positionSW.lat + " AND ?lat < " + positionNE.lat + ") AND "
        if (options.not_here){
            for (var idx = 0 ; idx < options.not_here.length ; idx++) {
                var area = options.not_here[idx];
                q += "      !(?lng > " + area.SW.lng + "  AND ?lng < " + area.NE.lng
                q += "      AND ?lat > " + area.SW.lat + " AND ?lat < " + area.NE.lat + ") AND "
            }
        }
        q += "      LANG(?label)='" + lang + "'"
        if (!options.type_url){
            q += "      AND LANG(?type)='" + lang + "')"
        }
        q += "  } Limit 100"
        return q
    }

    function assemble_class_based_query(item_url, limit){
      var q = "SELECT ?page ?label ?wiki_page WHERE { \n";
      q += "    ?page a <" + item_url + ">  .\n";
      q += "    ?page foaf:isPrimaryTopicOf ?wiki_page .\n";
      q += "    ?page rdfs:label ?label .\n";
      q += "    FILTER(lang(?label) = 'en')\n";
      q += "} LIMIT 100";
      return q
    }

    function assemble_free_text_search_query(klass){
      var free_text = $('#proto_free_text_input').val().trim().split(" ");
      var what = $('#proto_free_search_field_select').val()
      var q = "SELECT distinct(?page) ?label ?wiki_page " + (what == 'description' ? "?desc" : "") + " WHERE {\n"
      var q_count = "SELECT count(distinct(?page)) as ?count WHERE {\n"
      var conditions = _assemble_conditions(free_text, what, Sem.current_top_level && Sem.current_top_level.url)
      q_count += conditions;
      q += conditions;
      q += "} ORDER BY ?page";
      q_count += "}";
      var url = Sem.assemble_dbpedia_url(q);
      var count_url = Sem.assemble_dbpedia_url(q_count);
      send_query(url, true);
      display_query_in_monitor(q, url);
      send_query(count_url);
      //console.log(q)
    }

    function assemble_2_classes_based_query(classA, classB){

    }

    function _assemble_conditions(free_text, what, klass){
      var join1 = free_text.join("' AND '");
      var join2 = free_text.join("");
      var q = "    ?page rdfs:label ?label .\n";
      q += "    ?page foaf:isPrimaryTopicOf ?wiki_page .\n";
      if (klass){
          q += "    ?page a <" + klass + ">  .";
      }
      if (what == 'description'){
          q += "    ?page dbpedia-owl:abstract ?desc .";
          q += "    ?desc bif:contains \"'(" + join1 + ")' or '" + join2 + "'\"\n";
          q += "    FILTER(lang(?label) = 'en' AND lang(?desc) = 'en' AND\n";  // take only english labels
      } else {
          q += "    ?label bif:contains \"'(" + join1 + ")' or '" + join2 + "'\"\n";
          q += "    FILTER(lang(?label) = 'en' AND\n";  // take only english labels
      }
      q += "    NOT EXISTS {?page dbpedia-owl:wikiPageRedirects ?real_page})\n"; // filter out alternative spellings.
      return q
    }

    function send_query(url, callback, options){
        // options:
        // - track_loading -> function, e.g. onUpdateProgress
        options = options || {};
        set_progress_value(2, "request sent...");
        var ajaxSetup = {
          dataType: "json",
          url: url,
          success: callback,
        }
        if (options.track_loading){
          // ajaxSetup.progress = onUpdateProgress
          ajaxSetup.progress = options.track_loading
        }

        var lastAjax = $.ajax(ajaxSetup);
        if (options.track_loading){ // i.e. if the call is for content, not for count
          exports.currentAjax = lastAjax;
        }
    }
    exports.send_query = send_query;

    function onUpdateProgress(e) {
      if (e.lengthComputable) {
        var percent_complete = (e.loaded/e.total) * 100;
      } else {
        var percent_complete = 0;
      }
      //console.log(percent_complete)
      set_progress_value(percent_complete);
    }

    function set_progress_value(val, str){
        var cont = $('#loading_progress');
        var ele = cont.find('div');
        if (str) {
          $('#loading_message').show()
        } else {
          $('#loading_message').hide()
        }
        var new_width = String(val) + '%';
        ele.css('width', new_width);
        cont.show();
    }

    function stop_loading_animation(){
      $('#loading_progress').hide()
    }
    queries.stop_loading_animation = stop_loading_animation;

    function display_query_in_monitor(q, url){
      $('#query_monitor_container').show();
      $('#query_monitor').html("
" + q + "

run query");
    }

})(typeof exports === 'undefined' ? this['queries'] = {} : exports)
<commit_msg>refactor queries for better var names<commit_after>(function(exports){
    function assemble_dbpedia_url(query){
       return "http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&query=" +
                   escape(query) + "&format=json";
    }
    exports.assemble_dbpedia_url = assemble_dbpedia_url;

    exports.assembles_area_query = function(positionSW, positionNE, options){
        // assembles a SPARQL query for resources in the specified area.
        // options:
        // - not_here: list(areas): areas to exclude in the query, format [obj, obj]:
        //             obj must have the following format:
        //                {SW:{lat:NN.NN, lng:NN.NN,
        //                 NE:{lat:NN.NN, lng: NN.NN}}
        // - language: string, default: 'en'
        // - include_cities: bool, default: false
        //      NB: by default populated places (dbpedia-owl:PopulatedPlace) are excluded from the query
        // - type_url: SPARQL-URL-string (e.g. <http://queries for: 'rdf:type')
        options = options || {};
        var lang = options.language || 'en';
        var type_query_head = options.type_url ? "" : " (GROUP_CONCAT(?type; separator=',') as ?types) ";
        var q = "SELECT DISTINCT (str(?label) as ?label) ?lng ?lat ?link ?thumbnail " + type_query_head + " WHERE {"
        q += "       ?res <http://www.w3.org/2003/01/geo/wgs84_pos#long> ?lng."
        q += "       ?res <http://www.w3.org/2003/01/geo/wgs84_pos#lat> ?lat."
        q += "       ?res rdfs:label ?label ."
        q += "       ?res foaf:isPrimaryTopicOf ?link."
        q += "       ?res <http://dbpedia.org/ontology/thumbnail> ?thumbnail."
        if (options.type_url){
            q += "      ?res rdf:type " + type_url
        } else {
            q += "      ?res rdf:type  ?type_url ."
            q += "      ?type_url rdfs:label ?type ."
        }
        if (!options.include_cities && !options.type_url){
            q += "      MINUS {?res a <http://dbpedia.org/ontology/PopulatedPlace>}."
        }
        q += "      FILTER ((?lng > " + positionSW.lng + "  AND ?lng < " + positionNE.lng
        q += "      AND ?lat > " + positionSW.lat + " AND ?lat < " + positionNE.lat + ") AND "
        if (options.not_here){
            for (var idx = 0 ; idx < options.not_here.length ; idx++) {
                var area = options.not_here[idx];
                q += "      !(?lng > " + area.SW.lng + "  AND ?lng < " + area.NE.lng
                q += "      AND ?lat > " + area.SW.lat + " AND ?lat < " + area.NE.lat + ") AND "
            }
        }
        q += "      LANG(?label)='" + lang + "'"
        if (!options.type_url){
            q += "      AND LANG(?type)='" + lang + "')"
        }
        q += "  } Limit 100"
        return q
    }

    function assemble_class_based_query(item_url, limit){
      var q = "SELECT ?page ?label ?wiki_page WHERE { \n";
      q += "    ?page a <" + item_url + ">  .\n";
      q += "    ?page foaf:isPrimaryTopicOf ?wiki_page .\n";
      q += "    ?page rdfs:label ?label .\n";
      q += "    FILTER(lang(?label) = 'en')\n";
      q += "} " + (limit ? "LIMIT " + limit : "");
      return q
    }

    function assemble_free_text_search_query(free_text, field){
      var q = "SELECT distinct(?page) ?label ?wiki_page " + (field == 'description' ? "?desc" : "") + " WHERE {\n"
      var q_count = "SELECT count(distinct(?page)) as ?count WHERE {\n"
      var conditions = _assemble_conditions(free_text, field, Sem.current_top_level && Sem.current_top_level.url)
      q_count += conditions;
      q += conditions;
      q += "} ORDER BY ?page";
      q_count += "}";
      var url = assemble_dbpedia_url(q);
      var count_url = assemble_dbpedia_url(q_count);
      send_query(url, true);
      display_query_in_monitor(q, url);
      send_query(count_url);
      //console.log(q)
    }

    function assemble_2_classes_based_query(classA, classB){

    }

    function _assemble_conditions(free_text, field, type){
      var join1 = free_text.join("' AND '");
      var join2 = free_text.join("");
      var q = "    ?page rdfs:label ?label .\n";
      q += "    ?page foaf:isPrimaryTopicOf ?wiki_page .\n";
      if (type){
          q += "    ?page a <" + type + ">  .";
      }
      if (field == 'description'){
          q += "    ?page dbpedia-owl:abstract ?desc .";
          q += "    ?desc bif:contains \"'(" + join1 + ")' or '" + join2 + "'\"\n";
          q += "    FILTER(lang(?label)='en' AND lang(?desc)='en' AND\n";  // take only english labels
      } else {
          q += "    ?label bif:contains \"'(" + join1 + ")' or '" + join2 + "'\"\n";
          q += "    FILTER(lang(?label)='en' AND\n";  // take only english labels
      }
      q += "    NOT EXISTS {?page dbpedia-owl:wikiPageRedirects ?real_page})\n"; // filter out alternative spellings.
      return q
    }

    function send_query(url, callback, options){
        // options:
        // - track_loading -> function, e.g. onUpdateProgress
        options = options || {};
        set_progress_value(2, "request sent...");
        var ajaxSetup = {
          dataType: "json",
          url: url,
          success: callback,
        }
        if (options.track_loading){
          // ajaxSetup.progress = onUpdateProgress
          ajaxSetup.progress = options.track_loading
        }

        var lastAjax = $.ajax(ajaxSetup);
        if (options.track_loading){ // i.e. if the call is for content, not for count
          exports.currentAjax = lastAjax;
        }
    }
    exports.send_query = send_query;

    function onUpdateProgress(e) {
      if (e.lengthComputable) {
        var percent_complete = (e.loaded/e.total) * 100;
      } else {
        var percent_complete = 0;
      }
      //console.log(percent_complete)
      set_progress_value(percent_complete);
    }

    function set_progress_value(val, str){
        var cont = $('#loading_progress');
        var ele = cont.find('div');
        if (str) {
          $('#loading_message').show()
        } else {
          $('#loading_message').hide()
        }
        var new_width = String(val) + '%';
        ele.css('width', new_width);
        cont.show();
    }

    function stop_loading_animation(){
      $('#loading_progress').hide()
    }
    queries.stop_loading_animation = stop_loading_animation;

    function display_query_in_monitor(q, url){
      $('#query_monitor_container').show();
      $('#query_monitor').html("
" + q + "

run query");
    }

})(typeof exports === 'undefined' ? this['queries'] = {} : exports)
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

import {AbstractBackend, addBackend} from "./AbstractBackend";

export var GoogleDrive = Object.create(AbstractBackend);

// Configure these settings in GoogleDrive.config.js
GoogleDrive.clientId = "Your OAuth client Id";
GoogleDrive.apiKey = "Your developer API key";

GoogleDrive.init = function (container, _) {
    AbstractBackend.init.call(this, container, "sozi-editor-backend-GoogleDrive-input", _("Load from Google Drive"));

    $(window).blur(this.doAutosave.bind(this));

    gapi.client.setApiKey(this.apiKey);
    this.authorize(true);
    return this;
};

GoogleDrive.openFileChooser = function () {
    $("#sozi-editor-backend-GoogleDrive-input").click();
};

GoogleDrive.authorize = function (onInit) {
    gapi.auth.authorize({
        client_id: this.clientId,
        scope: "https://www.googleapis.com/auth/drive",
        immediate: onInit
    }, this.onAuthResult.bind(this, onInit));
};

GoogleDrive.onAuthResult = function (onInit, authResult) {
    var inputButton = $("#sozi-editor-backend-GoogleDrive-input");

    if (authResult && !authResult.error) {
        this.accessToken = authResult.access_token;
        // Access granted: create a file picker and show the "Load" button.
        gapi.client.load("drive", "v2");
        gapi.load("picker", {
            callback: () => {
                this.createPicker();
                inputButton.off("click").click(() => this.picker.setVisible(true));
                if (!onInit) {
                    inputButton.click();
                }
            }
        });
    }
    else {
        // No access token could be retrieved, show the button to start the authorization flow.
        inputButton.click(() => this.authorize(false));
    }
};

GoogleDrive.createPicker = function () {
    var view = new google.picker.View(google.picker.ViewId.DOCS);
    view.setMimeTypes("image/svg+xml");

    this.picker = new google.picker.PickerBuilder().
        addView(view).
        setOAuthToken(this.accessToken).
        setDeveloperKey(this.apiKey).
        setCallback(data => {
            if (data[google.picker.Response.ACTION] === google.picker.Action.PICKED) {
                gapi.client.drive.files.get({fileId: data.docs[0].id}).execute(response => {
                    if (!response.error) {
                        this.load(response);
                    }
                    else {
                        console.log(response.error.message);
                    }
                });
            }
        }).
        build();
};

GoogleDrive.getName = function (fileDescriptor) {
    return fileDescriptor.title;
};

GoogleDrive.getLocation = function (fileDescriptor) {
    return fileDescriptor.parents;
};

GoogleDrive.find = function (name, location, callback) {
    function findInParent(index) {
        gapi.client.drive.files.list({
            q: "title = '" + name + "' and " +
               "'" + location[index].id + "' in parents"
        }).execute(response => {
            if (response.items && response.items.length) {
                callback(response.items[0]);
            }
            else if (index < location.length - 1) {
                findInParent(index + 1);
            }
            else {
                callback(null);
            }
        });
    }
    findInParent(0);
};

// TODO implement the "change" event
GoogleDrive.load = function (fileDescriptor) {
    // The file is loaded using an AJAX GET operation.
    // The data type is forced to "text" to prevent parsing it.
    // Emit the "load" event with the file content in case of success,
    // or with the error status in case of failure.
    $.ajax(fileDescriptor.downloadUrl, {
        contentType: fileDescriptor.mimeType,
        dataType: "text",
        headers: {
            "Authorization": "Bearer " + this.accessToken
        },
        context: this
    }).done(data => this.emit("load", fileDescriptor, data))
      .fail((xhr, status) => this.emit("load", fileDescriptor, null, status));
};

GoogleDrive.create = function (name, location, mimeType, data, callback) {
    var boundary = "-------314159265358979323846";
    var delimiter = "\r\n--" + boundary + "\r\n";
    var closeDelimiter = "\r\n--" + boundary + "--";

    var metadata = {
        title: name,
        parents: location,
        mimeType
    };

    var multipartRequestBody =
        delimiter +
        "Content-Type: application/json\r\n\r\n" + JSON.stringify(metadata) +
        delimiter +
        "Content-Type: " + mimeType + "\r\n" +
        "Content-Transfer-Encoding: base64\r\n\r\n" +
        toBase64(data) + // Force UTF-8 encoding
        closeDelimiter;

    gapi.client.request({
        path: "/upload/drive/v2/files",
        method: "POST",
        params: {
            uploadType: "multipart"
        },
        headers: {
          "Content-Type": 'multipart/mixed; boundary="' + boundary + '"'
        },
        body: multipartRequestBody
    }).execute(response => {
        if (!response.error) {
            callback(response);
        }
        else {
            callback(response, response.error.message);
        }
    });
};

GoogleDrive.save = function (fileDescriptor, data) {
    var base64Data = toBase64(data); // Force UTF-8 encoding
    gapi.client.request({
        path: "/upload/drive/v2/files/" + fileDescriptor.id,
        method: "PUT",
        params: {
            uploadType: "media"
        },
        headers: {
            "Content-Type": fileDescriptor.mimeType,
            "Content-Length": base64Data.length,
            "Content-Encoding": "base64"
        },
        body: base64Data
    }).execute(response => {
        this.emit("save", fileDescriptor, response.error);
    });
};

function toBase64(data) {
    return btoa(unescape(encodeURIComponent(data)));
}

addBackend(GoogleDrive);
<commit_msg>Fixes API key error in Google Drive file picker<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

import {AbstractBackend, addBackend} from "./AbstractBackend";

export var GoogleDrive = Object.create(AbstractBackend);

// Configure these settings in GoogleDrive.config.js
GoogleDrive.clientId = "Your OAuth client Id";
GoogleDrive.apiKey = "Your developer API key";

GoogleDrive.init = function (container, _) {
    AbstractBackend.init.call(this, container, "sozi-editor-backend-GoogleDrive-input", _("Load from Google Drive"));

    $(window).blur(this.doAutosave.bind(this));

    gapi.client.setApiKey(this.apiKey);
    this.authorize(true);
    return this;
};

GoogleDrive.openFileChooser = function () {
    $("#sozi-editor-backend-GoogleDrive-input").click();
};

GoogleDrive.authorize = function (onInit) {
    gapi.auth.authorize({
        client_id: this.clientId,
        scope: "https://www.googleapis.com/auth/drive",
        immediate: onInit
    }, this.onAuthResult.bind(this, onInit));
};

GoogleDrive.onAuthResult = function (onInit, authResult) {
    var inputButton = $("#sozi-editor-backend-GoogleDrive-input");

    if (authResult && !authResult.error) {
        this.accessToken = authResult.access_token;
        // Access granted: create a file picker and show the "Load" button.
        gapi.client.load("drive", "v2");
        gapi.load("picker", {
            callback: () => {
                this.createPicker();
                inputButton.off("click").click(() => this.picker.setVisible(true));
                if (!onInit) {
                    inputButton.click();
                }
            }
        });
    }
    else {
        // No access token could be retrieved, show the button to start the authorization flow.
        inputButton.click(() => this.authorize(false));
    }
};

GoogleDrive.createPicker = function () {
    var view = new google.picker.View(google.picker.ViewId.DOCS);
    view.setMimeTypes("image/svg+xml");

    this.picker = new google.picker.PickerBuilder().
        addView(view).
        setOAuthToken(this.accessToken).
        setCallback(data => {
            if (data[google.picker.Response.ACTION] === google.picker.Action.PICKED) {
                gapi.client.drive.files.get({fileId: data.docs[0].id}).execute(response => {
                    if (!response.error) {
                        this.load(response);
                    }
                    else {
                        console.log(response.error.message);
                    }
                });
            }
        }).
        build();
};

GoogleDrive.getName = function (fileDescriptor) {
    return fileDescriptor.title;
};

GoogleDrive.getLocation = function (fileDescriptor) {
    return fileDescriptor.parents;
};

GoogleDrive.find = function (name, location, callback) {
    function findInParent(index) {
        gapi.client.drive.files.list({
            q: "title = '" + name + "' and " +
               "'" + location[index].id + "' in parents"
        }).execute(response => {
            if (response.items && response.items.length) {
                callback(response.items[0]);
            }
            else if (index < location.length - 1) {
                findInParent(index + 1);
            }
            else {
                callback(null);
            }
        });
    }
    findInParent(0);
};

// TODO implement the "change" event
GoogleDrive.load = function (fileDescriptor) {
    // The file is loaded using an AJAX GET operation.
    // The data type is forced to "text" to prevent parsing it.
    // Emit the "load" event with the file content in case of success,
    // or with the error status in case of failure.
    $.ajax(fileDescriptor.downloadUrl, {
        contentType: fileDescriptor.mimeType,
        dataType: "text",
        headers: {
            "Authorization": "Bearer " + this.accessToken
        },
        context: this
    }).done(data => this.emit("load", fileDescriptor, data))
      .fail((xhr, status) => this.emit("load", fileDescriptor, null, status));
};

GoogleDrive.create = function (name, location, mimeType, data, callback) {
    var boundary = "-------314159265358979323846";
    var delimiter = "\r\n--" + boundary + "\r\n";
    var closeDelimiter = "\r\n--" + boundary + "--";

    var metadata = {
        title: name,
        parents: location,
        mimeType
    };

    var multipartRequestBody =
        delimiter +
        "Content-Type: application/json\r\n\r\n" + JSON.stringify(metadata) +
        delimiter +
        "Content-Type: " + mimeType + "\r\n" +
        "Content-Transfer-Encoding: base64\r\n\r\n" +
        toBase64(data) + // Force UTF-8 encoding
        closeDelimiter;

    gapi.client.request({
        path: "/upload/drive/v2/files",
        method: "POST",
        params: {
            uploadType: "multipart"
        },
        headers: {
          "Content-Type": 'multipart/mixed; boundary="' + boundary + '"'
        },
        body: multipartRequestBody
    }).execute(response => {
        if (!response.error) {
            callback(response);
        }
        else {
            callback(response, response.error.message);
        }
    });
};

GoogleDrive.save = function (fileDescriptor, data) {
    var base64Data = toBase64(data); // Force UTF-8 encoding
    gapi.client.request({
        path: "/upload/drive/v2/files/" + fileDescriptor.id,
        method: "PUT",
        params: {
            uploadType: "media"
        },
        headers: {
            "Content-Type": fileDescriptor.mimeType,
            "Content-Length": base64Data.length,
            "Content-Encoding": "base64"
        },
        body: base64Data
    }).execute(response => {
        this.emit("save", fileDescriptor, response.error);
    });
};

function toBase64(data) {
    return btoa(unescape(encodeURIComponent(data)));
}

addBackend(GoogleDrive);
<|endoftext|>


<commit_before>import {ProseMirror} from "prosemirror/dist/edit/main"
import {fidusFnSchema} from "../schema"
import "prosemirror/dist/collab"
import {Doc} from "prosemirror/dist/model"

import {ModFootnoteEditor} from "./editor"
import {ModFootnoteMarkers} from "./markers"
import {ModFootnoteLayout} from "./layout"

export class ModFootnotes {
    constructor(editor) {
        editor.mod.footnotes = this
        this.editor = editor
        this.schema = fidusFnSchema
        this.footnotes = []
        this.init()
        this.bindEvents()
        new ModFootnoteEditor(this)
        new ModFootnoteMarkers(this)
        new ModFootnoteLayout(this)
    }

    init() {
        this.fnPm = new ProseMirror({
            place: document.getElementById('footnote-box-container'),
            //doc: new Doc(),
            schema: this.schema,
            collab: {
                version: 0
            } // Version number does not matter much, as we do not verify it between users.
        })
    }

    bindEvents() {
        let that = this
        // Set the current editor depending on where the focus currently is.
        this.fnPm.on("focus", function(){that.editor.currentPm = that.fnPm})
        this.editor.pm.on("focus", function(){that.editor.currentPm = that.editor.pm})
    }
}
<commit_msg>remove unused Doc-node import<commit_after>import {ProseMirror} from "prosemirror/dist/edit/main"
import {fidusFnSchema} from "../schema"
import "prosemirror/dist/collab"

import {ModFootnoteEditor} from "./editor"
import {ModFootnoteMarkers} from "./markers"
import {ModFootnoteLayout} from "./layout"

export class ModFootnotes {
    constructor(editor) {
        editor.mod.footnotes = this
        this.editor = editor
        this.schema = fidusFnSchema
        this.footnotes = []
        this.init()
        this.bindEvents()
        new ModFootnoteEditor(this)
        new ModFootnoteMarkers(this)
        new ModFootnoteLayout(this)
    }

    init() {
        this.fnPm = new ProseMirror({
            place: document.getElementById('footnote-box-container'),
            schema: this.schema,
            collab: {
                version: 0
            } // Version number does not matter much, as we do not verify it between users.
        })
    }

    bindEvents() {
        let that = this
        // Set the current editor depending on where the focus currently is.
        this.fnPm.on("focus", function(){that.editor.currentPm = that.fnPm})
        this.editor.pm.on("focus", function(){that.editor.currentPm = that.editor.pm})
    }
}
<|endoftext|>