<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var Cleaner = require('./statsd-clean');
var clean = Cleaner.clean;
var cleanHostPort = Cleaner.cleanHostPort;

function TChannelStatsd(channel, statsd) {
    if (!(this instanceof TChannelStatsd)) {
        return new TChannelStatsd(channel, statsd);
    }

    var self = this;

    self.statsd = statsd;
    self.channel = channel;
    self.channel.statEvent.on(onStat);

    function onStat(stat) {
        self.onStat(stat);
    }
}

function getKey(stat) {
    var prefix = stat.name;

    if (stat.tags.toStatKey) {
        return stat.tags.toStatKey(prefix);
    }

    return getSlowKey(stat, prefix);
}

function getSlowKey(stat, prefix) {
    /*eslint complexity: [2, 30]*/
    switch (prefix) {
        // outbound
        case 'tchannel.outbound.calls.system-errors':
        case 'tchannel.outbound.calls.operational-errors':
            return prefix + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags['target-service'], 'no-target-service') + '.' +
                clean(stat.tags['target-endpoint'], 'no-endpoint') + '.' +
                clean(stat.tags.type, 'no-type');

        case 'tchannel.outbound.calls.per-attempt.system-errors':
        case 'tchannel.outbound.calls.per-attempt.operational-errors':
            return prefix + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags['target-service'], 'no-target-service') + '.' +
                clean(stat.tags['target-endpoint'], 'no-endpoint') + '.' +
                clean(stat.tags.type, 'no-type') + '.' +
                stat.tags['retry-count'];

        case 'tchannel.outbound.calls.retries':
            return prefix + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags['target-service'], 'no-target-service') + '.' +
                clean(stat.tags['target-endpoint'], 'no-endpoint') + '.' +
                stat.tags['retry-count'];

        // inbound
        case 'tchannel.inbound.calls.system-errors':
            return prefix + '.' +
                clean(stat.tags['calling-service'], 'no-calling-service') + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags.endpoint, 'no-endpoint') + '.' +
                clean(stat.tags.type, 'no-type');

        case 'tchannel.inbound.protocol-errors':
        case 'tchannel.connections.active':
        case 'tchannel.connections.initiated':
        case 'tchannel.connections.connect-errors':
        case 'tchannel.connections.accepted':
            return prefix + '.' +
                cleanHostPort(stat.tags['peer-host-port'], 'no-peer-host-port');

        case 'tchannel.connections.accept-errors':
            return prefix + '.' +
                cleanHostPort(stat.tags['host-port'], 'no-host-port');

        case 'tchannel.connections.errors':
            return prefix + '.' +
                cleanHostPort(stat.tags['peer-host-port'], 'no-peer-host-port') + '.' +
                clean(stat.tags.type, 'no-type');

        case 'tchannel.connections.closed':
            return prefix + '.' +
                cleanHostPort(stat.tags['peer-host-port'], 'no-peer-host-port') + '.' +
                clean(stat.tags.reason, 'no-reason');

        // other types
        default:
            return 'tchannel.bad-stat-object';
    }
}

TChannelStatsd.prototype.onStat = function onStat(stat) {
    var self = this;

    var key = getKey(stat);

    if (stat.type === 'counter') {
        return self.statsd.increment(key, stat.value);
    } else if (stat.type === 'gauge') {
        return self.statsd.gauge(key, stat.value);
    } else if (stat.type === 'timing') {
        return self.statsd.timing(key, stat.value);
    } else {
        self.channel.logger.error('Trying to emit an invalid stat object', {
            statType: stat.type,
            statName: stat.name
        });
    }
};

module.exports = TChannelStatsd;
<commit_msg>use counter instead of increment in statsd<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var Cleaner = require('./statsd-clean');
var clean = Cleaner.clean;
var cleanHostPort = Cleaner.cleanHostPort;

function TChannelStatsd(channel, statsd) {
    if (!(this instanceof TChannelStatsd)) {
        return new TChannelStatsd(channel, statsd);
    }

    var self = this;

    self.statsd = statsd;
    self.channel = channel;
    self.channel.statEvent.on(onStat);

    function onStat(stat) {
        self.onStat(stat);
    }
}

function getKey(stat) {
    var prefix = stat.name;

    if (stat.tags.toStatKey) {
        return stat.tags.toStatKey(prefix);
    }

    return getSlowKey(stat, prefix);
}

function getSlowKey(stat, prefix) {
    /*eslint complexity: [2, 30]*/
    switch (prefix) {
        // outbound
        case 'tchannel.outbound.calls.system-errors':
        case 'tchannel.outbound.calls.operational-errors':
            return prefix + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags['target-service'], 'no-target-service') + '.' +
                clean(stat.tags['target-endpoint'], 'no-endpoint') + '.' +
                clean(stat.tags.type, 'no-type');

        case 'tchannel.outbound.calls.per-attempt.system-errors':
        case 'tchannel.outbound.calls.per-attempt.operational-errors':
            return prefix + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags['target-service'], 'no-target-service') + '.' +
                clean(stat.tags['target-endpoint'], 'no-endpoint') + '.' +
                clean(stat.tags.type, 'no-type') + '.' +
                stat.tags['retry-count'];

        case 'tchannel.outbound.calls.retries':
            return prefix + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags['target-service'], 'no-target-service') + '.' +
                clean(stat.tags['target-endpoint'], 'no-endpoint') + '.' +
                stat.tags['retry-count'];

        // inbound
        case 'tchannel.inbound.calls.system-errors':
            return prefix + '.' +
                clean(stat.tags['calling-service'], 'no-calling-service') + '.' +
                clean(stat.tags.service, 'no-service') + '.' +
                clean(stat.tags.endpoint, 'no-endpoint') + '.' +
                clean(stat.tags.type, 'no-type');

        case 'tchannel.inbound.protocol-errors':
        case 'tchannel.connections.active':
        case 'tchannel.connections.initiated':
        case 'tchannel.connections.connect-errors':
        case 'tchannel.connections.accepted':
            return prefix + '.' +
                cleanHostPort(stat.tags['peer-host-port'], 'no-peer-host-port');

        case 'tchannel.connections.accept-errors':
            return prefix + '.' +
                cleanHostPort(stat.tags['host-port'], 'no-host-port');

        case 'tchannel.connections.errors':
            return prefix + '.' +
                cleanHostPort(stat.tags['peer-host-port'], 'no-peer-host-port') + '.' +
                clean(stat.tags.type, 'no-type');

        case 'tchannel.connections.closed':
            return prefix + '.' +
                cleanHostPort(stat.tags['peer-host-port'], 'no-peer-host-port') + '.' +
                clean(stat.tags.reason, 'no-reason');

        // other types
        default:
            return 'tchannel.bad-stat-object';
    }
}

TChannelStatsd.prototype.onStat = function onStat(stat) {
    var self = this;

    var key = getKey(stat);

    if (stat.type === 'counter') {
        return self.statsd.counter(key, stat.value);
    } else if (stat.type === 'gauge') {
        return self.statsd.gauge(key, stat.value);
    } else if (stat.type === 'timing') {
        return self.statsd.timing(key, stat.value);
    } else {
        self.channel.logger.error('Trying to emit an invalid stat object', {
            statType: stat.type,
            statName: stat.name
        });
    }
};

module.exports = TChannelStatsd;
<|endoftext|>


<commit_before>const fastq = require('fastq');
const later = require('@breejs/later');
const pWaitFor = require('p-wait-for');
const isCronExpression = require('./is-cron-expression');

const worker = async (task, callback) => {
    try {
        let result = await task();
        callback(null, result);
    } catch (error) {
        callback(error);
    }
};

const handler = (error, result) => {
    if (error) {
        throw error;
    }
    // Can potentially standardise the result here
    return result;
};

class JobManager {
    constructor(logging) {
        this.queue = fastq(this, worker, 1);
        this.schedule = [];
        this.logging = logging;
    }

    /**
     * Adds job to queue
     *
     * @param {Function} job function to be executed in the queue
     * @param {Object} [data] data to be passed into the job
     */
    addJob(job, data) {
        this.logging.info('Adding one off job to the queue');

        this.queue.push(async () => {
            await job(data);
        }, handler);
    }

    /**
     * Schedules recuring job
     *
     * @param {Function|String} job - function or path to a file defining a job
     * @param {Object} data - data to be passed into the joba
     * @param {String} when - cron or human readable schedule format
     */
    scheduleJob(job, data, when) {
        let schedule;

        schedule = later.parse.text(when);

        if (isCronExpression(when)) {
            schedule = later.parse.cron(when);
        }

        if ((schedule.error && schedule.error !== -1) || schedule.schedules.length === 0) {
            throw new Error('Invalid schedule format');
        }

        this.logging.info(`Scheduling job. Next run on: ${later.schedule(schedule).next()}`);

        const cancelInterval = later.setInterval(() => {
            this.logging.info(`Scheduled job added to the queue.`);
            this.addJob(job, data);
        }, schedule);

        this.schedule.push(cancelInterval);
    }

    /**
     * @param {import('p-wait-for').Options} [options]
     */
    async shutdown(options) {
        this.schedule.forEach((cancelHandle) => {
            cancelHandle.clear();
        });

        if (this.queue.idle()) {
            return;
        }

        this.logging.warn('Waiting for busy job queue');

        await pWaitFor(() => this.queue.idle() === true, options);

        this.logging.warn('Job queue finished');
    }
}

module.exports = JobManager;
<commit_msg>Updated JSDoc<commit_after>const fastq = require('fastq');
const later = require('@breejs/later');
const pWaitFor = require('p-wait-for');
const isCronExpression = require('./is-cron-expression');

const worker = async (task, callback) => {
    try {
        let result = await task();
        callback(null, result);
    } catch (error) {
        callback(error);
    }
};

const handler = (error, result) => {
    if (error) {
        throw error;
    }
    // Can potentially standardise the result here
    return result;
};

class JobManager {
    constructor(logging) {
        this.queue = fastq(this, worker, 1);
        this.schedule = [];
        this.logging = logging;
    }

    /**
     * Adds job to queue
     *
     * @param {Function} job - function to be executed in the queue
     * @param {Object} [data] - data to be passed into the job
     */
    addJob(job, data) {
        this.logging.info('Adding one off job to the queue');

        this.queue.push(async () => {
            await job(data);
        }, handler);
    }

    /**
     * Schedules recuring job
     *
     * @param {Function|String} job - function or path to a file defining a job
     * @param {Object} data - data to be passed into the joba
     * @param {String} when - cron or human readable schedule format
     */
    scheduleJob(job, data, when) {
        let schedule;

        schedule = later.parse.text(when);

        if (isCronExpression(when)) {
            schedule = later.parse.cron(when);
        }

        if ((schedule.error && schedule.error !== -1) || schedule.schedules.length === 0) {
            throw new Error('Invalid schedule format');
        }

        this.logging.info(`Scheduling job. Next run on: ${later.schedule(schedule).next()}`);

        const cancelInterval = later.setInterval(() => {
            this.logging.info(`Scheduled job added to the queue.`);
            this.addJob(job, data);
        }, schedule);

        this.schedule.push(cancelInterval);
    }

    /**
     * @param {import('p-wait-for').Options} [options]
     */
    async shutdown(options) {
        this.schedule.forEach((cancelHandle) => {
            cancelHandle.clear();
        });

        if (this.queue.idle()) {
            return;
        }

        this.logging.warn('Waiting for busy job queue');

        await pWaitFor(() => this.queue.idle() === true, options);

        this.logging.warn('Job queue finished');
    }
}

module.exports = JobManager;
<|endoftext|>


<commit_before>/**
 *
 *
 */
(function () {
    'use strict';
    CPM.namespace('platform.services.replication');

    (function (replication, components, core) {

        replication.const = _.extend(replication.const || {}, {
            css: {
                base: 'composum-platform-replication-status',
                _badge: '_badge',
                _view: '_view',
                _stage: '_stage',
                _title: '_title',
                _process: '_process',
                _state: '_state .badge',
                _abort: '_abort',
                _synchronize: '_synchronize',
                _progress: '_progress .progress-bar',
                _timestamp: '_timestamp',
                dialog: 'composum-platform-replication-dialog',
                _footer: '_footer',
                _option: '_option',
                _full: '_full'
            },
            url: {
                servlet: '/bin/cpm/platform/staging',
                _publish: '.stageRelease',
                _release: 'releaseKey=',
                _abort: '.abortReplication',
                base: '/libs/composum/platform/services/replication',
                _dialog: '/dialog',
                _summary: '/status.summary',
                _status: '/status',
                _reload: '.reload'
            },
            polling: {
                running: 2000, idle: 10000
            },
            dialog: 'normal'
        });

        /**
         * @abstract triggers the abstract 'refresh()' function while state is 'running'
         */
        replication.StateMonitor = Backbone.View.extend({

            stopRefresh: function () {
                if (this.tmRefresh) {
                    window.clearTimeout(this.tmRefresh);
                    this.tmRefresh = undefined;
                }
            },

            resumeRefresh: function () {
                if (!this.tmRefresh) {
                    this.tmRefresh = window.setTimeout(_.bind(this.refresh, this),
                        replication.const.polling[this.data.state.state === 'running' ? 'running' : 'idle']);
                }
            }
        });

        replication.Badge = replication.StateMonitor.extend({

            initialize: function (options) {
                this.data = {
                    state: JSON.parse(Base64.decode(this.$el.data('state')))
                };
                this.resumeRefresh();
            },

            refresh: function () {
                this.tmRefresh = undefined;
                var u = replication.const.url;
                core.getJson(u.base + u._summary + '.' + this.data.state.stage + '.json' + this.$el.data('path'),
                    _.bind(function (state) {
                        var c = replication.const.css;
                        this.$el.removeClass().addClass(c.base + c._badge + ' widget badge badge-pill ' + state.state);
                        core.i18n.get([state.stage, state.state], _.bind(function (value) {
                            this.$el.attr('title', value[0] + ': ' + value[1]);
                        }, this));
                        this.data.state = state;
                        this.resumeRefresh();
                    }, this));
            }
        });

        CPM.widgets.register('.widget.' + replication.const.css.base + replication.const.css._badge, replication.Badge);

        replication.Process = Backbone.View.extend({

            initialize: function (options) {
                var c = replication.const.css;
                this.data = {
                    state: JSON.parse(Base64.decode(this.$el.data('state')))
                };
                this.$state = this.$('.' + c.base + c._state);
                this.$progress = this.$('.' + c.base + c._progress);
                this.$timestamp = this.$('.' + c.base + c._timestamp);
            },

            refresh: function (state) {
                this.$state.removeClass().addClass('badge ' + state.state);
                core.i18n.get(state.state, _.bind(function (value) {
                    this.$state.text(value);
                }, this));
                this.$progress
                    .css('width', state.progress + '%')
                    .attr('aria-valuenow', state.progress)
                    .text(state.progress + '%');
                if (state.state === 'synchron' && this.data.state.state !== 'synchron') {
                    core.i18n.get('finished at', _.bind(function (value) {
                        this.$timestamp.find('.key').text(value);
                    }, this));
                    this.$timestamp.find('.value').text(state.finishedAt);
                }
                this.data.state = state;
            }
        });

        replication.Status = replication.StateMonitor.extend({

            initialize: function (options) {
                this.listeners = [];
                this.initContent();
            },

            initContent: function () {
                this.stopRefresh();
                var c = replication.const.css;
                this.$view = this.$('.' + c.base + c._view);
                this.data = {
                    path: this.$view.data('path'),
                    stage: this.$view.data('stage'),
                    release: this.$view.data('release'),
                    releaseKey: this.$view.data('key'),
                    releaseLabel: this.$view.data('label'),
                    state: JSON.parse(Base64.decode(this.$view.data('state')))
                };
                this.$stage = this.$('.' + c.base + c._stage);
                this.$state = this.$stage.find('.' + c.base + c._state);
                this.$title = this.$stage.find('.' + c.base + c._title);
                this.$progress = this.$('.' + c.base + c._progress);
                this.$abort = this.$('.' + c.base + c._abort);
                this.$synchronize = this.$('.' + c.base + c._synchronize);
                var that = this;
                var processes = this.processes = {};
                this.$('.' + c.base + c._process).each(function () {
                    var process = core.getView($(this), replication.Process);
                    processes[process.data.state.id] = process;
                });
                this.$abort.find('button').click(_.bind(this.abort, this));
                this.$synchronize.find('button').click(_.bind(this.synchronize, this));
                this.propagateRefresh();
                this.resumeRefresh();
            },

            setLabel: function (label) {
                this.$title.text(label);
            },

            addListener: function (callback) {
                this.listeners = _.union(this.listeners, [callback]);
            },

            removeListener: function (callback) {
                this.listeners = _.without(this.listeners, [callback]);
            },

            propagateRefresh: function (callback) {
                this.listeners.forEach(function (callback) {
                    callback(this);
                }, this);
            },

            abort: function (event) {
                event.preventDefault();
                this.openPublishDialog(this.data.release, _.bind(this.reload, this));
                return false;
            },

            synchronize: function (event) {
                event.preventDefault();
                this.openPublishDialog(this.data.release, _.bind(this.reload, this));
                return false;
            },

            openPublishDialog: function (releasePath, callback) {
                var u = replication.const.url;
                var url = u.base + u._dialog + '.' + this.data.stage + '.html' + releasePath;
                core.openFormDialog(url, replication.PublishDialog, {
                        path: this.data.release,
                        stage: this.data.stage,
                        currentKey: this.data.releaseKey,
                        currentLabel: this.data.releaseLabel,
                        targetKey: this.data.releaseKey,
                        tagretLabel: this.data.releaseLabel
                    }, undefined,
                    _.bind(function () {
                        if (_.isFunction(callback)) {
                            callback();
                        }
                    }, this));
            },

            refresh: function () {
                this.tmRefresh = undefined;
                var u = replication.const.url;
                core.getJson(u.base + u._status + '.' + this.data.state.stage + '.json' + this.data.path,
                    _.bind(function (data) {
                        var state = data.summary;
                        this.$state.removeClass().addClass('badge badge-pill ' + state.state);
                        core.i18n.get(state.state, _.bind(function (value) {
                            this.$state.text(value);
                        }, this));
                        if (state.running) {
                            this.$abort.removeClass('hidden');
                            this.$synchronize.addClass('hidden');
                        } else {
                            this.$abort.addClass('hidden');
                            this.$synchronize.removeClass('hidden');
                        }
                        this.$progress
                            .css('width', state.progress + '%')
                            .attr('aria-valuenow', state.progress)
                            .text(state.progress + '%');
                        for (var i = 0; i < data.processes.length; i++) {
                            var process = this.processes[data.processes[i].id];
                            if (process) {
                                process.refresh(data.processes[i]);
                            } else {
                                this.reload();
                                return;
                            }
                        }
                        this.data.state = state;
                        this.propagateRefresh();
                        this.resumeRefresh();
                    }, this));
            },

            reload: function () {
                var u = replication.const.url;
                core.getHtml(u.base + u._status + u._reload + '.' + this.data.state.stage + '.html' + this.data.path,
                    _.bind(function (content) {
                        this.$el.html(content);
                        this.initContent();
                    }, this));
            }
        });

        CPM.widgets.register('.widget.' + replication.const.css.base, replication.Status);

        /**
         * @param options{path,stage,targetKey,targetLabel,currentKey,currentLabel}
         */
        replication.PublishDialog = components.LoadedDialog.extend({

            initialize: function (options) {
                var c = replication.const.css;
                components.LoadedDialog.prototype.initialize.call(this, options);
                this.data = {
                    path: options.path || this.$el.data('path'),
                    stage: options.stage || this.$el.data('stage'),
                    targetKey: options.targetKey,
                    targetLabel: options.targetLabel,
                    currentKey: options.currentKey,
                    currentLabel: options.currentLabel
                };
                this.status = core.getWidget(this.$el, '.' + c.base, replication.Status);
                var $footer = this.$('.' + c.dialog + c._footer);
                this.$fullSync = $footer.find('.' + c.dialog + c._option + c._full);
                this.$abort = $footer.find('button.abort');
                this.$cancel = $footer.find('button.cancel');
                this.$publish = $footer.find('button.publish');
                this.$close = $footer.find('button.exit');
                if (this.data.targetKey === this.data.currentKey) {
                    core.i18n.get('Synchronize', _.bind(function (value) {
                        this.$publish.text(value);
                    }, this));
                }
                this.refresh();
                this.status.addListener(_.bind(this.refresh, this));
                this.$abort.click(_.bind(this.abort, this));
                this.$publish.click(_.bind(this.publish, this));
                this.$close.click(_.bind(this.hide, this));
            },

            /**
             * @listens status: adjusts the button states
             */
            refresh: function () {
                if (this.data.currentLabel) {
                    this.status.setLabel(this.data.currentLabel);
                }
                if (this.status.data.state.state === 'running') {
                    this.$abort.removeClass('hidden');
                    this.$publish.attr('disabled', 'disabled');
                } else {
                    this.$abort.addClass('hidden');
                    this.$publish.removeAttr('disabled');
                }
            },

            abort: function (event) {
                event.preventDefault();
                var u = replication.const.url;
                var url = u.servlet + u._abort + '.' + this.data.stage + '.json' + this.data.path;
                core.ajaxPost(url, {
                        releaseKey: this.data.targetKey
                    }, {}, _.bind(function (result) {
                        this.status.refresh();
                    }, this)
                );
                return false;
            },

            publish: function (event) {
                event.preventDefault();
                var u = replication.const.url;
                var url = u.servlet + u._publish + '.' + this.data.stage + '.json' + this.data.path;
                core.ajaxPost(url, {
                        releaseKey: this.data.targetKey,
                        fullSync: this.$fullSync.prop('checked') ? 'true' : 'false'
                    }, {}, _.bind(function (result) {
                        if (replication.const.dialog === 'normal') {
                            // close like a normal dialog
                            this.hide();
                        } else {
                            // let it open to show replication status changes
                            this.$cancel.addClass('hidden');
                            this.$close.removeClass('hidden');
                            this.$publish.removeClass('btn-primary').addClass('btn-default');
                            this.status.reload();
                        }
                    }, this)
                );
                return false;
            }
        });

    })(CPM.platform.services.replication, CPM.core.components, CPM.core);

})();
<commit_msg>path url encodings abd POST charset hints fixed<commit_after>/**
 *
 *
 */
(function () {
    'use strict';
    CPM.namespace('platform.services.replication');

    (function (replication, components, core) {

        replication.const = _.extend(replication.const || {}, {
            css: {
                base: 'composum-platform-replication-status',
                _badge: '_badge',
                _view: '_view',
                _stage: '_stage',
                _title: '_title',
                _process: '_process',
                _state: '_state .badge',
                _abort: '_abort',
                _synchronize: '_synchronize',
                _progress: '_progress .progress-bar',
                _timestamp: '_timestamp',
                dialog: 'composum-platform-replication-dialog',
                _footer: '_footer',
                _option: '_option',
                _full: '_full'
            },
            url: {
                servlet: '/bin/cpm/platform/staging',
                _publish: '.stageRelease',
                _release: 'releaseKey=',
                _abort: '.abortReplication',
                base: '/libs/composum/platform/services/replication',
                _dialog: '/dialog',
                _summary: '/status.summary',
                _status: '/status',
                _reload: '.reload'
            },
            polling: {
                running: 2000, idle: 10000
            },
            dialog: 'normal'
        });

        /**
         * @abstract triggers the abstract 'refresh()' function while state is 'running'
         */
        replication.StateMonitor = Backbone.View.extend({

            stopRefresh: function () {
                if (this.tmRefresh) {
                    window.clearTimeout(this.tmRefresh);
                    this.tmRefresh = undefined;
                }
            },

            resumeRefresh: function () {
                if (!this.tmRefresh) {
                    this.tmRefresh = window.setTimeout(_.bind(this.refresh, this),
                        replication.const.polling[this.data.state.state === 'running' ? 'running' : 'idle']);
                }
            }
        });

        replication.Badge = replication.StateMonitor.extend({

            initialize: function (options) {
                this.data = {
                    state: JSON.parse(Base64.decode(this.$el.data('state')))
                };
                this.resumeRefresh();
            },

            refresh: function () {
                this.tmRefresh = undefined;
                var u = replication.const.url;
                core.getJson(u.base + u._summary + '.' + this.data.state.stage + '.json'
                    + core.encodePath(this.$el.data('path')),
                    _.bind(function (state) {
                        var c = replication.const.css;
                        this.$el.removeClass().addClass(c.base + c._badge + ' widget badge badge-pill ' + state.state);
                        core.i18n.get([state.stage, state.state], _.bind(function (value) {
                            this.$el.attr('title', value[0] + ': ' + value[1]);
                        }, this));
                        this.data.state = state;
                        this.resumeRefresh();
                    }, this));
            }
        });

        CPM.widgets.register('.widget.' + replication.const.css.base + replication.const.css._badge, replication.Badge);

        replication.Process = Backbone.View.extend({

            initialize: function (options) {
                var c = replication.const.css;
                this.data = {
                    state: JSON.parse(Base64.decode(this.$el.data('state')))
                };
                this.$state = this.$('.' + c.base + c._state);
                this.$progress = this.$('.' + c.base + c._progress);
                this.$timestamp = this.$('.' + c.base + c._timestamp);
            },

            refresh: function (state) {
                this.$state.removeClass().addClass('badge ' + state.state);
                core.i18n.get(state.state, _.bind(function (value) {
                    this.$state.text(value);
                }, this));
                this.$progress
                    .css('width', state.progress + '%')
                    .attr('aria-valuenow', state.progress)
                    .text(state.progress + '%');
                if (state.state === 'synchron' && this.data.state.state !== 'synchron') {
                    core.i18n.get('finished at', _.bind(function (value) {
                        this.$timestamp.find('.key').text(value);
                    }, this));
                    this.$timestamp.find('.value').text(state.finishedAt);
                }
                this.data.state = state;
            }
        });

        replication.Status = replication.StateMonitor.extend({

            initialize: function (options) {
                this.listeners = [];
                this.initContent();
            },

            initContent: function () {
                this.stopRefresh();
                var c = replication.const.css;
                this.$view = this.$('.' + c.base + c._view);
                this.data = {
                    path: this.$view.data('path'),
                    stage: this.$view.data('stage'),
                    release: this.$view.data('release'),
                    releaseKey: this.$view.data('key'),
                    releaseLabel: this.$view.data('label'),
                    state: JSON.parse(Base64.decode(this.$view.data('state')))
                };
                this.$stage = this.$('.' + c.base + c._stage);
                this.$state = this.$stage.find('.' + c.base + c._state);
                this.$title = this.$stage.find('.' + c.base + c._title);
                this.$progress = this.$('.' + c.base + c._progress);
                this.$abort = this.$('.' + c.base + c._abort);
                this.$synchronize = this.$('.' + c.base + c._synchronize);
                var that = this;
                var processes = this.processes = {};
                this.$('.' + c.base + c._process).each(function () {
                    var process = core.getView($(this), replication.Process);
                    processes[process.data.state.id] = process;
                });
                this.$abort.find('button').click(_.bind(this.abort, this));
                this.$synchronize.find('button').click(_.bind(this.synchronize, this));
                this.propagateRefresh();
                this.resumeRefresh();
            },

            setLabel: function (label) {
                this.$title.text(label);
            },

            addListener: function (callback) {
                this.listeners = _.union(this.listeners, [callback]);
            },

            removeListener: function (callback) {
                this.listeners = _.without(this.listeners, [callback]);
            },

            propagateRefresh: function (callback) {
                this.listeners.forEach(function (callback) {
                    callback(this);
                }, this);
            },

            abort: function (event) {
                event.preventDefault();
                this.openPublishDialog(this.data.release, _.bind(this.reload, this));
                return false;
            },

            synchronize: function (event) {
                event.preventDefault();
                this.openPublishDialog(this.data.release, _.bind(this.reload, this));
                return false;
            },

            openPublishDialog: function (releasePath, callback) {
                var u = replication.const.url;
                var url = u.base + u._dialog + '.' + this.data.stage + '.html' + releasePath;
                core.openFormDialog(url, replication.PublishDialog, {
                        path: this.data.release,
                        stage: this.data.stage,
                        currentKey: this.data.releaseKey,
                        currentLabel: this.data.releaseLabel,
                        targetKey: this.data.releaseKey,
                        tagretLabel: this.data.releaseLabel
                    }, undefined,
                    _.bind(function () {
                        if (_.isFunction(callback)) {
                            callback();
                        }
                    }, this));
            },

            refresh: function () {
                this.tmRefresh = undefined;
                var u = replication.const.url;
                core.getJson(u.base + u._status + '.' + this.data.state.stage + '.json'
                    + core.encodePath(this.data.path),
                    _.bind(function (data) {
                        var state = data.summary;
                        this.$state.removeClass().addClass('badge badge-pill ' + state.state);
                        core.i18n.get(state.state, _.bind(function (value) {
                            this.$state.text(value);
                        }, this));
                        if (state.running) {
                            this.$abort.removeClass('hidden');
                            this.$synchronize.addClass('hidden');
                        } else {
                            this.$abort.addClass('hidden');
                            this.$synchronize.removeClass('hidden');
                        }
                        this.$progress
                            .css('width', state.progress + '%')
                            .attr('aria-valuenow', state.progress)
                            .text(state.progress + '%');
                        for (var i = 0; i < data.processes.length; i++) {
                            var process = this.processes[data.processes[i].id];
                            if (process) {
                                process.refresh(data.processes[i]);
                            } else {
                                this.reload();
                                return;
                            }
                        }
                        this.data.state = state;
                        this.propagateRefresh();
                        this.resumeRefresh();
                    }, this));
            },

            reload: function () {
                var u = replication.const.url;
                core.getHtml(u.base + u._status + u._reload + '.' + this.data.state.stage + '.html'
                    + core.encodePath(this.data.path),
                    _.bind(function (content) {
                        this.$el.html(content);
                        this.initContent();
                    }, this));
            }
        });

        CPM.widgets.register('.widget.' + replication.const.css.base, replication.Status);

        /**
         * @param options{path,stage,targetKey,targetLabel,currentKey,currentLabel}
         */
        replication.PublishDialog = components.LoadedDialog.extend({

            initialize: function (options) {
                var c = replication.const.css;
                components.LoadedDialog.prototype.initialize.call(this, options);
                this.data = {
                    path: options.path || this.$el.data('path'),
                    stage: options.stage || this.$el.data('stage'),
                    targetKey: options.targetKey,
                    targetLabel: options.targetLabel,
                    currentKey: options.currentKey,
                    currentLabel: options.currentLabel
                };
                this.status = core.getWidget(this.$el, '.' + c.base, replication.Status);
                var $footer = this.$('.' + c.dialog + c._footer);
                this.$fullSync = $footer.find('.' + c.dialog + c._option + c._full);
                this.$abort = $footer.find('button.abort');
                this.$cancel = $footer.find('button.cancel');
                this.$publish = $footer.find('button.publish');
                this.$close = $footer.find('button.exit');
                if (this.data.targetKey === this.data.currentKey) {
                    core.i18n.get('Synchronize', _.bind(function (value) {
                        this.$publish.text(value);
                    }, this));
                }
                this.refresh();
                this.status.addListener(_.bind(this.refresh, this));
                this.$abort.click(_.bind(this.abort, this));
                this.$publish.click(_.bind(this.publish, this));
                this.$close.click(_.bind(this.hide, this));
            },

            /**
             * @listens status: adjusts the button states
             */
            refresh: function () {
                if (this.data.currentLabel) {
                    this.status.setLabel(this.data.currentLabel);
                }
                if (this.status.data.state.state === 'running') {
                    this.$abort.removeClass('hidden');
                    this.$publish.attr('disabled', 'disabled');
                } else {
                    this.$abort.addClass('hidden');
                    this.$publish.removeAttr('disabled');
                }
            },

            abort: function (event) {
                event.preventDefault();
                var u = replication.const.url;
                var url = u.servlet + u._abort + '.' + this.data.stage + '.json' + core.encodePath(this.data.path);
                core.ajaxPost(url, {
                        _charset_: 'UTF-8',
                        releaseKey: this.data.targetKey
                    }, {}, _.bind(function (result) {
                        this.status.refresh();
                    }, this)
                );
                return false;
            },

            publish: function (event) {
                event.preventDefault();
                var u = replication.const.url;
                var url = u.servlet + u._publish + '.' + this.data.stage + '.json' + core.encodePath(this.data.path);
                core.ajaxPost(url, {
                        _charset_: 'UTF-8',
                        releaseKey: this.data.targetKey,
                        fullSync: this.$fullSync.prop('checked') ? 'true' : 'false'
                    }, {}, _.bind(function (result) {
                        if (replication.const.dialog === 'normal') {
                            // close like a normal dialog
                            this.hide();
                        } else {
                            // let it open to show replication status changes
                            this.$cancel.addClass('hidden');
                            this.$close.removeClass('hidden');
                            this.$publish.removeClass('btn-primary').addClass('btn-default');
                            this.status.reload();
                        }
                    }, this)
                );
                return false;
            }
        });

    })(CPM.platform.services.replication, CPM.core.components, CPM.core);

})();
<|endoftext|>


<commit_before>function ai_move_cmp_fn(a, b)
{
    return a.score - b.score;
}

function AiMove(unit)
{
    this.unit = unit;
    this.doMove = false;
    this.x = 0;
    this.y = 0;
    this.target = undefined;
    this.score = 0;
}

AiMove.prototype.setMove =
    function(x, y)
    {
        this.x = x;
        this.y = y;
        this.doMove = true;
    }

AiMove.prototype.attackUnit =
    function(unit)
    {
        this.target = unit;
    }

AiMove.prototype.setScore =
    function(v)
    {
        this.score = v;
    }

function Ai(game)
{
    this.game = game;

    var game_map = game.getGameMap();
    this.inf_map = new InfluenceMap(game_map.width, game_map.height, visible=true);
}

Ai.prototype.findBestMove =
    function(unit)
    {
        var game_map = this.game.getGameMap();
        var my_army = this.game.getCurrentArmy();
        var my_army_iter = new UnitIterator(my_army);

        var enemy_unit_iter = g.getEnemyUnitIterator();
        var other_unit;

        /*
         * Need to select the unit as functions such as isValidMove
         * check for the selected game unit.
         */
        this.game.selectUnit(unit.id);

        this.inf_map.clearAll();

        var map_tiles = this.inf_map.getSurroundingHex(unit.x, unit.y, unit.move);
        var map_i;
        var x, y;

        map_tiles.push({"x":unit.x, "y":unit.y});

        console.log("------FINDING BEST MOVE FOR "+unit.name+", current at ("+unit.x+","+unit.y+") --------");

        for (map_i = 0; map_i < map_tiles.length; map_i++)
        {
            //console.log("considering "+map_tiles[map_i].x+","+map_tiles[map_i].y)
            x = map_tiles[map_i].x;
            y = map_tiles[map_i].y;

            /* Skip any square that's occupied (except by this unit) or impassable */
            if (!game_map.isPassable(x, y) || (g.unitInTile(x, y) && (x != unit.x || y != unit.y)))
            {
                /* Don't set any influence and they won't get considered at all */
                continue;
            }

            /* Initialise the tile, otherwise we'll only consider tiles
             * affected by something below.
             * Initialise current tile to 1 so we have a tendency to stay in
             * place if there's no better options.
             */
            this.inf_map.setInfluence(x, y, (x == unit.x && y == unit.y)?1:0);

            /* Is this in our half - +inf if we are in defense mode +10 */

            /* Is this an objective +20 */
            var objective = this.game.objectives.getObjective(x, y);
            if (objective !== undefined)
            {
                if (objective.owner == my_army.id)
                {
                    /* If it's ours then it's good to stay here to defend */
                    this.inf_map.addInfluence(x, y, 4);
                }
                else
                {
                    this.inf_map.addInfluence
                    (
                        x,
                        y,
                        Math.max(0, 12 - hexmap_distance(x, y, unit.x, unit.y))
                    );
                }
            }
            /* Is this a good defense position - difficult access for enemy +15 */

            /* Does this position defend a friend +10 */
            my_army_iter.moveFirst();
            while (my_army_iter.moveNext())
            {
                other_unit = my_army_iter.get();
                if (other_unit.id == unit.id)
                    continue;
                //console.log(4 - hexmap_distance(other_unit.x, other_unit.y, x, y));
                this.inf_map.addInfluence
                (
                    x,
                    y,
                    Math.max(0, 4 - hexmap_distance(other_unit.x, other_unit.y, x, y))
                );
            }
            //console.log("------");

            /* Can I attack an enemy from here +10 */
            if (!unit.getTracker().attacked)
            {
                enemy_unit_iter.moveFirst();
                while (enemy_unit_iter.moveNext())
                {
                    other_unit = enemy_unit_iter.get();

                    if
                    (
                        hexmap_distance(other_unit.x, other_unit.y, x, y)
                        <=
                        unit.range
                    )
                    {
                        console.log
                        (
                            "can attack " + other_unit.name +
                            " in (" + other_unit.x + "," + other_unit.y +
                            ") from ("+x+","+y+")"
                        );
                        /* influence will relative to the % of damage we can do
                         * Taking the min of the ratio or the unit health is an
                         * attempt to stop powerful units moving miles to attack
                         * something that another unit could kill.
                         */
                        var dmg_ratio = Math.min(unit.damage / other_unit.health, other_unit.health);
                        this.inf_map.addInfluence(x, y, dmg_ratio * 30 + 0.5);

                        /* Add some extra influence if we can attack without moving
                         * And make it a lot if we can kill them in current location
                         * That's a no brainer move
                         */
                        if (x == unit.x && y == unit.y)
                        {
                            this.inf_map.addInfluence(x, y, dmg_ratio * 20);
                        }
                    }
                }
            }

            /* Can I be attacked here -15
             * But if I'm defended by a friend, then this is less of a worry
             * i.e. archer + runner vs archer + runner
             * We want runner to hit archer followed by archer hitting runner
             * We don't want the runner to be scared to take the attack.
             * Will probably be good to count wits here and have that factor
             * in.
             */
            var enemy_unit_counter = 0;
            enemy_unit_iter.moveFirst();
            while (enemy_unit_iter.moveNext())
            {
                other_unit = enemy_unit_iter.get();

                if
                (
                    hexmap_distance(other_unit.x, other_unit.y, x, y)
                    <=
                    (other_unit.range + other_unit.move)
                )
                {
                    if
                    (
                        enemy_unit_counter == 0
                        &&
                        unit.damage >= other_unit.health
                        &&
                        hexmap_distance(other_unit.x, other_unit.y, x, y) <= unit.range
                    )
                    {
                        /* ignore this one */
                        enemy_unit_counter += 1;
                        console.log(unit.name+": ignoring "+other_unit.name);
                    }
                    else if (other_unit.damage >= unit.health)
                    {
                        /* we are going to die if we go here */
                        this.inf_map.addInfluence(x, y, -20);
                        console.log(unit.name+": "+other_unit.name+" will kill me!");
                    }
                    else
                    {
                        /* will damage but not kill us, not so bad */
                        this.inf_map.addInfluence(x, y, -10);
                        console.log(unit.name+": not overly worried about "+other_unit.name);
                    }
                }
            }

            /* Does this increase my view significantly +5 */

            /* Is it close to a danger zone - e.g. opponent spawn -10 */

            console.log("("+x+","+y+") = "+this.inf_map.getTile(x,y).value);
        }

        /*
         * Make a move object and return it.
         */
        var m = new AiMove(unit);

        var attack_pos = {"x":unit.x, "y":unit.y};

        var inf_map_best = this.inf_map.getHighest();
        if (inf_map_best != undefined)
        {
            m.setScore(inf_map_best.score);

            console.log
            (
                "Best move for "+unit.name
                +
                " at ("+unit.x+","+unit.y+")"
                +
                " to ("+inf_map_best.x +","+ inf_map_best.y+")"
                +
                " with score="+inf_map_best.score
            );

            if (inf_map_best.x != unit.x || inf_map_best.y != unit.y)
            {
                m.setMove(inf_map_best.x, inf_map_best.y);
            }

            attack_pos.x = inf_map_best.x;
            attack_pos.y = inf_map_best.y;
        }

        enemy_unit_iter.moveFirst();
        var attack_unit = undefined;
        var max_ratio = 0.0;

        while (enemy_unit_iter.moveNext())
        {
            other_unit = enemy_unit_iter.get();

            if
            (
                hexmap_distance(other_unit.x, other_unit.y, attack_pos.x, attack_pos.y)
                <=
                unit.range
            )
            {
                /*
                console.log
                (
                    "in position to attack " + other_unit.name +
                    " in (" + other_unit.x + "," + other_unit.y +
                    ") from ("+attack_pos.x +","+ attack_pos.y+")"
                );
                */
                /* influence will relative to the % of damage we can do */
                var dmg_ratio = unit.damage / other_unit.health;

                if (dmg_ratio > max_ratio)
                {
                    max_ratio = dmg_ratio;
                    attack_unit = other_unit;
                    //console.log(unit.name +  ", might attack" + attack_unit.name);
                }
            }
        }

        if (attack_unit == undefined && !m.doMove)
        {
            console.log("No good moves for "+unit.name + " (attack_unit="+attack_unit+", m.doMove="+m.doMove);
            return undefined;
        }

        m.attackUnit(attack_unit);

        return m;
    }

Ai.prototype.Turn =
    function()
    {
        var g = this.game;
        my_army = g.getCurrentArmy();

        var unit_iter = new UnitIterator(my_army);
        var unit_tracker = []
        var unit;
        var pq = new PriorityQueue(ai_move_cmp_fn);
        var done = false;

        var i = 0;
        while (unit_iter.moveNext())
        {
            unit = unit_iter.get();
            unit_tracker[i] = {"unit":unit, "moved":false};
            i += 1;
        }

        console.log("============= DOING AI TURN ==================");

        while (!done)
        {
            console.log("wits="+my_army.getTracker().wits);
            /*
             * Work out the move for each unit and store in a priority queue
             * ordered by move score.
             */
            unit_iter.moveFirst();
            while (unit_iter.moveNext())
            {
                unit = unit_iter.get();
                if (!unit.getTracker().moved || !unit.getTracker().attacked)
                {
                    var m = this.findBestMove(unit);
                    if (m != undefined)
                    {
                        pq.insert(m);
                    }
                }
            }

            /*
             * Execute moves in order of score.
             */
            var move = pq.pop();
            if (move != undefined)
            {
                /* Moves and attacks won't happen if there aren't enough wits */
                g.selectUnit(move.unit.id);
                if (move.doMove)
                {
                    console.log("moving "+move.unit.name+" to "+move.x+","+move.y);
                    g.MoveCurrentUnit(move.x, move.y);
                }
                else
                {
                    console.log(move.unit.name+" decided not to move.");
                }

                if (move.target != undefined)
                {
                    console.log(unit.name+" is attacking "+move.target.name);
                    g.attackWithCurrentUnit(move.target.id);
                }
                /* Update the view after the ai has moved */
                g.updateFogOfWar();
                g.getGameMap().redraw();
            }

            pq.clear();

            if
            (
                move == undefined
                ||
                my_army.getTracker().wits < 1
            )
            {
                done = true;
            }
        }
    }<commit_msg>AI shouldn't block spawn points and gets some randomness<commit_after>function ai_move_cmp_fn(a, b)
{
    return a.score - b.score;
}

function AiMove(unit)
{
    this.unit = unit;
    this.doMove = false;
    this.x = 0;
    this.y = 0;
    this.target = undefined;
    this.score = 0;
}

AiMove.prototype.setMove =
    function(x, y)
    {
        this.x = x;
        this.y = y;
        this.doMove = true;
    }

AiMove.prototype.attackUnit =
    function(unit)
    {
        this.target = unit;
    }

AiMove.prototype.setScore =
    function(v)
    {
        this.score = v;
    }

function Ai(game)
{
    this.game = game;

    var game_map = game.getGameMap();
    this.inf_map = new InfluenceMap(game_map.width, game_map.height, visible=true);

    this.aidebug = new AiDebug(game, game_map);
}

Ai.prototype.findBestMove =
    function(unit)
    {
        var game_map = this.game.getGameMap();
        var my_army = this.game.getCurrentArmy();
        var my_army_iter = new UnitIterator(my_army);

        var enemy_unit_iter = g.getEnemyUnitIterator();
        var other_unit;

        /*
         * Need to select the unit as functions such as isValidMove
         * check for the selected game unit.
         */
        this.game.selectUnit(unit.id);

        this.inf_map.clearAll();

        var map_tiles = this.inf_map.getSurroundingHex(unit.x, unit.y, unit.move);
        var map_i;
        var x, y;

        map_tiles.push({"x":unit.x, "y":unit.y});

        console.log("------FINDING BEST MOVE FOR "+unit.name+", current at ("+unit.x+","+unit.y+") --------");

        for (map_i = 0; map_i < map_tiles.length; map_i++)
        {
            //console.log("considering "+map_tiles[map_i].x+","+map_tiles[map_i].y)
            x = map_tiles[map_i].x;
            y = map_tiles[map_i].y;

            /* Skip any square that's occupied (except by this unit) or impassable */
            if (!game_map.isPassable(x, y) || (g.unitInTile(x, y) && (x != unit.x || y != unit.y)))
            {
                /* Don't set any influence and they won't get considered at all */
                continue;
            }

            /* Initialise the tile, otherwise we'll only consider tiles
             * affected by something below.
             * Initialise current tile to 1 so we have a tendency to stay in
             * place if there's no better options.
             * If playing the game without wits, there's no benefit to staying
             * in place so cancel that above in this version.
             */
            //this.inf_map.setInfluence(x, y, (x == unit.x && y == unit.y)?1:0);
            //this.inf_map.setInfluence(x, y, 0);
            // add a small amount of randonmisation to stop us getting stuck in a steady state.
            this.inf_map.setInfluence(x, y, Math.random() * 3);

            /* Is this in our half - +inf if we are in defense mode +10 */

            /* Is this an objective +20 */
            var objective = this.game.objectives.getObjective(x, y);
            if (objective !== undefined)
            {
                if (objective.owner == my_army.id)
                {
                    /* If it's ours then it's good to stay here to defend */
                    this.inf_map.addInfluence(x, y, 4);
                }
                else
                {
                    this.inf_map.addInfluence
                    (
                        x,
                        y,
                        Math.max(0, 12 - hexmap_distance(x, y, unit.x, unit.y))
                    );
                }
            }

            /* Don't block spawn points */
            if (game_map.getTile(x, y).tile_type == TILE_SPAWN0 || game_map.getTile(x, y).tile_type == TILE_SPAWN1)
            {
                this.inf_map.addInfluence(x, y, -10);
            }

            /* Approach enemy spawn */
            // for now, just make them move right a bit
            this.inf_map.addInfluence(x, y, x - unit.x);

            /* Is this a good defense position - difficult access for enemy +15 */

            /* Does this position defend a friend +10 */
            my_army_iter.moveFirst();
            while (my_army_iter.moveNext())
            {
                other_unit = my_army_iter.get();
                if (other_unit.id == unit.id)
                    continue;
                //console.log(4 - hexmap_distance(other_unit.x, other_unit.y, x, y));
                this.inf_map.addInfluence
                (
                    x,
                    y,
                    Math.max(0, 4 - hexmap_distance(other_unit.x, other_unit.y, x, y))
                );
            }
            //console.log("------");

            /* Can I attack an enemy from here +10 */
            if (!unit.getTracker().attacked)
            {
                enemy_unit_iter.moveFirst();
                while (enemy_unit_iter.moveNext())
                {
                    other_unit = enemy_unit_iter.get();

                    if
                    (
                        hexmap_distance(other_unit.x, other_unit.y, x, y)
                        <=
                        unit.range
                    )
                    {
                        console.log
                        (
                            "can attack " + other_unit.name +
                            " in (" + other_unit.x + "," + other_unit.y +
                            ") from ("+x+","+y+")"
                        );
                        /* influence will relative to the % of damage we can do
                         * Taking the min of the ratio or the unit health is an
                         * attempt to stop powerful units moving miles to attack
                         * something that another unit could kill.
                         */
                        var dmg_ratio = Math.min(unit.damage / other_unit.health, other_unit.health);
                        this.inf_map.addInfluence(x, y, dmg_ratio * 30 + 0.5);

                        /* Add some extra influence if we can attack without moving
                         * And make it a lot if we can kill them in current location
                         * That's a no brainer move
                         */
                        if (x == unit.x && y == unit.y)
                        {
                            this.inf_map.addInfluence(x, y, dmg_ratio * 20);
                        }
                    }
                }
            }

            /* Can I be attacked here -15
             * But if I'm defended by a friend, then this is less of a worry
             * i.e. archer + runner vs archer + runner
             * We want runner to hit archer followed by archer hitting runner
             * We don't want the runner to be scared to take the attack.
             * Will probably be good to count wits here and have that factor
             * in.
             */
            var enemy_unit_counter = 0;
            enemy_unit_iter.moveFirst();
            while (enemy_unit_iter.moveNext())
            {
                other_unit = enemy_unit_iter.get();

                if
                (
                    hexmap_distance(other_unit.x, other_unit.y, x, y)
                    <=
                    (other_unit.range + other_unit.move)
                )
                {
                    if
                    (
                        enemy_unit_counter == 0
                        &&
                        unit.damage >= other_unit.health
                        &&
                        hexmap_distance(other_unit.x, other_unit.y, x, y) <= unit.range
                    )
                    {
                        /* ignore this one */
                        enemy_unit_counter += 1;
                        console.log(unit.name+": ignoring "+other_unit.name);
                    }
                    else if (other_unit.damage >= unit.health)
                    {
                        /* we are going to die if we go here */
                        this.inf_map.addInfluence(x, y, -20);
                        console.log(unit.name+": "+other_unit.name+" will kill me!");
                    }
                    else
                    {
                        /* will damage but not kill us, not so bad */
                        this.inf_map.addInfluence(x, y, -10);
                        console.log(unit.name+": not overly worried about "+other_unit.name);
                    }
                }
            }

            /* Does this increase my view significantly +5 */

            /* Is it close to a danger zone - e.g. opponent spawn -10 */

            console.log("("+x+","+y+") = "+this.inf_map.getTile(x,y).value);
        }

        /*
         * Make a move object and return it.
         */
        var m = new AiMove(unit);

        var attack_pos = {"x":unit.x, "y":unit.y};

        var inf_map_best = this.inf_map.getHighest();
        if (inf_map_best != undefined)
        {
            m.setScore(inf_map_best.score);

            console.log
            (
                "Best move for "+unit.name
                +
                " at ("+unit.x+","+unit.y+")"
                +
                " to ("+inf_map_best.x +","+ inf_map_best.y+")"
                +
                " with score="+inf_map_best.score
            );

            if (inf_map_best.x != unit.x || inf_map_best.y != unit.y)
            {
                m.setMove(inf_map_best.x, inf_map_best.y);
            }

            attack_pos.x = inf_map_best.x;
            attack_pos.y = inf_map_best.y;
        }

        enemy_unit_iter.moveFirst();
        var attack_unit = undefined;
        var max_ratio = 0.0;

        while (enemy_unit_iter.moveNext())
        {
            other_unit = enemy_unit_iter.get();

            if
            (
                hexmap_distance(other_unit.x, other_unit.y, attack_pos.x, attack_pos.y)
                <=
                unit.range
            )
            {
                /*
                console.log
                (
                    "in position to attack " + other_unit.name +
                    " in (" + other_unit.x + "," + other_unit.y +
                    ") from ("+attack_pos.x +","+ attack_pos.y+")"
                );
                */
                /* influence will relative to the % of damage we can do */
                var dmg_ratio = unit.damage / other_unit.health;

                if (dmg_ratio > max_ratio)
                {
                    max_ratio = dmg_ratio;
                    attack_unit = other_unit;
                    //console.log(unit.name +  ", might attack" + attack_unit.name);
                }
            }
        }

        if (attack_unit == undefined && !m.doMove)
        {
            console.log("No good moves for "+unit.name + " (attack_unit="+attack_unit+", m.doMove="+m.doMove);
            return undefined;
        }

        m.attackUnit(attack_unit);

        return m;
    }

Ai.prototype.singleUnitTurn =
    function(unit)
    {
        var g = this.game;
        var move = this.findBestMove(unit);
        if (move !== undefined) {
            // @todo disable wit counting
            g.selectUnit(move.unit.id);
            if (move.doMove)
            {
                console.log("moving "+move.unit.name+" to "+move.x+","+move.y);
                g.MoveCurrentUnit(move.x, move.y);
            }
            else
            {
                console.log(move.unit.name+" decided not to move.");
            }

            if (move.target != undefined)
            {
                console.log(unit.name+" is attacking "+move.target.name);
                g.attackWithCurrentUnit(move.target.id);
            }
        }
        /* Update the view after the ai has moved */
        g.updateFogOfWar();
        g.getGameMap().redraw();
        this.aidebug.showInfMap(this.inf_map);
    }

/*
 * Runs through a whole turn for the AI.
 * This gives the best chance to work together and make the most
 * of the wits by spending them on the best moves.
 */
Ai.prototype.Turn =
    function()
    {
        var g = this.game;
        my_army = g.getCurrentArmy();

        var unit_iter = new UnitIterator(my_army);
        var unit_tracker = []
        var unit;
        var pq = new PriorityQueue(ai_move_cmp_fn);
        var done = false;

        var i = 0;
        while (unit_iter.moveNext())
        {
            unit = unit_iter.get();
            unit_tracker[i] = {"unit":unit, "moved":false};
            i += 1;
        }

        console.log("============= DOING AI TURN ==================");

        while (!done)
        {
            console.log("wits="+my_army.getTracker().wits);
            /*
             * Work out the move for each unit and store in a priority queue
             * ordered by move score.
             */
            unit_iter.moveFirst();
            while (unit_iter.moveNext())
            {
                unit = unit_iter.get();
                if (!unit.getTracker().moved || !unit.getTracker().attacked)
                {
                    var m = this.findBestMove(unit);
                    if (m != undefined)
                    {
                        pq.insert(m);
                    }
                }
            }

            /*
             * Execute moves in order of score.
             */
            var move = pq.pop();
            if (move != undefined)
            {
                /* Moves and attacks won't happen if there aren't enough wits */
                g.selectUnit(move.unit.id);
                if (move.doMove)
                {
                    console.log("moving "+move.unit.name+" to "+move.x+","+move.y);
                    g.MoveCurrentUnit(move.x, move.y);
                }
                else
                {
                    console.log(move.unit.name+" decided not to move.");
                }

                if (move.target != undefined)
                {
                    console.log(unit.name+" is attacking "+move.target.name);
                    g.attackWithCurrentUnit(move.target.id);
                }
                /* Update the view after the ai has moved */
                g.updateFogOfWar();
                g.getGameMap().redraw();
            }

            pq.clear();

            if
            (
                move == undefined
                ||
                my_army.getTracker().wits < 1
            )
            {
                done = true;
            }
        }
    }
<|endoftext|>


<commit_before>'use strict'
var inView = require('in-view')
var shortid = require('shortid')
var isDefine = function (v) { return typeof v !== 'undefined' },
isString = function (v) { return typeof v === 'string' },
isNumber = function (v) { return typeof v === 'number' },
isFunc   = function (v) { return typeof v === 'function' },
isArray  = function (v) { return Array.isArray(v) },
isObject = function (v) { return !isArray(v) && typeof v === 'object' }
var hasKey = function (obj, src) {
  var result = false
  var key
  for (key in obj) {
    if (obj.hasOwnProperty(key) && key === src) result = true
  }
  return result
}

var objLength = function (v) {
  var result=0
  var key
  for (key in v) {
      v.hasOwnProperty(key) && result++
  }
  return result
}
// check if in object in array has same value
var hasObj_Array = function (v, search, val) {
  const defined = Object.create(null)
  defined.is = false
  defined.count = 0
  var length = v.length
  var i
  for (i = 0; i < length; i++) {
    if (isDefine(v[i]) && isDefine(v[i][search])) {
      if (isDefine(val) && v[i][search] === val) {
        defined.is = true
        defined.count += 1
      }
    }
  }
  return defined
}
var countEntered = 0
var countExits = 0
// create element object
var createEl = Object.create(null)
createEl.$enter = []
createEl.$exits = []
createEl.enter = ''
createEl.exit = ''
createEl.register = []
createEl.values = {}
// add element enter
var _element_enter = function (el, classid) {
  createEl.enter = el
  var cElm_exits = createEl.$exits.length
  // remove element if has exits
  var i
  for (i = 0;i < cElm_exits; i++) {
    if (isDefine(createEl.$exits[i]) && isDefine(createEl.$exits[i]) && createEl.$exits[i].class === classid) {
      createEl.$exits.splice(i,1)
    }
  }
  // push element enter
  if (!hasObj_Array(createEl.$enter,'class',classid).is) createEl.$enter.push({class:classid,el:el})
}
// add element exits
var element_exit = function (el, classid) {
  createEl.exit = el
  var cElm_enter = createEl.$enter.length
  // remove element if has enter
  var i
  for (i = 0;i < cElm_enter; i++) {
    if (isDefine(createEl.$enter[i]) && isDefine(createEl.$enter[i].class) && createEl.$enter[i].class === classid) {
      createEl.$enter.splice(i,1)
    }
  }
  // push element is exits
  if (!hasObj_Array(createEl.$exits,'class',classid).is) createEl.$exits.push({class:classid,el:el} )
}
var obsclassreg = function (rw) {
  var result
  rgsize = createEl.register.length
  var i
  for (i = 0;i < rgsize; i++) {
    if (createEl.register[i].rawName === rw) result = createEl.register[i].classid
  }
  return result
}
var cssjs = function (css) {
  css = css.split('-')
  var result = css[0] === 'float' ? 'cssFloat' : css[0]
  var size = css.length
  if ( size > 1 ) {
    var i
    for (i = 0; i < size; i++) {
      if (i > 0) result += css[i].charAt(0).toUpperCase() + css[i].substr(1)
    }
  }
  return result
}
// define plugin
var vue_inview = function () {}
// inview handler
var _$eventview = function (arg, classId, callback) {
  var view = inView('.' + classId)
  arg === 'on' ? view.on('enter',callback.enter).on('exit',callback.exit) :
  arg === 'once' ? view.once('enter',callback.enter).once('exit',callback.exit) :
  console.warn('[in-view] event handler not found')
}
// object modifiers
var object_modifiers = function ($m) {
  var convert
  var key
  for (key in $m) {
    if ($m.hasOwnProperty(key) && $m[key] === true) {
      if (isDefine(convert)) convert += '.' + key
      else convert = key
    }
  }
  return convert
}
// validate argument
var $arg = function (arg) {
  var result
  switch (arg) {
    case 'on':
      result = arg
      break
    case 'once':
      result = arg
      break
    case 'class':
      result = arg
      break
    case 'style':
      result = arg
      break
    case 'enter':
      result = arg
      break
    case 'leave':
      result = arg
      break
    default:
      console.warn('[in-view] argument ${arg} undefined')
  }
  return result
}
//default action
var defaultAction = function (bidd, callback) {
  if (!isDefine(bidd.arg)) callback()
  if (bidd.arg === 'on' || bidd.arg === 'once' && objLength(bidd.modifiers) === 0) callback()
}
// add / remove class
var object_class = function (clss, el) {
  if (isString(clss)) el.classList.add(clss)
  if (isObject(clss)) {
    var classArr = el.className.split(' ')
    var key
    for (key in clss) {
      if (classArr.indexOf(key) && clss[key]===false) el.classList.remove(key)
      if (clss.hasOwnProperty(key) && clss[key]===true) el.classList.add(key)
    }
  }
  if (isArray(clss)) {
    var i
    for (i = 0;i < clss.length; i++) {
      el.classList.add(clss[i])
    }
  }
}
// add / remove style
var object_style = function (css,el) {
  var style = el.style
  if (isObject(css)) {
    var key
    for (key in css) {
      if (isDefine(style[cssjs(key)])) style[cssjs(key)] = css[key]
    }
  }
  if (isArray(css)) {
    var size = css.length
    var i
    for (i = 0; i < size; i++){
      if (isDefine(style[cssjs(css[i])])) style[cssjs(css[i])] = ""
    }
  }
}
//element inview
var _$elinview = function (el, $bd) {
  // generate class indetities
  var classId = shortid.generate()
  var elSize = el.classList.length
  // register class element
  el.classList.add(classId)
  createEl.register.push({classid: classId,rawName: $bd.rawName})
  // if directive value not registed
  if (!hasKey(createEl.values, classId) && isDefine($bd.value)) createEl.values[classId] = $bd.value
  // register handler
  var regHdlr = !isDefine($bd.arg) ? 'on' : isDefine($arg($bd.arg)) && $arg($bd.arg) === 'once' ? 'once' : isDefine($arg($bd.arg)) ?
                'on' : 'undefined'
  // object function on enter and exit
  var funcEvent = Object.create(null)
  // default event handler
  defaultAction($bd, function () {
    if (isDefine(createEl.values[classId]) && isFunc(createEl.values[classId])) createEl.values[classId](funcEvent)
  })
  var _$arg = isDefine($arg($bd.arg)) && $arg($bd.arg) !== 'on' || $arg($bd.arg) === 'once' ? $arg($bd.arg) : 'undefined'
  _$eventview(regHdlr,classId,{
    enter: function(el) {
      var elvalue
      // check the value of the directive has been registered
      if(hasKey(createEl.values,classId)) elvalue = createEl.values[classId]
      // for magic properties
      countEntered += 1
      _element_enter(el, classId)
      // end magic properties
      if (_$arg !== 'undefined' && objLength($bd.modifiers) === 0 && isDefine(elvalue)){
          _$arg === 'class' && object_class(elvalue,el)
          _$arg === 'style' && object_style(elvalue,el)
          if (_$arg === 'enter') isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
      }

      if (_$arg === 'on' || _$arg === 'once' && objLength($bd.modifiers) > 0 && isDefine(elvalue)){
        // register modifiers
        var $mdf = object_modifiers($bd.modifiers)
        // modifiers enter
        if ($mdf === 'enter') isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
        // modifiers class
        $mdf === 'class' && object_class(elvalue,el)
        // modifiers style
        $mdf === 'style' && object_style(elvalue,el)
      }

      isDefine(funcEvent.enter) && funcEvent.enter(el)
    },
    exit: function (el) {
      var elvalue
      // check the value of the directive has been registered
      if (hasKey(createEl.values,classId)) elvalue = createEl.values[classId]
      // for magic properties
      countExits += 1
      element_exit(el,classId)
      // end magic properties
      if (_$arg !== 'undefined' && isDefine(elvalue)) {
        if (_$arg === 'leave' && objLength($bd.modifiers)===0) isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
        if (objLength($bd.modifiers) > 0 && object_modifiers($bd.modifiers) === 'leave') {
          _$arg === 'class' && object_class(elvalue,el)
          _$arg === 'style' && object_style(elvalue,el)
        }
      }
      // check if has modifiers
      if (_$arg === 'on' || _$arg === 'once' && objLength($bd.modifiers)>0 && isDefine(elvalue)) {
        // register modifiers
        var $mdf = object_modifiers($bd.modifiers)
        // modifiers leave
        if ($mdf === 'leave') isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
        // leave : class modifiers
        $mdf === 'class.leave' && object_class(elvalue,el)
        // leave : style modifiers
        $mdf === 'style.leave' && object_style(elvalue,el)
      }
      isDefine(funcEvent.exit) && funcEvent.exit(el)
    }
  })
}
// define directive object
var _directObj = {
  inserted: function (el,$bd) {
    _$elinview(el,$bd)
  },
  componentUpdated: function (el,$bd) {
    var elSize = el.classList.length
    var getclass
    // check the class has been registered
    var i
    for (i = 0; i < elSize; i++) {
      if (isDefine(obsclassreg($bd.rawName)) && obsclassreg($bd.rawName)===el.classList[i]) getclass = el.classList[i]
    }
    if (isDefine(getclass) && isDefine($bd.value)) createEl.values[getclass] = $bd.value
  }
}
//has attribute
var hasAtt = function (el, att) {
  var result = false
  if (/^\.[\w]+/.test(att)) {
    var className = att.match(/^\.([\w]+)/)[1]
    var gClass = el.className.split(' ')
    if (gClass.indexOf(className)>-1) {
      result = true
    }
  }
  if (/^\#[\w]+/.test(att)) {
    var idName = att.match(/^\#([\w]+)/)[1]
    if (el.hasAttribute('id') && el.getAttribute('id')===idName) result = true
  }
  if (/^\[[\w]+=\"[\w]+\"\]$/.test(att)) {
    var attr = att.match(/^\[([\w]+)=\"([\w]+)\"\]$/)
    var attName = attr[1]
    var attval = attr[2]
    if (el.hasAttribute(attName) && el.getAttribute(attName)===attval) result = true
  }
  if (/^\[[\w]+=\'[\w]+\'\]$/.test(att)){
    var attr = att.match(/^\[([\w]+)=\'([\w]+)\'\]$/)
    var attName = attr[1]
    var attval = attr[2]
    if (el.hasAttribute(attName) && el.getAttribute(attName)===attval) result = true
  }
  return result
}

//setTimeout
var updateLifeCycle = function (update) {
  var sync = function () {
    update()
    setTimeout(sync,0)
  }
  sync()
}
// define methods inview
var _$inview = function ($arg, $opt) {
  var lastEnter = 0
  var lastExit = 0
  updateLifeCycle(function () {
    if (isDefine($opt) && isObject($opt) && isString($arg)) {
      if (countEntered > lastEnter) {
        isDefine($opt.enter) && hasAtt(createEl.enter,$arg) && $opt.enter(createEl.enter)
        lastEnter = countEntered
      }
      if (countExits > lastExit) {
        isDefine($opt.exit) && hasAtt(createEl.exit,$arg) && $opt.exit(createEl.exit)
        lastExit = countExits
      }
    }
  })
}
// define directive
var _directive = function ($vm) {
  $vm.directive('inview', _directObj)
}
// define methods
var _$methods = function ($vm) {
  $vm.prototype._$inview = _$inview
}
var _install = function (Vue, Option) {
  if (isDefine(Option) && isObject(Option)) inView.offset(Option)
  _directive(Vue)
  _$methods(Vue)
}
vue_inview.install = _install
vue_inview.threshold = function (c) {
  inView.threshold(c)
}
vue_inview.offset = function (c) {
  inView.offset(c)
}
module.exports = vue_inview
<commit_msg>undefine rgsize fix<commit_after>'use strict'
var inView = require('in-view')
var shortid = require('shortid')
var isDefine = function (v) { return typeof v !== 'undefined' },
isString = function (v) { return typeof v === 'string' },
isNumber = function (v) { return typeof v === 'number' },
isFunc   = function (v) { return typeof v === 'function' },
isArray  = function (v) { return Array.isArray(v) },
isObject = function (v) { return !isArray(v) && typeof v === 'object' }
var hasKey = function (obj, src) {
  var result = false
  var key
  for (key in obj) {
    if (obj.hasOwnProperty(key) && key === src) result = true
  }
  return result
}

var objLength = function (v) {
  var result=0
  var key
  for (key in v) {
      v.hasOwnProperty(key) && result++
  }
  return result
}
// check if in object in array has same value
var hasObj_Array = function (v, search, val) {
  const defined = Object.create(null)
  defined.is = false
  defined.count = 0
  var length = v.length
  var i
  for (i = 0; i < length; i++) {
    if (isDefine(v[i]) && isDefine(v[i][search])) {
      if (isDefine(val) && v[i][search] === val) {
        defined.is = true
        defined.count += 1
      }
    }
  }
  return defined
}
var countEntered = 0
var countExits = 0
// create element object
var createEl = Object.create(null)
createEl.$enter = []
createEl.$exits = []
createEl.enter = ''
createEl.exit = ''
createEl.register = []
createEl.values = {}
// add element enter
var _element_enter = function (el, classid) {
  createEl.enter = el
  var cElm_exits = createEl.$exits.length
  // remove element if has exits
  var i
  for (i = 0;i < cElm_exits; i++) {
    if (isDefine(createEl.$exits[i]) && isDefine(createEl.$exits[i]) && createEl.$exits[i].class === classid) {
      createEl.$exits.splice(i,1)
    }
  }
  // push element enter
  if (!hasObj_Array(createEl.$enter,'class',classid).is) createEl.$enter.push({class:classid,el:el})
}
// add element exits
var element_exit = function (el, classid) {
  createEl.exit = el
  var cElm_enter = createEl.$enter.length
  // remove element if has enter
  var i
  for (i = 0;i < cElm_enter; i++) {
    if (isDefine(createEl.$enter[i]) && isDefine(createEl.$enter[i].class) && createEl.$enter[i].class === classid) {
      createEl.$enter.splice(i,1)
    }
  }
  // push element is exits
  if (!hasObj_Array(createEl.$exits,'class',classid).is) createEl.$exits.push({class:classid,el:el} )
}
var obsclassreg = function (rw) {
  var result
  var rgsize = createEl.register.length
  var i
  for (i = 0;i < rgsize; i++) {
    if (createEl.register[i].rawName === rw) result = createEl.register[i].classid
  }
  return result
}
var cssjs = function (css) {
  css = css.split('-')
  var result = css[0] === 'float' ? 'cssFloat' : css[0]
  var size = css.length
  if ( size > 1 ) {
    var i
    for (i = 0; i < size; i++) {
      if (i > 0) result += css[i].charAt(0).toUpperCase() + css[i].substr(1)
    }
  }
  return result
}
// define plugin
var vue_inview = function () {}
// inview handler
var _$eventview = function (arg, classId, callback) {
  var view = inView('.' + classId)
  arg === 'on' ? view.on('enter',callback.enter).on('exit',callback.exit) :
  arg === 'once' ? view.once('enter',callback.enter).once('exit',callback.exit) :
  console.warn('[in-view] event handler not found')
}
// object modifiers
var object_modifiers = function ($m) {
  var convert
  var key
  for (key in $m) {
    if ($m.hasOwnProperty(key) && $m[key] === true) {
      if (isDefine(convert)) convert += '.' + key
      else convert = key
    }
  }
  return convert
}
// validate argument
var $arg = function (arg) {
  var result
  switch (arg) {
    case 'on':
      result = arg
      break
    case 'once':
      result = arg
      break
    case 'class':
      result = arg
      break
    case 'style':
      result = arg
      break
    case 'enter':
      result = arg
      break
    case 'leave':
      result = arg
      break
    default:
      console.warn('[in-view] argument ${arg} undefined')
  }
  return result
}
//default action
var defaultAction = function (bidd, callback) {
  if (!isDefine(bidd.arg)) callback()
  if (bidd.arg === 'on' || bidd.arg === 'once' && objLength(bidd.modifiers) === 0) callback()
}
// add / remove class
var object_class = function (clss, el) {
  if (isString(clss)) el.classList.add(clss)
  if (isObject(clss)) {
    var classArr = el.className.split(' ')
    var key
    for (key in clss) {
      if (classArr.indexOf(key) && clss[key]===false) el.classList.remove(key)
      if (clss.hasOwnProperty(key) && clss[key]===true) el.classList.add(key)
    }
  }
  if (isArray(clss)) {
    var i
    for (i = 0;i < clss.length; i++) {
      el.classList.add(clss[i])
    }
  }
}
// add / remove style
var object_style = function (css,el) {
  var style = el.style
  if (isObject(css)) {
    var key
    for (key in css) {
      if (isDefine(style[cssjs(key)])) style[cssjs(key)] = css[key]
    }
  }
  if (isArray(css)) {
    var size = css.length
    var i
    for (i = 0; i < size; i++){
      if (isDefine(style[cssjs(css[i])])) style[cssjs(css[i])] = ""
    }
  }
}
//element inview
var _$elinview = function (el, $bd) {
  // generate class indetities
  var classId = shortid.generate()
  var elSize = el.classList.length
  // register class element
  el.classList.add(classId)
  createEl.register.push({classid: classId,rawName: $bd.rawName})
  // if directive value not registed
  if (!hasKey(createEl.values, classId) && isDefine($bd.value)) createEl.values[classId] = $bd.value
  // register handler
  var regHdlr = !isDefine($bd.arg) ? 'on' : isDefine($arg($bd.arg)) && $arg($bd.arg) === 'once' ? 'once' : isDefine($arg($bd.arg)) ?
                'on' : 'undefined'
  // object function on enter and exit
  var funcEvent = Object.create(null)
  // default event handler
  defaultAction($bd, function () {
    if (isDefine(createEl.values[classId]) && isFunc(createEl.values[classId])) createEl.values[classId](funcEvent)
  })
  var _$arg = isDefine($arg($bd.arg)) && $arg($bd.arg) !== 'on' || $arg($bd.arg) === 'once' ? $arg($bd.arg) : 'undefined'
  _$eventview(regHdlr,classId,{
    enter: function(el) {
      var elvalue
      // check the value of the directive has been registered
      if(hasKey(createEl.values,classId)) elvalue = createEl.values[classId]
      // for magic properties
      countEntered += 1
      _element_enter(el, classId)
      // end magic properties
      if (_$arg !== 'undefined' && objLength($bd.modifiers) === 0 && isDefine(elvalue)){
          _$arg === 'class' && object_class(elvalue,el)
          _$arg === 'style' && object_style(elvalue,el)
          if (_$arg === 'enter') isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
      }

      if (_$arg === 'on' || _$arg === 'once' && objLength($bd.modifiers) > 0 && isDefine(elvalue)){
        // register modifiers
        var $mdf = object_modifiers($bd.modifiers)
        // modifiers enter
        if ($mdf === 'enter') isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
        // modifiers class
        $mdf === 'class' && object_class(elvalue,el)
        // modifiers style
        $mdf === 'style' && object_style(elvalue,el)
      }

      isDefine(funcEvent.enter) && funcEvent.enter(el)
    },
    exit: function (el) {
      var elvalue
      // check the value of the directive has been registered
      if (hasKey(createEl.values,classId)) elvalue = createEl.values[classId]
      // for magic properties
      countExits += 1
      element_exit(el,classId)
      // end magic properties
      if (_$arg !== 'undefined' && isDefine(elvalue)) {
        if (_$arg === 'leave' && objLength($bd.modifiers)===0) isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
        if (objLength($bd.modifiers) > 0 && object_modifiers($bd.modifiers) === 'leave') {
          _$arg === 'class' && object_class(elvalue,el)
          _$arg === 'style' && object_style(elvalue,el)
        }
      }
      // check if has modifiers
      if (_$arg === 'on' || _$arg === 'once' && objLength($bd.modifiers)>0 && isDefine(elvalue)) {
        // register modifiers
        var $mdf = object_modifiers($bd.modifiers)
        // modifiers leave
        if ($mdf === 'leave') isFunc(elvalue) ? elvalue(el) : console.warn('[in-view:${$bd.expression}] invalid method')
        // leave : class modifiers
        $mdf === 'class.leave' && object_class(elvalue,el)
        // leave : style modifiers
        $mdf === 'style.leave' && object_style(elvalue,el)
      }
      isDefine(funcEvent.exit) && funcEvent.exit(el)
    }
  })
}
// define directive object
var _directObj = {
  inserted: function (el,$bd) {
    _$elinview(el,$bd)
  },
  componentUpdated: function (el,$bd) {
    var elSize = el.classList.length
    var getclass
    // check the class has been registered
    var i
    for (i = 0; i < elSize; i++) {
      if (isDefine(obsclassreg($bd.rawName)) && obsclassreg($bd.rawName)===el.classList[i]) getclass = el.classList[i]
    }
    if (isDefine(getclass) && isDefine($bd.value)) createEl.values[getclass] = $bd.value
  }
}
//has attribute
var hasAtt = function (el, att) {
  var result = false
  if (/^\.[\w]+/.test(att)) {
    var className = att.match(/^\.([\w]+)/)[1]
    var gClass = el.className.split(' ')
    if (gClass.indexOf(className)>-1) {
      result = true
    }
  }
  if (/^\#[\w]+/.test(att)) {
    var idName = att.match(/^\#([\w]+)/)[1]
    if (el.hasAttribute('id') && el.getAttribute('id')===idName) result = true
  }
  if (/^\[[\w]+=\"[\w]+\"\]$/.test(att)) {
    var attr = att.match(/^\[([\w]+)=\"([\w]+)\"\]$/)
    var attName = attr[1]
    var attval = attr[2]
    if (el.hasAttribute(attName) && el.getAttribute(attName)===attval) result = true
  }
  if (/^\[[\w]+=\'[\w]+\'\]$/.test(att)){
    var attr = att.match(/^\[([\w]+)=\'([\w]+)\'\]$/)
    var attName = attr[1]
    var attval = attr[2]
    if (el.hasAttribute(attName) && el.getAttribute(attName)===attval) result = true
  }
  return result
}

//setTimeout
var updateLifeCycle = function (update) {
  var sync = function () {
    update()
    setTimeout(sync,0)
  }
  sync()
}
// define methods inview
var _$inview = function ($arg, $opt) {
  var lastEnter = 0
  var lastExit = 0
  updateLifeCycle(function () {
    if (isDefine($opt) && isObject($opt) && isString($arg)) {
      if (countEntered > lastEnter) {
        isDefine($opt.enter) && hasAtt(createEl.enter,$arg) && $opt.enter(createEl.enter)
        lastEnter = countEntered
      }
      if (countExits > lastExit) {
        isDefine($opt.exit) && hasAtt(createEl.exit,$arg) && $opt.exit(createEl.exit)
        lastExit = countExits
      }
    }
  })
}
// define directive
var _directive = function ($vm) {
  $vm.directive('inview', _directObj)
}
// define methods
var _$methods = function ($vm) {
  $vm.prototype._$inview = _$inview
}
var _install = function (Vue, Option) {
  if (isDefine(Option) && isObject(Option)) inView.offset(Option)
  _directive(Vue)
  _$methods(Vue)
}
vue_inview.install = _install
vue_inview.threshold = function (c) {
  inView.threshold(c)
}
vue_inview.offset = function (c) {
  inView.offset(c)
}
module.exports = vue_inview
<|endoftext|>


<commit_before>#!/usr/bin/env node

var exec = require('child-process').spawn;
exec('luvit')
<commit_msg>cleanup<commit_after><|endoftext|>


<commit_before>load('mongo-fulltext/_load.js');
var s = db.ranking_works;
s.drop();
var full_vector_norm = false;

<<<<<<< HEAD
=======

>>>>>>> b01b3dc4c90059ef524a69bbbe873a360a2759d0
var fixture = [
    { "_id" : 1, "title" : "fish", "content" : "groupers like John Dory" },
    { "_id" : 2, "title" : "dogs", "content" : "whippets kick mongrels" },
    { "_id" : 3, "title" : "dogs & fish", "content" : "whippets kick groupers" }
];
var conf = db.fulltext_config;
conf.insert({'collection_name' : 'ranking_works', 'fields': {'title': 5, 'content': 1}, 'params': {'full_vector_norm': full_vector_norm}});

mft.get('util').load_records_from_list(fixture, 'ranking_works');
var search = mft.get('search');
search.mapReduceIndex('ranking_works');

var result ;

// TODO: add index on collection name (should we have an _id attribute too?)
result = search.mapReduceSearch('ranking_works', 'fish').toArray();

// print(result, "Search result for 'fish'");

assert.eq(result, [
        {
                "_id" : 1,
                "value" : 1.6666666666666667
        },
        {
                "_id" : 3,
                "value" : 1.386750490563073
        }
]);

result = search.mapReduceSearch('ranking_works', 'Dory').toArray();

// print(result, "Search result for 'Dory'");

assert.eq(result, [ { "_id" : 1, "value" : 0.3333333333333333 } ]);
<commit_msg>erroneous merge markers removed<commit_after>load('mongo-fulltext/_load.js');
var s = db.ranking_works;
s.drop();
var full_vector_norm = false;

var fixture = [
    { "_id" : 1, "title" : "fish", "content" : "groupers like John Dory" },
    { "_id" : 2, "title" : "dogs", "content" : "whippets kick mongrels" },
    { "_id" : 3, "title" : "dogs & fish", "content" : "whippets kick groupers" }
];
var conf = db.fulltext_config;
conf.insert({'collection_name' : 'ranking_works', 'fields': {'title': 5, 'content': 1}, 'params': {'full_vector_norm': full_vector_norm}});

mft.get('util').load_records_from_list(fixture, 'ranking_works');
var search = mft.get('search');
search.mapReduceIndex('ranking_works');

var result ;

// TODO: add index on collection name (should we have an _id attribute too?)
result = search.mapReduceSearch('ranking_works', 'fish').toArray();

// print(result, "Search result for 'fish'");

assert.eq(result, [
        {
                "_id" : 1,
                "value" : 1.6666666666666667
        },
        {
                "_id" : 3,
                "value" : 1.386750490563073
        }
]);

result = search.mapReduceSearch('ranking_works', 'Dory').toArray();

// print(result, "Search result for 'Dory'");

assert.eq(result, [ { "_id" : 1, "value" : 0.3333333333333333 } ]);
<|endoftext|>