<commit_before>/**
 * @file Pagging component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import PaggingSize from '../_PaggingSize';
import PaggingPage from '../_PaggingPage';

export default class Pagging extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.pageChangedHandle = ::this.pageChangedHandle;
        this.pageSizeChangedHandle = ::this.pageSizeChangedHandle;

    }

    pageChangedHandle(page) {

        const {pageSize, onChange} = this.props;

        this.props.page != page && onChange && onChange({
            page,
            pageSize
        });

    }

    pageSizeChangedHandle(pageSize) {

        const {page, onChange} = this.props;

        this.props.pageSize != pageSize && onChange && onChange({
            page,
            pageSize
        });

    }

    render() {

        const {
            count, page, total, pageSize, pageSizes,
            selectedCount, selectedCountVisible, pageSizeVisible,
            paggingPrevIconCls, paggingNextIconCls, paggingFirstIconCls, paggingLastIconCls
        } = this.props;

        return (

                    {
                        selectedCountVisible ?

                                {`Selected: ${selectedCount}`}

                            :
                            null
                    }

                        {`Total: ${count}`}

                    {
                        pageSizeVisible ?
                            <PaggingSize pageSize={pageSize}
                                         pageSizes={pageSizes}
                                         onPageSizeChange={this.pageSizeChangedHandle}/>
                            :
                            null
                    }

                    <PaggingPage page={page}
                                 total={total}
                                 paggingPrevIconCls={paggingPrevIconCls}
                                 paggingNextIconCls={paggingNextIconCls}
                                 paggingFirstIconCls={paggingFirstIconCls}
                                 paggingLastIconCls={paggingLastIconCls}
                                 onPageChange={this.pageChangedHandle}/>

        );

    }
};

Pagging.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The total of data.
     */
    count: PropTypes.number,

    /**
     * The valid page.
     */
    page: PropTypes.number,

    /**
     * The page count.
     */
    total: PropTypes.number,

    /**
     * The number of per page.
     */
    pageSize: PropTypes.number,

    /**
     * The array of pageSize.
     */
    pageSizes: PropTypes.array,

    /**
     * The total count of selected.
     */
    selectedCount: PropTypes.number,

    /**
     * If true,the selectedCount will show.
     */
    selectedCountVisible: PropTypes.bool,

    /**
     * If false, the pageSize choice box will not show.
     */
    pageSizeVisible: PropTypes.bool,

    /**
     * Use this property to set prev button icon.
     */
    paggingPrevIconCls: PropTypes.string,

    /**
     * Use this property to set next button icon.
     */
    paggingNextIconCls: PropTypes.string,

    /**
     * Use this property to set first button icon.
     */
    paggingFirstIconCls: PropTypes.string,

    /**
     * Use this property to set last button icon.
     */
    paggingLastIconCls: PropTypes.string,

    /**
     * Callback function fired when Pagging component change.
     */
    onChange: PropTypes.func

};

Pagging.defaultProps = {

    className: '',
    style: null,

    count: 0,
    page: 0,
    total: 0,
    pageSize: 10,
    pageSizes: [5, 10, 15, 20],
    selectedCount: 0,

    selectedCountVisible: false,
    pageSizeVisible: true,

    paggingPrevIconCls: 'fa fa-angle-left',
    paggingNextIconCls: 'fa fa-angle-right',
    paggingFirstIconCls: 'fa fa-angle-double-left',
    paggingLastIconCls: 'fa fa-angle-double-right'

};<commit_msg>update Pagging<commit_after>/**
 * @file Pagging component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import PaggingSize from '../_PaggingSize';
import PaggingPage from '../_PaggingPage';

class Pagging extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.pageChangedHandle = ::this.pageChangedHandle;
        this.pageSizeChangedHandle = ::this.pageSizeChangedHandle;

    }

    pageChangedHandle(page) {

        const {pageSize, onChange} = this.props;

        this.props.page != page && onChange && onChange({
            page,
            pageSize
        });

    }

    pageSizeChangedHandle(pageSize) {

        const {page, onChange} = this.props;

        this.props.pageSize != pageSize && onChange && onChange({
            page,
            pageSize
        });

    }

    render() {

        const {
            count, page, total, pageSize, pageSizes,
            selectedCount, selectedCountVisible, pageSizeVisible,
            paggingPrevIconCls, paggingNextIconCls, paggingFirstIconCls, paggingLastIconCls
        } = this.props;

        return (

                    {
                        selectedCountVisible ?

                                {`Selected: ${selectedCount}`}

                            :
                            null
                    }

                        {`Total: ${count}`}

                    {
                        pageSizeVisible ?
                            <PaggingSize pageSize={pageSize}
                                         pageSizes={pageSizes}
                                         onPageSizeChange={this.pageSizeChangedHandle}/>
                            :
                            null
                    }

                    <PaggingPage page={page}
                                 total={total}
                                 paggingPrevIconCls={paggingPrevIconCls}
                                 paggingNextIconCls={paggingNextIconCls}
                                 paggingFirstIconCls={paggingFirstIconCls}
                                 paggingLastIconCls={paggingLastIconCls}
                                 onPageChange={this.pageChangedHandle}/>

        );

    }
};

Pagging.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The total of data.
     */
    count: PropTypes.number,

    /**
     * The valid page.
     */
    page: PropTypes.number,

    /**
     * The page count.
     */
    total: PropTypes.number,

    /**
     * The number of per page.
     */
    pageSize: PropTypes.number,

    /**
     * The array of pageSize.
     */
    pageSizes: PropTypes.array,

    /**
     * The total count of selected.
     */
    selectedCount: PropTypes.number,

    /**
     * If true,the selectedCount will show.
     */
    selectedCountVisible: PropTypes.bool,

    /**
     * If false, the pageSize choice box will not show.
     */
    pageSizeVisible: PropTypes.bool,

    /**
     * Use this property to set prev button icon.
     */
    paggingPrevIconCls: PropTypes.string,

    /**
     * Use this property to set next button icon.
     */
    paggingNextIconCls: PropTypes.string,

    /**
     * Use this property to set first button icon.
     */
    paggingFirstIconCls: PropTypes.string,

    /**
     * Use this property to set last button icon.
     */
    paggingLastIconCls: PropTypes.string,

    /**
     * Callback function fired when Pagging component change.
     */
    onChange: PropTypes.func

};

Pagging.defaultProps = {

    className: '',
    style: null,

    count: 0,
    page: 0,
    total: 0,
    pageSize: 10,
    pageSizes: [5, 10, 15, 20],
    selectedCount: 0,

    selectedCountVisible: false,
    pageSizeVisible: true,

    paggingPrevIconCls: 'fa fa-angle-left',
    paggingNextIconCls: 'fa fa-angle-right',
    paggingFirstIconCls: 'fa fa-angle-double-left',
    paggingLastIconCls: 'fa fa-angle-double-right'

};

export default Pagging;<|endoftext|>


<commit_before>// Mithril component which embeds four iframes with HTML videos

const MyComponent = {
    view(controller, args) {
        return m("div.ba.ma3.pa3.bg-light-purple", [
            // Passengers 2016 - Starship Avalon Slingshot Around The Red Giant Star Arcturus
            m("iframe", {src: "//www.youtube.com/embed/1jGRpuzrkpk", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),
            // Alan Kay at OOPSLA 1997 - The computer revolution hasn't happened yet
            m("iframe", {src: "//www.youtube.com/embed/oKg1hTOQXoY", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),
            // The Mother of All Demos, presented by Douglas Engelbart (1968)
            m("iframe", {src: "//www.youtube.com/embed/yJDv-zdhzMY", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),
            // Twirlip Civic Sensemaking Project Overview
            m("iframe", {src: "//www.youtube.com/embed/_mRy4sGK7xk", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),
        ])
    }
}

Twirlip7.show(MyComponent, { title: "Videos on the future, the present, and the past" } )
<commit_msg>Replace a video in example because previous one disappeared<commit_after>// Mithril component which embeds four iframes with HTML videos

const MyComponent = {
    view(controller, args) {
        return m("div.ba.ma3.pa3.bg-light-purple", [
            // The Mother of All Demos, presented by Douglas Engelbart (1968)
            m("iframe", {src: "//www.youtube.com/embed/yJDv-zdhzMY", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),

            // Alan Kay at OOPSLA 1997 - The computer revolution hasn't happened yet
            m("iframe", {src: "//www.youtube.com/embed/oKg1hTOQXoY", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),

            // The Lively Kernel presented by Dan Ingalls aa a Google Tech Talks  (2008)
            m("iframe", {src: "//www.youtube.com/embed/gGw09RZjQf8", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),

            // Twirlip Civic Sensemaking Project Overview (2011)
            m("iframe", {src: "//www.youtube.com/embed/_mRy4sGK7xk", width: 800, height: 600, frameborder: "0", allowfullscreen: true}),
        ])
    }
}

Twirlip7.show(MyComponent, { title: "Videos on the future, the present, and the past" } )
<|endoftext|>


<commit_before>define(function(require) {
    var Require = require('./Require');

    /**
     * @ngInject
     */
    function RequireProvider() {
        this.config = {
            directives: {},
            services: {},
            factories: {},
            values: {},
            filters: {}
        };

        // These are set in the config phase
        this.$compileProvider = null;
        this.$controllerProvider = null;
        this.$filterProvider = null;
        this.$provide = null;
    }

    RequireProvider.prototype.mergeConfig = function(config, base) {
        this.mergeDirectivesConfig_(config['directives'], base);
        this.mergeFiltersConfig_(config['filters'], base);

        this.mergeServicesConfig_('values', config, base);
        this.mergeServicesConfig_('services', config, base);
        this.mergeServicesConfig_('factories', config, base);
    };

    RequireProvider.prototype.normalizeConfig_ = function(config) {
        var normalizedConfig = {};

        if (Array.isArray(config)) {
            config.forEach(function(name) {
                normalizedConfig[name] = true;
            });
        } else {
            normalizedConfig = config || {};
        }

        return normalizedConfig;
    };

    /**
     * {
     *   "filters": ["one", "two"]
     * }
     *
     * is shorthand for
     *
     * {
     *   "filters": {
     *     "one": true,
     *     "two": true
     *   }
     * }
     *
     * is shorthand for
     *
     * {
     *   "filters": {
     *     "one": "{{base}}/filters/one",
     *     "two": "{{base}}/filters/two"
     *   }
     * }
     */
    RequireProvider.prototype.mergeFiltersConfig_ = function(config, base) {
        var filtersConfig = this.normalizeConfig_(config);

        Object.keys(filtersConfig).forEach(function(name) {
            var module = filtersConfig[name];
            if (module === true) {
                module = base + '/filters/' + name;
            }

            this.config['filters'][name] = module;
        }.bind(this));
    };

    /**
     *
     * @param {Object} config
     *
     * {
     *   "directives": ["one", "two"]
     * }
     *
     * is shorthand for
     *
     * {
     *   "directives": {
     *     "one": true,
     *     "two": true
     *   }
     * }
     *
     * is shorthand for
     *
     * {
     *   "directives": {
     *     "one": "{{base}}/directives/one/directive",
     *     "two": "{{base}}/directives/two/directive"
     *   }
     * }
     *
     * @param {string} base An AMD namespace for the default modules.
     *
     */
    RequireProvider.prototype.mergeDirectivesConfig_ = function(config, base) {
        var directivesConfig = this.normalizeConfig_(config);

        Object.keys(directivesConfig).forEach(function(name) {
            var module = directivesConfig[name];
            if (module === true) {
                module = base + '/directives/' + name + '/directive';
            }

            this.config['directives'][name] = module;
        }.bind(this));
    };

    /**
     * @param {string} type "services," "factories," or "values"
     * @param {Object} config
     *
     * {
     *   "services": ["serviceName"],
     *   "factories": ["serviceName"],
     *   "values": ["serviceName"]
     * }
     *
     * is shorthand for
     *
     * {
     *   "services": { "serviceName": true },
     *   "factories": { "serviceName": true },
     *   "values": { "serviceName": true }
     * }
     *
     * is shorthand for
     *
     * {
     *   "services": { "serviceName": "{{base}}/services/ServiceName" },
     *   "factories": { "serviceName": "{{base}}/factories/serviceName" },
     *   "values": { "serviceName": "{{base}}/values/serviceName" }
     * }
     *
     * NB: The "services" option capitalizes ServiceName, since it is meant
     *     to be a constructor function (i.e. a class).
     *
     * NB: Providers and constants are not supported for lazy-loading. Register
     *     those in the traditional, synchronous way.
     *
     * @param {string} base An AMD namespace for the default modules
     */
    RequireProvider.prototype.mergeServicesConfig_ = function(type, config, base) {
        var servicesConfig = this.normalizeConfig_(config[type]);

        Object.keys(servicesConfig).forEach(function(name) {
            this.config['values'][name] = false;
            this.config['services'][name] = false;
            this.config['factories'][name] = false;

            if (type === 'services') {
                name = name.charAt(0).toUpperCase() + name.slice(1);
            }

            var module = servicesConfig[name];
            if (module === true) {
                module = base + '/' + type + '/' + name;
            }

            this.config[type][name] = module;
        }.bind(this));
    };

    /**
     * @ngInject
     */
    RequireProvider.prototype.$get = function($q, $injector) {
        return new Require(this.config, $q, $injector, this.$compileProvider,
            this.$controllerProvider, this.$filterProvider, this.$provide);
    };

    return RequireProvider;
});
<commit_msg>fix(services): lazy-loading via services/ServiceName works again<commit_after>define(function(require) {
    var Require = require('./Require');

    /**
     * @ngInject
     */
    function RequireProvider() {
        this.config = {
            directives: {},
            services: {},
            factories: {},
            values: {},
            filters: {}
        };

        // These are set in the config phase
        this.$compileProvider = null;
        this.$controllerProvider = null;
        this.$filterProvider = null;
        this.$provide = null;
    }

    RequireProvider.prototype.mergeConfig = function(config, base) {
        this.mergeDirectivesConfig_(config['directives'], base);
        this.mergeFiltersConfig_(config['filters'], base);

        this.mergeServicesConfig_('values', config, base);
        this.mergeServicesConfig_('services', config, base);
        this.mergeServicesConfig_('factories', config, base);
    };

    RequireProvider.prototype.normalizeConfig_ = function(config) {
        var normalizedConfig = {};

        if (Array.isArray(config)) {
            config.forEach(function(name) {
                normalizedConfig[name] = true;
            });
        } else {
            normalizedConfig = config || {};
        }

        return normalizedConfig;
    };

    /**
     * {
     *   "filters": ["one", "two"]
     * }
     *
     * is shorthand for
     *
     * {
     *   "filters": {
     *     "one": true,
     *     "two": true
     *   }
     * }
     *
     * is shorthand for
     *
     * {
     *   "filters": {
     *     "one": "{{base}}/filters/one",
     *     "two": "{{base}}/filters/two"
     *   }
     * }
     */
    RequireProvider.prototype.mergeFiltersConfig_ = function(config, base) {
        var filtersConfig = this.normalizeConfig_(config);

        Object.keys(filtersConfig).forEach(function(name) {
            var module = filtersConfig[name];
            if (module === true) {
                module = base + '/filters/' + name;
            }

            this.config['filters'][name] = module;
        }.bind(this));
    };

    /**
     *
     * @param {Object} config
     *
     * {
     *   "directives": ["one", "two"]
     * }
     *
     * is shorthand for
     *
     * {
     *   "directives": {
     *     "one": true,
     *     "two": true
     *   }
     * }
     *
     * is shorthand for
     *
     * {
     *   "directives": {
     *     "one": "{{base}}/directives/one/directive",
     *     "two": "{{base}}/directives/two/directive"
     *   }
     * }
     *
     * @param {string} base An AMD namespace for the default modules.
     *
     */
    RequireProvider.prototype.mergeDirectivesConfig_ = function(config, base) {
        var directivesConfig = this.normalizeConfig_(config);

        Object.keys(directivesConfig).forEach(function(name) {
            var module = directivesConfig[name];
            if (module === true) {
                module = base + '/directives/' + name + '/directive';
            }

            this.config['directives'][name] = module;
        }.bind(this));
    };

    /**
     * @param {string} type "services," "factories," or "values"
     * @param {Object} config
     *
     * {
     *   "services": ["serviceName"],
     *   "factories": ["serviceName"],
     *   "values": ["serviceName"]
     * }
     *
     * is shorthand for
     *
     * {
     *   "services": { "serviceName": true },
     *   "factories": { "serviceName": true },
     *   "values": { "serviceName": true }
     * }
     *
     * is shorthand for
     *
     * {
     *   "services": { "serviceName": "{{base}}/services/ServiceName" },
     *   "factories": { "serviceName": "{{base}}/factories/serviceName" },
     *   "values": { "serviceName": "{{base}}/values/serviceName" }
     * }
     *
     * NB: The "services" option capitalizes ServiceName, since it is meant
     *     to be a constructor function (i.e. a class).
     *
     * NB: Providers and constants are not supported for lazy-loading. Register
     *     those in the traditional, synchronous way.
     *
     * @param {string} base An AMD namespace for the default modules
     */
    RequireProvider.prototype.mergeServicesConfig_ = function(type, config, base) {
        var servicesConfig = this.normalizeConfig_(config[type]);

        Object.keys(servicesConfig).forEach(function(name) {
            this.config['values'][name] = false;
            this.config['services'][name] = false;
            this.config['factories'][name] = false;

            // Capitalize service names ('someService' => 'SomeService')
            var moduleName = type !== 'services' ? name :
                name.charAt(0).toUpperCase() + name.slice(1)

            var module = servicesConfig[name];
            if (module === true) {
                module = base + '/' + type + '/' + moduleName;
            }

            this.config[type][name] = module;
        }.bind(this));
    };

    /**
     * @ngInject
     */
    RequireProvider.prototype.$get = function($q, $injector) {
        return new Require(this.config, $q, $injector, this.$compileProvider,
            this.$controllerProvider, this.$filterProvider, this.$provide);
    };

    return RequireProvider;
});
<|endoftext|>


<commit_before>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Listens for incoming postMessage requests from the integrations UI URL. The following API is exposed:
{
    action: "invite" | "membership_state" | "bot_options" | "set_bot_options",
    room_id: $ROOM_ID,
    user_id: $USER_ID
    // additional request fields
}

The complete request object is returned to the caller with an additional "response" key like so:
{
    action: "invite" | "membership_state" | "bot_options" | "set_bot_options",
    room_id: $ROOM_ID,
    user_id: $USER_ID,
    // additional request fields
    response: { ... }
}

The "action" determines the format of the request and response. All actions can return an error response.
An error response is a "response" object which consists of a sole "error" key to indicate an error.
They look like:
{
    error: {
        message: "Unable to invite user into room.",
        _error: <Original Error Object>
    }
}
The "message" key should be a human-friendly string.

ACTIONS
=======
All actions can return an error response instead of the response outlined below.

invite
------
Invites a user into a room.

Request:
 - room_id is the room to invite the user into.
 - user_id is the user ID to invite.
 - No additional fields.
Response:
{
    success: true
}
Example:
{
    action: "invite",
    room_id: "!foo:bar",
    user_id: "@invitee:bar",
    response: {
        success: true
    }
}

set_bot_options
---------------
Set the m.room.bot.options state event for a bot user.

Request:
 - room_id is the room to send the state event into.
 - user_id is the user ID of the bot who you're setting options for.
 - "content" is an object consisting of the content you wish to set.
Response:
{
    success: true
}
Example:
{
    action: "set_bot_options",
    room_id: "!foo:bar",
    user_id: "@bot:bar",
    content: {
        default_option: "alpha"
    },
    response: {
        success: true
    }
}

membership_state AND bot_options
--------------------------------
Get the content of the "m.room.member" or "m.room.bot.options" state event respectively.

NB: Whilst this API is basically equivalent to getStateEvent, we specifically do not
    want external entities to be able to query any state event for any room, hence the
    restrictive API outlined here.

Request:
 - room_id is the room which has the state event.
 - user_id is the state_key parameter which in both cases is a user ID (the member or the bot).
 - No additional fields.
Response:
 - The event content. If there is no state event, the "response" key should be null.
Example:
{
    action: "membership_state",
    room_id: "!foo:bar",
    user_id: "@somemember:bar",
    response: {
        membership: "join",
        displayname: "Bob",
        avatar_url: null
    }
}
*/

const SdkConfig = require('./SdkConfig');
const MatrixClientPeg = require("./MatrixClientPeg");
var dis = require("./dispatcher");

function sendResponse(event, res) {
    const data = JSON.parse(JSON.stringify(event.data));
    data.response = res;
    event.source.postMessage(data, event.origin);
}

function sendError(event, msg, nestedError) {
    console.error("Action:" + event.data.action + " failed with message: " + msg);
    const data = JSON.parse(JSON.stringify(event.data));
    data.response = {
        error: {
            message: msg,
        },
    };
    if (nestedError) {
        data.response.error._error = nestedError;
    }
    event.source.postMessage(data, event.origin);
}

function inviteUser(event, roomId, userId) {
    console.log(`Received request to invite ${userId} into room ${roomId}`);
    const client = MatrixClientPeg.get();
    if (!client) {
        sendError(event, "You need to be logged in.");
        return;
    }
    const room = client.getRoom(roomId);
    if (room) {
        // if they are already invited we can resolve immediately.
        const member = room.getMember(userId);
        if (member && member.membership === "invite") {
            sendResponse(event, {
                success: true,
            });
            return;
        }
    }

    client.invite(roomId, userId).done(function() {
        sendResponse(event, {
            success: true,
        });
    }, function(err) {
        sendError(event, "You need to be able to invite users to do that.", err);
    });
}

function setBotOptions(event, roomId, userId) {
    console.log(`Received request to set options for bot ${userId} in room ${roomId}`);
    const client = MatrixClientPeg.get();
    if (!client) {
        sendError(event, "You need to be logged in.");
        return;
    }
    client.sendStateEvent(roomId, "m.room.bot.options", event.data.content, "_" + userId).done(() => {
        sendResponse(event, {
            success: true,
        });
    }, (err) => {
        sendError(event, err.message ? err.message : "Failed to send request.", err);
    });
}

function getMembershipState(event, roomId, userId) {
    console.log(`membership_state of ${userId} in room ${roomId} requested.`);
    returnStateEvent(event, roomId, "m.room.member", userId);
}

function getJoinRules(event, roomId) {
    console.log(`join_rules of ${roomId} requested.`);
    returnStateEvent(event, roomId, "m.room.join_rules");
}

function botOptions(event, roomId, userId) {
    console.log(`bot_options of ${userId} in room ${roomId} requested.`);
    returnStateEvent(event, roomId, "m.room.bot.options", "_" + userId);
}

function returnStateEvent(event, roomId, eventType, stateKey) {
    const client = MatrixClientPeg.get();
    if (!client) {
        sendError(event, "You need to be logged in.");
        return;
    }
    const room = client.getRoom(roomId);
    if (!room) {
        sendError(event, "This room is not recognised.");
        return;
    }
    const stateEvent = room.currentState.getStateEvents(eventType, stateKey);
    if (!stateEvent) {
        sendResponse(event, null);
        return;
    }
    sendResponse(event, stateEvent.getContent());
}

var currentRoomId = null;

// Listen for when a room is viewed
dis.register(onAction);
function onAction(payload) {
    switch (payload.action) {
        case 'view_room':
            currentRoomId = payload.room_id;
        break;
    }
}

const onMessage = function(event) {
    if (!event.origin) { // stupid chrome
        event.origin = event.originalEvent.origin;
    }

    // check it is from the integrations UI URL (remove trailing spaces)
    let url = SdkConfig.get().integrations_ui_url;
    if (url.endsWith("/")) {
        url = url.substr(0, url.length - 1);
    }
    if (url !== event.origin) {
        console.warn("Unauthorised postMessage received. Source URL: " + event.origin);
        return;
    }

    const roomId = event.data.room_id;
    const userId = event.data.user_id;
    if (!userId) {
        sendError(event, "Missing user_id in request");
        return;
    }
    if (!roomId) {
        sendError(event, "Missing room_id in request");
        return;
    }
    if (!currentRoomId) {
        sendError(event, "Must be viewing a room");
        return;
    }
    if (roomId !== currentRoomId) {
        sendError(event, "Room " + roomId + " not in view");
        return;
    }

    switch (event.data.action) {
        case "membership_state":
            getMembershipState(event, roomId, userId);
            break;
        case "invite":
            inviteUser(event, roomId, userId);
            break;
        case "bot_options":
            botOptions(event, roomId, userId);
            break;
        case "set_bot_options":
            setBotOptions(event, roomId, userId);
            break;
        case "join_rules_state":
            getJoinRules(event, roomId);
            break;
        default:
            console.warn("Unhandled postMessage event with action '" + event.data.action +"'");
            break;
    }
};

module.exports = {
    startListening: function() {
        window.addEventListener("message", onMessage, false);
    },

    stopListening: function() {
        window.removeEventListener("message", onMessage);
    },
};
<commit_msg>Code review<commit_after>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Listens for incoming postMessage requests from the integrations UI URL. The following API is exposed:
{
    action: "invite" | "membership_state" | "bot_options" | "set_bot_options",
    room_id: $ROOM_ID,
    user_id: $USER_ID
    // additional request fields
}

The complete request object is returned to the caller with an additional "response" key like so:
{
    action: "invite" | "membership_state" | "bot_options" | "set_bot_options",
    room_id: $ROOM_ID,
    user_id: $USER_ID,
    // additional request fields
    response: { ... }
}

The "action" determines the format of the request and response. All actions can return an error response.
An error response is a "response" object which consists of a sole "error" key to indicate an error.
They look like:
{
    error: {
        message: "Unable to invite user into room.",
        _error: <Original Error Object>
    }
}
The "message" key should be a human-friendly string.

ACTIONS
=======
All actions can return an error response instead of the response outlined below.

invite
------
Invites a user into a room.

Request:
 - room_id is the room to invite the user into.
 - user_id is the user ID to invite.
 - No additional fields.
Response:
{
    success: true
}
Example:
{
    action: "invite",
    room_id: "!foo:bar",
    user_id: "@invitee:bar",
    response: {
        success: true
    }
}

set_bot_options
---------------
Set the m.room.bot.options state event for a bot user.

Request:
 - room_id is the room to send the state event into.
 - user_id is the user ID of the bot who you're setting options for.
 - "content" is an object consisting of the content you wish to set.
Response:
{
    success: true
}
Example:
{
    action: "set_bot_options",
    room_id: "!foo:bar",
    user_id: "@bot:bar",
    content: {
        default_option: "alpha"
    },
    response: {
        success: true
    }
}

membership_state AND bot_options
--------------------------------
Get the content of the "m.room.member" or "m.room.bot.options" state event respectively.

NB: Whilst this API is basically equivalent to getStateEvent, we specifically do not
    want external entities to be able to query any state event for any room, hence the
    restrictive API outlined here.

Request:
 - room_id is the room which has the state event.
 - user_id is the state_key parameter which in both cases is a user ID (the member or the bot).
 - No additional fields.
Response:
 - The event content. If there is no state event, the "response" key should be null.
Example:
{
    action: "membership_state",
    room_id: "!foo:bar",
    user_id: "@somemember:bar",
    response: {
        membership: "join",
        displayname: "Bob",
        avatar_url: null
    }
}
*/

const SdkConfig = require('./SdkConfig');
const MatrixClientPeg = require("./MatrixClientPeg");
var dis = require("./dispatcher");

function sendResponse(event, res) {
    const data = JSON.parse(JSON.stringify(event.data));
    data.response = res;
    event.source.postMessage(data, event.origin);
}

function sendError(event, msg, nestedError) {
    console.error("Action:" + event.data.action + " failed with message: " + msg);
    const data = JSON.parse(JSON.stringify(event.data));
    data.response = {
        error: {
            message: msg,
        },
    };
    if (nestedError) {
        data.response.error._error = nestedError;
    }
    event.source.postMessage(data, event.origin);
}

function inviteUser(event, roomId, userId) {
    console.log(`Received request to invite ${userId} into room ${roomId}`);
    const client = MatrixClientPeg.get();
    if (!client) {
        sendError(event, "You need to be logged in.");
        return;
    }
    const room = client.getRoom(roomId);
    if (room) {
        // if they are already invited we can resolve immediately.
        const member = room.getMember(userId);
        if (member && member.membership === "invite") {
            sendResponse(event, {
                success: true,
            });
            return;
        }
    }

    client.invite(roomId, userId).done(function() {
        sendResponse(event, {
            success: true,
        });
    }, function(err) {
        sendError(event, "You need to be able to invite users to do that.", err);
    });
}

function setBotOptions(event, roomId, userId) {
    console.log(`Received request to set options for bot ${userId} in room ${roomId}`);
    const client = MatrixClientPeg.get();
    if (!client) {
        sendError(event, "You need to be logged in.");
        return;
    }
    client.sendStateEvent(roomId, "m.room.bot.options", event.data.content, "_" + userId).done(() => {
        sendResponse(event, {
            success: true,
        });
    }, (err) => {
        sendError(event, err.message ? err.message : "Failed to send request.", err);
    });
}

function getMembershipState(event, roomId, userId) {
    console.log(`membership_state of ${userId} in room ${roomId} requested.`);
    returnStateEvent(event, roomId, "m.room.member", userId);
}

function getJoinRules(event, roomId) {
    console.log(`join_rules of ${roomId} requested.`);
    returnStateEvent(event, roomId, "m.room.join_rules", "");
}

function botOptions(event, roomId, userId) {
    console.log(`bot_options of ${userId} in room ${roomId} requested.`);
    returnStateEvent(event, roomId, "m.room.bot.options", "_" + userId);
}

function returnStateEvent(event, roomId, eventType, stateKey) {
    const client = MatrixClientPeg.get();
    if (!client) {
        sendError(event, "You need to be logged in.");
        return;
    }
    const room = client.getRoom(roomId);
    if (!room) {
        sendError(event, "This room is not recognised.");
        return;
    }
    const stateEvent = room.currentState.getStateEvents(eventType, stateKey);
    if (!stateEvent) {
        sendResponse(event, null);
        return;
    }
    sendResponse(event, stateEvent.getContent());
}

var currentRoomId = null;

// Listen for when a room is viewed
dis.register(onAction);
function onAction(payload) {
    if (payload.action !== "view_room")
        return;
    }
    currentRoomId = payload.room_id;
}

const onMessage = function(event) {
    if (!event.origin) { // stupid chrome
        event.origin = event.originalEvent.origin;
    }

    // check it is from the integrations UI URL (remove trailing spaces)
    let url = SdkConfig.get().integrations_ui_url;
    if (url.endsWith("/")) {
        url = url.substr(0, url.length - 1);
    }
    if (url !== event.origin) {
        console.warn("Unauthorised postMessage received. Source URL: " + event.origin);
        return;
    }

    const roomId = event.data.room_id;
    const userId = event.data.user_id;
    if (!userId) {
        sendError(event, "Missing user_id in request");
        return;
    }
    if (!roomId) {
        sendError(event, "Missing room_id in request");
        return;
    }
    if (!currentRoomId) {
        sendError(event, "Must be viewing a room");
        return;
    }
    if (roomId !== currentRoomId) {
        sendError(event, "Room " + roomId + " not visible");
        return;
    }

    switch (event.data.action) {
        case "membership_state":
            getMembershipState(event, roomId, userId);
            break;
        case "invite":
            inviteUser(event, roomId, userId);
            break;
        case "bot_options":
            botOptions(event, roomId, userId);
            break;
        case "set_bot_options":
            setBotOptions(event, roomId, userId);
            break;
        case "join_rules_state":
            getJoinRules(event, roomId);
            break;
        default:
            console.warn("Unhandled postMessage event with action '" + event.data.action +"'");
            break;
    }
};

module.exports = {
    startListening: function() {
        window.addEventListener("message", onMessage, false);
    },

    stopListening: function() {
        window.removeEventListener("message", onMessage);
    },
};
<|endoftext|>


<commit_before>(function (canvas) {
    /* Init some variables */
    var w = canvas.width;
    var h = canvas.height;
    var ctx = canvas.getContext("2d");
    var keysDown = {};
    var characters, treasure, boat, player, score, gameOver, level;

    /* Keyboard handling */
    addEventListener("keydown", function (e) {
        keysDown[e.keyCode] = true;
    }, false);
    addEventListener("keyup", function (e) {
        delete keysDown[e.keyCode];
    }, false);
    //prevent arrow key scrolling
    window.addEventListener("keydown", function(e) {
        // arrow keys
        if([37, 38, 39, 40].indexOf(e.keyCode) > -1) {
        e.preventDefault();
        }
    }, false);

    /* Base objects */
    var Rect = function(x, y, w, h)
    {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    };
    var Character = function (x, y, moveSpeed, sprite, collisionBox, isPlayer) {
        this.posX = x || 0;
        this.posY = y || 0;
        this.moveSpeed = moveSpeed || 0;
        this.sprite = sprite || null;
        this.collisionBox = collisionBox || null;
        this.isPlayer = isPlayer || false;
    };
    Character.prototype.move = function (deltaX, deltaY) {
        this.posX = (this.posX + deltaX + w) % w;
        targetY = this.posY + deltaY;
        if (targetY > h * 0.2 && targetY < h * 0.9 - 16) {
            this.posY = targetY;
        }
    };
    var Item = function(x, y, sprite) {
        this.posX = x || 0;
        this.posY = y || 0;
        this.visible = true;
        this.sprite = sprite || null;
    };

    /* Movement handlers */
    var octoMove = function(timePassed) {
        this.move(this.moveSpeed * this.dir * timePassed * 100, 0);
        if (collisionCheck(player, this)) {
            gameOver = true;
        }
    };
    var playerMove = function(timePassed) {
        if (38 in keysDown) { // up
            this.move(0, -this.moveSpeed * timePassed * 100);
        }
        if (40 in keysDown) { // down
            this.move(0, this.moveSpeed * timePassed * 100);
        }
        if (39 in keysDown) { // right
            this.dir = 1;
        }
        if (37 in keysDown) { // left
            this.dir = -1;
        }
    };

    /* Init rects */
    var sprites = {
        diver: new Rect(0,0,31,31),
        octo: new Rect(0,32,32,32),
        boat: new Rect(0,64,32,32),
        treasure: new Rect(0,96,32,32),
    };
    var collisionBoxes = {
        diver: new Rect(2,6,26,6),
        octo: new Rect(6,2,16,20),
    };

    /*collision detection (Axis-Aligned Bounding Boxes)*/
    var collisionCheck = function (item1, item2) {
        var box1 = item1.collisionBox;
        var box2 = item2.collisionBox;
        var x1 = box1.x + item1.posX - item1.sprite.w / 2;
        var y1 = box1.y + item1.posY;
        var x2 = box2.x + item2.posX - item2.sprite.w / 2;
        var y2 = box2.y + item2.posY;
        return (x1 < x2 + box2.w &&
                x1 + box1.w > x2 &&
                y1 < y2 + box2.h &&
                box1.h + y1 > y2);
    };

    /* Drawing helpers */
    var drawSprite = function(ctx, sprite, x, y) {
       var sprites = document.getElementById("sprites");
       ctx.drawImage(sprites, sprite.x, sprite.y, sprite.w, sprite.h, x, y, sprite.w, sprite.h);
    };
    var drawGameOver = function(ctx) {
        ctx.font = "100px monospace";
        ctx.fillStyle = "white";
        ctx.fillText("GAME OVER", 130, h / 2);
    };

    /* Main init, runs once */
    var initGame = function () {
        characters = [];
        treasure = new Item(w / 2, h * 0.9, sprites.treasure);
        boat = new Item(w / 2, h * 0.2, sprites.boat);
        score = 0;
        gameOver = false;
        level = 1;
    };

    /* Level init, runs each level. */
    var initLevel = function(level) {
        characters = [];
        treasure.visible = true;
        player = new Character(w / 2, h * 0.2, 1, sprites.diver, collisionBoxes.diver, true);
        player.treasureCount = 0;
        player.update = playerMove;
        characters.push(player);
        // More octopuses each level
        for (var i = 0; i <= level * 2; i++) {
            // Can get faster each level, randomized for varied speeds.
            var speed = 1 + Math.random() * (level * 0.15);
            var octopus = new Character(Math.random() * w, Math.random() *  h * 0.6 + (h * 0.25), speed, sprites.octo, collisionBoxes.octo);
            octopus.dir = Math.random()<0.5 ? 1 : -1;
            octopus.update = octoMove;
            characters.push(octopus);
        }
    };

    /* Update game state */
    var update = function (timePassed) {
        characters.forEach(function(character) {
            character.update(timePassed);
        });

        if (treasure.visible && player.posY > 518) {
            player.treasureCount += 1;
            treasure.visible = false; //just hide it off screen
        }
        if (player.treasureCount > 0 && player.posY < 121) {
            score += player.treasureCount * 1000 * level;
            player.treasureCount = 0;
            level += 1;
            initLevel(level);
        }
    };

    /* Draw graphics to canvas */
    var draw = function() {
        //prepare graphics
        //draw background
        // sky
        ctx.fillStyle = "#0000dd";
        ctx.fillRect(0, 0, w, h);
        // water
        ctx.fillStyle = "#222255";
        ctx.fillRect(0, h * 0.2, w, h * 0.7);
        // sand
        ctx.fillStyle = "#442200";
        ctx.fillRect(0, h * 0.9, w, h * 0.1);
        //draw boat
        drawSprite(ctx, boat.sprite, boat.posX - boat.sprite.w / 2, boat.posY - boat.sprite.h);
        //draw treasure
        if (treasure.visible) {
            drawSprite(ctx, treasure.sprite, treasure.posX - treasure.sprite.w / 2, treasure.posY - treasure.sprite.h);
        }
        //draw characters
        characters.forEach(function(character) {
            if (character.dir == -1) {
                ctx.save();
                ctx.scale(-1,1);
                drawSprite(ctx, character.sprite,
                           (character.posX - character.sprite.w / 2) * -1 - character.sprite.w,
                           character.posY);
                ctx.restore();
            } else {
                drawSprite(ctx, character.sprite, character.posX - character.sprite.w / 2, character.posY);
            }
        });
        //print level
        //print score
        ctx.font = "25px monospace";
        ctx.fillStyle = "white";
        ctx.fillText("LEVEL: " + level, 10, 30);
        ctx.fillText("SCORE: " + score, 10, 60);

    };

    /* Game loop */
    // Special thanks to http://gafferongames.com/game-physics/fix-your-timestep/
    var runTime = 0;
    var timeStep = 1 / 30;
    var currentTime = Date.now();
    var mainLoop = function () {
            var newTime = Date.now();
            var frameTime = newTime - currentTime;
            currentTime = newTime;
            while (frameTime > 0) {
                var delta = Math.min(frameTime, timeStep);
                update(delta / 1000);
                frameTime -= delta;
                runTime += delta;
            }
        draw();
        if (!gameOver) {
            requestAnimationFrame(mainLoop, canvas);
        }
        else {
            drawGameOver(ctx);
        }
    };

    /* Driver code*/
    initGame();
    initLevel(1);
    mainLoop();
})(canvas);<commit_msg>Make player 'carry' treasure chest. Fixes #2<commit_after>(function (canvas) {
    /* Init some variables */
    var w = canvas.width;
    var h = canvas.height;
    var ctx = canvas.getContext("2d");
    var keysDown = {};
    var characters, treasure, boat, player, score, gameOver, level;

    /* Keyboard handling */
    addEventListener("keydown", function (e) {
        keysDown[e.keyCode] = true;
    }, false);
    addEventListener("keyup", function (e) {
        delete keysDown[e.keyCode];
    }, false);
    //prevent arrow key scrolling
    window.addEventListener("keydown", function(e) {
        // arrow keys
        if([37, 38, 39, 40].indexOf(e.keyCode) > -1) {
        e.preventDefault();
        }
    }, false);

    /* Base objects */
    var Rect = function(x, y, w, h)
    {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    };
    var Character = function (x, y, moveSpeed, sprite, collisionBox, isPlayer) {
        this.posX = x || 0;
        this.posY = y || 0;
        this.moveSpeed = moveSpeed || 0;
        this.sprite = sprite || null;
        this.collisionBox = collisionBox || null;
        this.isPlayer = isPlayer || false;
    };
    Character.prototype.move = function (deltaX, deltaY) {
        this.posX = (this.posX + deltaX + w) % w;
        targetY = this.posY + deltaY;
        if (targetY > h * 0.2 && targetY < h * 0.9 - 16) {
            this.posY = targetY;
        }
    };
    var Item = function(x, y, sprite) {
        this.posX = x || 0;
        this.posY = y || 0;
        this.held = false;
        this.sprite = sprite || null;
    };

    /* Movement handlers */
    var octoMove = function(timePassed) {
        this.move(this.moveSpeed * this.dir * timePassed * 100, 0);
        if (collisionCheck(player, this)) {
            gameOver = true;
        }
    };
    var playerMove = function(timePassed) {
        if (38 in keysDown) { // up
            this.move(0, -this.moveSpeed * timePassed * 100);
        }
        if (40 in keysDown) { // down
            this.move(0, this.moveSpeed * timePassed * 100);
        }
        if (39 in keysDown) { // right
            this.dir = 1;
        }
        if (37 in keysDown) { // left
            this.dir = -1;
        }
    };

    /* Init rects */
    var sprites = {
        diver: new Rect(0,0,31,31),
        octo: new Rect(0,32,32,32),
        boat: new Rect(0,64,32,32),
        treasure: new Rect(0,97,32,31),
    };
    var collisionBoxes = {
        diver: new Rect(2,6,26,6),
        octo: new Rect(6,2,16,20),
    };

    /*collision detection (Axis-Aligned Bounding Boxes)*/
    var collisionCheck = function (item1, item2) {
        var box1 = item1.collisionBox;
        var box2 = item2.collisionBox;
        var x1 = box1.x + item1.posX - item1.sprite.w / 2;
        var y1 = box1.y + item1.posY;
        var x2 = box2.x + item2.posX - item2.sprite.w / 2;
        var y2 = box2.y + item2.posY;
        return (x1 < x2 + box2.w &&
                x1 + box1.w > x2 &&
                y1 < y2 + box2.h &&
                box1.h + y1 > y2);
    };

    /* Drawing helpers */
    var drawSprite = function(ctx, sprite, x, y) {
       var sprites = document.getElementById("sprites");
       ctx.drawImage(sprites, sprite.x, sprite.y, sprite.w, sprite.h, x, y, sprite.w, sprite.h);
    };
    var drawGameOver = function(ctx) {
        ctx.font = "100px monospace";
        ctx.fillStyle = "white";
        ctx.fillText("GAME OVER", 130, h / 2);
    };

    /* Main init, runs once */
    var initGame = function () {
        characters = [];
        treasure = new Item(w / 2, h * 0.9, sprites.treasure);
        boat = new Item(w / 2, h * 0.2, sprites.boat);
        score = 0;
        gameOver = false;
        level = 1;
    };

    /* Level init, runs each level. */
    var initLevel = function(level) {
        characters = [];
        treasure.held = false;
        player = new Character(w / 2, h * 0.2, 1, sprites.diver, collisionBoxes.diver, true);
        player.treasureCount = 0;
        player.update = playerMove;
        characters.push(player);
        // More octopuses each level
        for (var i = 0; i <= level * 2; i++) {
            // Can get faster each level, randomized for varied speeds.
            var speed = 1 + Math.random() * (level * 0.15);
            var octopus = new Character(Math.random() * w, Math.random() *  h * 0.6 + (h * 0.25), speed, sprites.octo, collisionBoxes.octo);
            octopus.dir = Math.random()<0.5 ? 1 : -1;
            octopus.update = octoMove;
            characters.push(octopus);
        }
    };

    /* Update game state */
    var update = function (timePassed) {
        characters.forEach(function(character) {
            character.update(timePassed);
        });

        if (!treasure.held && player.posY > 518) {
            player.treasureCount += 1;
            treasure.held = true;
        }
        if (player.treasureCount > 0 && player.posY < 121) {
            score += player.treasureCount * 1000 * level;
            player.treasureCount = 0;
            level += 1;
            initLevel(level);
        }
    };

    /* Draw graphics to canvas */
    var draw = function() {
        //prepare graphics
        //draw background
        // sky
        ctx.fillStyle = "#0000dd";
        ctx.fillRect(0, 0, w, h);
        // water
        ctx.fillStyle = "#222255";
        ctx.fillRect(0, h * 0.2, w, h * 0.7);
        // sand
        ctx.fillStyle = "#442200";
        ctx.fillRect(0, h * 0.9, w, h * 0.1);
        //draw boat
        drawSprite(ctx, boat.sprite, boat.posX - boat.sprite.w / 2, boat.posY - boat.sprite.h);
        //draw characters
        characters.forEach(function(character) {
            if (character.dir == -1) {
                ctx.save();
                ctx.scale(-1,1);
                drawSprite(ctx, character.sprite,
                           (character.posX - character.sprite.w / 2) * -1 - character.sprite.w,
                           character.posY);
                ctx.restore();
            } else {
                drawSprite(ctx, character.sprite, character.posX - character.sprite.w / 2, character.posY);
            }
        });
        //draw treasure
        if (treasure.held) {
            drawSprite(ctx, treasure.sprite, treasure.posX - treasure.sprite.w / 2, player.posY - 26);
        } else {
            drawSprite(ctx, treasure.sprite, treasure.posX - treasure.sprite.w / 2, treasure.posY - treasure.sprite.h);
        }
        //print level
        //print score
        ctx.font = "25px monospace";
        ctx.fillStyle = "white";
        ctx.fillText("LEVEL: " + level, 10, 30);
        ctx.fillText("SCORE: " + score, 10, 60);

    };

    /* Game loop */
    // Special thanks to http://gafferongames.com/game-physics/fix-your-timestep/
    var runTime = 0;
    var timeStep = 1 / 30;
    var currentTime = Date.now();
    var mainLoop = function () {
            var newTime = Date.now();
            var frameTime = newTime - currentTime;
            currentTime = newTime;
            while (frameTime > 0) {
                var delta = Math.min(frameTime, timeStep);
                update(delta / 1000);
                frameTime -= delta;
                runTime += delta;
            }
        draw();
        if (!gameOver) {
            requestAnimationFrame(mainLoop, canvas);
        }
        else {
            drawGameOver(ctx);
        }
    };

    /* Driver code*/
    initGame();
    initLevel(1);
    mainLoop();
})(canvas);<|endoftext|>


<commit_before>const os = require('os');
const moment = require('moment');
const botVersion = require('../../package.json').version;
const { version } = require('discord.js');
const time = require('time-parser');
const timeRXes = {
    'next': 'one',
    'a '  : 'one ',
    'an ' : 'one ',
    'sec' : 'second',
    'min' : 'minute'
};

require('moment-duration-format');

module.exports = async function (Bot, msg) {
    const prefix = await Bot.db.get('SELECT * FROM prefixes WHERE guildID = ?', msg.guild.id) || Bot.config.defaultPrefix;
    const command = msg.content.toLowerCase().slice(prefix.length).split(' ')[0];
    const args = msg.content.split(' ').slice(1).filter(arg => arg !== Bot.client.user.toString());
    const isCommand = (commands) => {
        if (!Array.isArray(commands)) {
            commands = [commands];
        }
        return commands.includes(command) && msg.content.startsWith(prefix) ||
        msg.isMentioned(Bot.client.user.id) && commands.some(word => msg.content.toLowerCase().includes(word));
    };

    if (isCommand('ping')) {
        msg.channel.send(`:ping_pong: Pong! ${Bot.client.ping.toFixed()}ms`);
    }

    if (isCommand('invite')) {
        msg.channel.send({ embed: {
            color: Bot.config.embedColor,
            description: `Click [here](https://discordapp.com/oauth2/authorize?permissions=27648&scope=bot&client_id=${this.client.user.id}) to invite me to your server, or click [here](https://discord.gg/Yphr6WG) for an invite to RemindMeBot\'s support server.`
        }});
    }

    if (isCommand('help')) {
        msg.channel.send(`To set a reminder, simply send \`${prefix}remindme\` and follow the instructions. Alternatively, you can also send \`${prefix}remindme time_argument "message"\`, \ne.g. \`${prefix}remindme 31 December 2017 "New Years"\`.\nMy prefix is \`${prefix}\`; here's a list of my commands: `, { embed: {
            color: this.config.embedColor,
            description: 'clear, forget, help, info, invite, list, ping, prefix, remindme'
        }});
    }

    if (isCommand(['stats', 'info'])) {
        msg.channel.send({ embed: {
            color: Bot.config.embedColor,
            title: `RemindMeBot ${botVersion}`,
            url: 'http://remindmebot.xyz',
            fields: [
                { name: 'Guilds',      value: Bot.client.guilds.size, inline: true },
                { name: 'Uptime',      value: moment.duration(process.uptime(), 'seconds').format('dd:hh:mm:ss'), inline: true },
                { name: 'Ping',        value: `${Bot.client.ping.toFixed()} ms`, inline: true },
                { name: 'RAM Usage',   value: `${(process.memoryUsage().rss / 1048576).toFixed()}MB/${(os.totalmem() > 1073741824 ? `${(os.totalmem() / 1073741824).toFixed(1)} GB` : `${(os.totalmem() / 1048576).toFixed()} MB`)}
(${(process.memoryUsage().rss / os.totalmem() * 100).toFixed(2)}%)`, inline: true },
                { name: 'System Info', value: `${process.platform} (${process.arch})\n${(os.totalmem() > 1073741824 ? `${(os.totalmem() / 1073741824).toFixed(1)} GB` : `${(os.totalmem() / 1048576).toFixed(2)} MB`)}`, inline: true },
                { name: 'Libraries',   value: `[Discord.js](https://discord.js.org) v${version}\n[Node.js](https://nodejs.org/en/) ${process.version}`, inline: true },
                { name: 'Links',       value: '[Bot invite](https://discordapp.com/oauth2/authorize?permissions=27648&scope=bot&client_id=290947970457796608) | [Support server invite](https://discord.gg/Yphr6WG) | [GitHub](https://github.com/Aetheryx/remindme) | [Website](http://remindmebot.xyz)' },
            ],
            footer: { text: 'Created by Aetheryx#2222' }
        }});
    }

    if (isCommand(['reboot', 'restart'])) {
        if (msg.author.id !== Bot.config.ownerID) {
            return msg.reply('You do not have permission to use this command.');
        }
        await msg.channel.send('Restarting...');
        await Bot.client.destroy();
        process.exit();
    }

    if (isCommand(['forget', 'delete'])) {
        const reminders = await Bot.db.all('SELECT ROWID, reminderText FROM reminders WHERE owner = ?', msg.author.id);
        if (!reminders[0]) {
            return msg.reply('You have no reminders set.');
        }
        msg.channel.send('Here\'s a list of your current reminders:', { embed: {
            color: Bot.config.embedColor,
            title: 'Reminders',
            description: reminders.map((r, i) => `[${i + 1}] ${r.reminderText}`).join('\n'),
            footer: { text: 'Send the number of the reminder you want me to forget (e.g. 3), or send c to cancel.' }
        }});

        const fetchAndParseInput = async () => {
            let m;
            try {
                m = await msg.channel.awaitMessages(m => m.author.id === msg.author.id, { max: 1, time: 10000, errors: ['time'] });
            } catch (e) {
                msg.channel.send('Prompt timed out.');
                return false;
            }
            m = m.first().content.toLowerCase();
            if (m.startsWith(`${prefix}delete`) || m.startsWith(`${prefix}forget`)) {
                return false;
            }
            if (m === 'c' || m === 'cancel') {
                msg.channel.send('Cancelled.');
                return false;
            }

            if (!parseInt(m)) {
                msg.channel.send('Send the number of the reminder you want me to forget (e.g. 3), or send c to cancel.');
                return fetchAndParseInput();
            }
            if (parseInt(m) > reminders.length) {
                msg.channel.send('You don\'t have that many reminders. Send the number of the reminder you want me to forget (e.g. 3), or send c to cancel.');
                return fetchAndParseInput();
            }
            return parseInt(m);
        };

        const res = await fetchAndParseInput();
        if (res) {
            const r = reminders[res - 1];
            Bot.db.run('DELETE FROM reminders WHERE rowid = ?;', r.rowid)
                .then(res => {
                    if (res) {
                        msg.channel.send(`Reminder ${r.reminderText} deleted.`);
                    }
                });
        }
    }

    if (isCommand('remindme') && args[0]) {
        if (!msg.content.includes('"')) {
            return msg.channel.send(`Argument error. Please follow the proper syntax for the command:\n\`${prefix}remindme time_argument "message"\`, e.g. \`${prefix}remindme 31 December 2017 "New Years"\``);
        }

        const timeRX = new RegExp(`${prefix}remindme(.*?)"`, 'i');
        let timeArg = timeRX.exec(msg.cleanContent)[1].trim();
        Object.keys(timeRXes).map(regexKey => {
            if (timeArg.includes(regexKey)) {
                timeArg = timeArg.replace(new RegExp(regexKey, 'gi'), timeRXes[regexKey]);
            }
        });

        const tParse = time(timeArg).absolute;
        Bot.log(timeArg);
        if (!isNaN(timeArg) || !tParse) {
            return msg.channel.send('Invalid time argument. Please enter a proper time argument, e.g. `12 hours` or `next week`.');
        }
        if (time(timeArg).relative < 0) {
            return msg.channel.send('Your reminder wasn\'t added because it was set for the past. Note that if you\'re trying to set a reminder for the same day at a specific time (e.g. `6 PM`), UTC time will be assumed.');
        }

        const reminderRX = /"(.*?)"/i;
        const reminder = reminderRX.exec(msg.cleanContent)[1].trim();

        Bot.db.run(`INSERT INTO reminders (owner, reminderText, createdDate, dueDate, channelID)
        VALUES (?, ?, ?, ?, ?)`,       msg.author.id, reminder, Date.now(), tParse, msg.channel.id)
            .then(res => {
                if (res) {
                    msg.channel.send({ embed: {
                        color: Bot.config.embedColor,
                        description: `:ballot_box_with_check: Reminder added: ${reminder}`,
                        footer: { text: 'Reminder set for ' },
                        timestamp: new Date(tParse)
                    }});
                }
            })
            .catch(err => {
                Bot.log(err.stack);
                msg.channel.send(`Your reminder wasn't added. This incident has been logged.\n${err.message}`);
            });
    }
};<commit_msg>Added list command, channel for reminders<commit_after>const os = require('os');
const moment = require('moment');
const botVersion = require('../../package.json').version;
const { version } = require('discord.js');
const time = require('time-parser');
const humanize = require('humanize-duration');
const timeRXes = {
    'next' : 'one',
    'a '   : 'one ',
    'an '  : 'one ',
    'sec ' : 'second',
    'min ' : 'minute'
};

require('moment-duration-format');

module.exports = async function (Bot, msg) {
    const prefix = await Bot.db.get('SELECT prefix FROM prefixes WHERE guildID = ?', msg.guild.id) || Bot.config.defaultPrefix;
    const command = msg.content.toLowerCase().slice(prefix.length).split(' ')[0];
    const args = msg.content.split(' ').slice(1).filter(arg => arg !== Bot.client.user.toString());
    const isCommand = (commands) => {
        if (!Array.isArray(commands)) {
            commands = [commands];
        }
        return commands.includes(command) && msg.content.startsWith(prefix) ||
        msg.isMentioned(Bot.client.user.id) && commands.some(word => msg.content.toLowerCase().includes(word));
    };

    if (isCommand('ping')) {
        msg.channel.send(`:ping_pong: Pong! ${Bot.client.ping.toFixed()}ms`);
    }

    if (isCommand('invite')) {
        msg.channel.send({ embed: {
            color: Bot.config.embedColor,
            description: `Click [here](https://discordapp.com/oauth2/authorize?permissions=27648&scope=bot&client_id=${Bot.client.user.id}) to invite me to your server, or click [here](https://discord.gg/Yphr6WG) for an invite to RemindMeBot\'s support server.`
        }});
    }

    if (isCommand('help')) {
        msg.channel.send(`To set a reminder, simply send \`${prefix}remindme\` and follow the instructions. Alternatively, you can also send \`${prefix}remindme time_argument "message"\`, \ne.g. \`${prefix}remindme 31 December 2017 "New Years"\`.\nMy prefix is \`${prefix}\`; here's a list of my commands: `, { embed: {
            color: Bot.config.embedColor,
            description: 'clear, forget, help, info, invite, list, ping, prefix, remindme'
        }});
    }

    if (isCommand(['stats', 'info'])) {
        msg.channel.send({ embed: {
            color: Bot.config.embedColor,
            title: `RemindMeBot ${botVersion}`,
            url: 'http://remindmebot.xyz',
            fields: [
                { name: 'Guilds',      value: Bot.client.guilds.size, inline: true },
                { name: 'Uptime',      value: moment.duration(process.uptime(), 'seconds').format('dd:hh:mm:ss'), inline: true },
                { name: 'Ping',        value: `${Bot.client.ping.toFixed()} ms`, inline: true },
                { name: 'RAM Usage',   value: `${(process.memoryUsage().rss / 1048576).toFixed()}MB/${(os.totalmem() > 1073741824 ? `${(os.totalmem() / 1073741824).toFixed(1)} GB` : `${(os.totalmem() / 1048576).toFixed()} MB`)}
(${(process.memoryUsage().rss / os.totalmem() * 100).toFixed(2)}%)`, inline: true },
                { name: 'System Info', value: `${process.platform} (${process.arch})\n${(os.totalmem() > 1073741824 ? `${(os.totalmem() / 1073741824).toFixed(1)} GB` : `${(os.totalmem() / 1048576).toFixed(2)} MB`)}`, inline: true },
                { name: 'Libraries',   value: `[Discord.js](https://discord.js.org) v${version}\n[Node.js](https://nodejs.org/en/) ${process.version}`, inline: true },
                { name: 'Links',       value: '[Bot invite](https://discordapp.com/oauth2/authorize?permissions=27648&scope=bot&client_id=290947970457796608) | [Support server invite](https://discord.gg/Yphr6WG) | [GitHub](https://github.com/Aetheryx/remindme) | [Website](http://remindmebot.xyz)' },
            ],
            footer: { text: 'Created by Aetheryx#2222' }
        }});
    }

    if (isCommand(['reboot', 'restart'])) {
        if (msg.author.id !== Bot.config.ownerID) {
            return msg.reply('You do not have permission to use this command.');
        }
        await msg.channel.send('Restarting...');
        await Bot.client.destroy();
        process.exit();
    }

    if (isCommand('list')) {
        const reminders = await Bot.db.all('SELECT reminderText, dueDate, createdDate FROM reminders WHERE owner = ?;', msg.author.id);
        if (!reminders[0]) {
            return msg.reply('You have no reminders set.');
        }

        const embed = {
            color: Bot.config.embedColor,
            title: `Current reminder${plural(reminders)}:`,
            fields: []
        };

        reminders.forEach(r => {
            if (embed.fields.length < 25) {
                embed.fields.push({
                    name:  `Due in ${humanize(r.dueDate - Date.now(), { conjunction: ' and ', serialComma: false, largest: 3, round: true })}`,
                    value: r.reminderText
                });
            }
        });

        msg.author.send({ embed })
            .then(() => {
                msg.channel.send(':ballot_box_with_check: Check your DMs!');
            })
            .catch(err => {
                if (err.message === 'Cannot send messages to this user') {
                    msg.channel.send({ embed });
                }
            });
    }

    if (isCommand('clear')) {
        const res = await Bot.db.get('SELECT rowid FROM reminders WHERE owner = ? LIMIT 1', msg.author.id);
        if (!res) {
            return msg.reply('You have no reminders set.');
        }

        msg.channel.send(':warning: This will delete all of your reminders! Are you sure? (`y`/`n`)');

        let m = await msg.channel.awaitMessages(m => m.author.id === msg.author.id, { max: 1, time: 5000, errors: ['time'] })
            .catch(() => {
                return msg.channel.send('Prompt timed out.');
            });
        m = m.first ? m.first() : m;

        if (m.author.id === Bot.client.user.id) {
            return;
        }

        if (m.content.toLowerCase() === 'y') {
            Bot.db.run('DELETE FROM reminders WHERE owner = ?', msg.author.id)
                .then(() => {
                    msg.channel.send(':ballot_box_with_check: Reminders cleared.');
                })
                .catch(err => {
                    msg.channel.send(`Your reminders weren't cleared.\n${err.message}`);
                });
        } else if (m.content.includes('clear')) {
            return;
        } else {
            msg.channel.send(':ballot_box_with_check: Cancelled.');
        }
    }

    if (isCommand(['forget', 'delete'])) {
        const reminders = await Bot.db.all('SELECT rowid, reminderText FROM reminders WHERE owner = ?;', msg.author.id);
        if (!reminders[0]) {
            return msg.reply('You have no reminders set.');
        }
        msg.channel.send('Here\'s a list of your current reminders:', { embed: {
            color: Bot.config.embedColor,
            title: 'Reminders',
            description: reminders.map((r, i) => `[${i + 1}] ${r.reminderText}`).join('\n'),
            footer: { text: 'Send the number of the reminder you want me to forget (e.g. 3), or send c to cancel.' }
        }});

        const fetchAndParseInput = async () => {
            let m;
            try {
                m = await msg.channel.awaitMessages(m => m.author.id === msg.author.id, { max: 1, time: 1000, errors: ['time'] });
            } catch (e) {
                msg.channel.send('Prompt timed out.');
                return false;
            }
            m = m.first().content.toLowerCase();
            if (m.includes('delete') || m.includes('forget')) {
                return false;
            }
            if (m === 'c' || m === 'cancel') {
                msg.channel.send('Cancelled.');
                return false;
            }

            if (!parseInt(m)) {
                msg.channel.send('Send the number of the reminder you want me to forget (e.g. 2), or send c to cancel.');
                return fetchAndParseInput();
            }
            if (parseInt(m) > reminders.length) {
                msg.channel.send('You don\'t have that many reminders. Send the number of the reminder you want me to forget (e.g. 3), or send c to cancel.');
                return fetchAndParseInput();
            }
            return parseInt(m);
        };

        const choice = await fetchAndParseInput();
        if (choice) {
            const r = reminders[choice - 1];
            const res = await Bot.db.run('DELETE FROM reminders WHERE rowid = ?;', r.rowid);
            if (res) {
                msg.channel.send(`Reminder \`${r.reminderText}\` deleted successfully.`);
            }
        }
    }

    if (isCommand('remindme') && args[0]) {
        if (!msg.content.includes('"')) {
            return msg.channel.send(`Argument error. Please follow the proper syntax for the command:\n\`${prefix}remindme time_argument "message"\`, e.g. \`${prefix}remindme 31 December 2017 "New Years"\``);
        }

        const timeRX = new RegExp(`${prefix}remindme(.*?)"`, 'i');
        let timeArg = timeRX.exec(msg.cleanContent)[1];

        Object.keys(timeRXes).map(regexKey => {
            if (timeArg.includes(regexKey)) {
                timeArg = timeArg.replace(new RegExp(regexKey, 'gi'), timeRXes[regexKey]);
            }
        });

        const parsedTime = time(timeArg.trim()).absolute;
        if (!isNaN(timeArg) || !parsedTime) {
            return msg.channel.send('Invalid time argument. Please enter a proper time argument, e.g. `12 hours` or `next week`.');
        }
        if (time(timeArg).relative < 0) {
            return msg.channel.send('Your reminder wasn\'t added because it was set for the past. Note that if you\'re trying to set a reminder for the same day at a specific time (e.g. `6 PM`), UTC time will be assumed.');
        }

        const channelRX = /channel: *(<#[0-9]{18}>)/g;
        const channelID = channelRX.exec(msg.content);

        const reminderRX = /"(.*?)"/i;
        const reminder = reminderRX.exec(msg.cleanContent)[1].trim();
        if (reminder.length > 1000) {
            return msg.channel.send('Your reminder cannot exceed 1000 characters.');
        }

        Bot.db.run(`INSERT INTO reminders (owner, reminderText, createdDate, dueDate, channelID)
        VALUES (?, ?, ?, ?, ?);`,      msg.author.id, reminder, Date.now(), parsedTime, channelID ? channelID[1].replace(/<|>|#/g, '') : null)
            .then(res => {
                if (res) {
                    msg.channel.send({ embed: {
                        color: Bot.config.embedColor,
                        description: `:ballot_box_with_check: Reminder added: ${reminder}`,
                        footer: { text: 'Reminder set for ' },
                        timestamp: new Date(parsedTime)
                    }});
                }
            })
            .catch(err => {
                msg.channel.send(`Your reminder wasn't added. This incident has been logged.\n${err.message}`);
                Bot.log(err.stack, 'error');
            });
    }

    if (isCommand(['reboot', 'restart'])) {
        if (msg.author.id !== Bot.config.ownerID) {
            return msg.reply('You do not have permission to use this command.');
        }
        await msg.channel.send('Restarting...');
        await Bot.client.destroy();
        process.exit();
    }

};

function plural (item) {
    return item.length > 1 ? 's' : '';
}<|endoftext|>


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

  'use strict';

  /**
   * Plugin NAMESPACE
   * @type {String}
   * @api private
   */
  var NAMESPACE = 'sr.tour',
      SELECTOR = '.tour';

  /**
   * Plugin constructor
   * @param {Node} element
   * @param {Object} [options]
   * @api public
   */
  function Plugin (element, options) {
    this.options = $.extend(true, $.fn[NAMESPACE].defaults, options);
    this.$element = $(element);
    this.$locationControls = $('[data-target]', this.$element);
    this.$stepsCloseButton = $('.tour__steps-close-button', this.$element);
  }

  /**
   * Plugin prototype
   * @type {Object}
   * @api public
   */
  Plugin.prototype = {
    constructor: Plugin,
    version: '0.1.0',

    /**
     * Init method
     * @api public
     */
    init: function () {

      // Set up interactions for location controls
      this.$locationControls.on('mouseenter', $.proxy(this.enterLocationControl, this));
      this.$locationControls.on('mouseleave', $.proxy(this.leaveLocationControl, this));
      this.$locationControls.on('focusin', $.proxy(this.focusLocationControl, this));
      this.$locationControls.on('focusout', $.proxy(this.blurLocationControl, this));

      this.$stepsCloseButton.on('click', $.proxy(this.setTourInactive, this));
    },

    /**
     * Mouse Enter Location Control method
     */
    enterLocationControl: function(event) {
      var $control = $(event.target);
      var stepId = $control.data('target');

      // Highlight any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').addClass('is-active');
    },

    /**
     * Mouse Leave Location Control method
     */
    leaveLocationControl: function(event) {
      var $control = $(event.target);
      var stepId = $control.data('target');

      // Remove highlight from any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').removeClass('is-active');
    },

    /**
     * Focus Location Control method
     */
    focusLocationControl: function(event) {
      var $control = $(event.target);
      var stepId = $control.data('target');
      var $step = $('#' + stepId);

      // Highlight any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').addClass('is-active');

      // Make currently active target inactive
      if (this.options.activeStepId) {
        $('#' + this.options.activeStepId).removeClass('is-active');
      }

      // Set target to active
      $step.addClass('is-active');
      this.options.activeStepId = stepId;

      // Set active step
      this.setActiveStep(stepId);
    },

    /**
     * Blur Location Control method
     */
    blurLocationControl: function(event) {
      var $control = $(event.target);
      var stepId = $control.data('target');

      // Remove highlight from any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').removeClass('is-active');
    },

    /**
     * Set Step to Active
     */
    setActiveStep: function(stepId) {

      // Set class on container to signal that a step is active
      this.$element.addClass('is-step-active');
    },

    /**
     * Set Tour to Inactive
     */
    setTourInactive: function() {

      console.log('setTourInactive');

      // Remove class on container to signal that no steps are active
      this.$element.removeClass('is-step-active');
    }

  };

  /**
   * jQuery plugin definition
   * @param  {String} [method]
   * @param  {Object} [options]
   * @return {Object}
   * @api public
   */
  $.fn[NAMESPACE] = function (method, options) {
    return this.each(function () {
      var $this = $(this),
      data = $this.data(NAMESPACE);
      options = (typeof method === 'object') ? method : options;
      if (!data) {
        $this.data(NAMESPACE, (data = new Plugin(this, options)));
      }
      data[(typeof method === 'string') ? method : 'init']();
    });
  };

  /**
   * jQuery plugin defaults
   * @type {Object}
   * @api public
   */
  $.fn[NAMESPACE].defaults = {
    activeStepId: null
  };

  /**
   * jQuery plugin data api
   * @api public
   */
  $(window).on('load', function (event) {
    $(SELECTOR).each(function () {
      $(this)[NAMESPACE]();
    });
  });

}(this, this.document, this.jQuery));
<commit_msg>Add click event listener to tour (for Safari)<commit_after>;(function(window, document, $, undefined) {

  'use strict';

  /**
   * Plugin NAMESPACE
   * @type {String}
   * @api private
   */
  var NAMESPACE = 'sr.tour',
      SELECTOR = '.tour';

  /**
   * Plugin constructor
   * @param {Node} element
   * @param {Object} [options]
   * @api public
   */
  function Plugin (element, options) {
    this.options = $.extend(true, $.fn[NAMESPACE].defaults, options);
    this.$element = $(element);
    this.$locationControls = $('[data-target]', this.$element);
    this.$stepsCloseButton = $('.tour__steps-close-button', this.$element);
  }

  /**
   * Plugin prototype
   * @type {Object}
   * @api public
   */
  Plugin.prototype = {
    constructor: Plugin,
    version: '0.1.0',

    /**
     * Init method
     * @api public
     */
    init: function () {

      // Set up interactions for location controls
      this.$locationControls.on('mouseenter', $.proxy(this.enterLocationControl, this));
      this.$locationControls.on('mouseleave', $.proxy(this.leaveLocationControl, this));
      this.$locationControls.on('click focusin', $.proxy(this.focusLocationControl, this));
      this.$locationControls.on('focusout', $.proxy(this.blurLocationControl, this));

      this.$stepsCloseButton.on('click', $.proxy(this.setTourInactive, this));
    },

    /**
     * Mouse Enter Location Control method
     */
    enterLocationControl: function(event) {
      console.log('enterLocationControl');
      var $control = $(event.target);
      var stepId = $control.data('target');

      // Highlight any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').addClass('is-active');
    },

    /**
     * Mouse Leave Location Control method
     */
    leaveLocationControl: function(event) {
      console.log('leaveLocationControl');
      var $control = $(event.target);
      var stepId = $control.data('target');

      // Remove highlight from any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').removeClass('is-active');
    },

    /**
     * Focus Location Control method
     */
    focusLocationControl: function(event) {
      console.log('focusLocationControl');
      var $control = $(event.target);
      var stepId = $control.data('target');
      var $step = $('#' + stepId);

      // Highlight any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').addClass('is-active');

      // Make currently active target inactive
      if (this.options.activeStepId) {
        $('#' + this.options.activeStepId).removeClass('is-active');
      }

      // Set target to active
      $step.addClass('is-active');
      this.options.activeStepId = stepId;

      // Set active step
      this.setActiveStep(stepId);
    },

    /**
     * Blur Location Control method
     */
    blurLocationControl: function(event) {
      console.log('blurLocationControl');
      var $control = $(event.target);
      var stepId = $control.data('target');

      // Remove highlight from any control with the stepId
      this.$locationControls.filter('[data-target="' + stepId + '"]').removeClass('is-active');
    },

    /**
     * Set Step to Active
     */
    setActiveStep: function(stepId) {

      // Set class on container to signal that a step is active
      this.$element.addClass('is-step-active');
    },

    /**
     * Set Tour to Inactive
     */
    setTourInactive: function() {

      console.log('setTourInactive');

      // Remove class on container to signal that no steps are active
      this.$element.removeClass('is-step-active');
    }

  };

  /**
   * jQuery plugin definition
   * @param  {String} [method]
   * @param  {Object} [options]
   * @return {Object}
   * @api public
   */
  $.fn[NAMESPACE] = function (method, options) {
    return this.each(function () {
      var $this = $(this),
      data = $this.data(NAMESPACE);
      options = (typeof method === 'object') ? method : options;
      if (!data) {
        $this.data(NAMESPACE, (data = new Plugin(this, options)));
      }
      data[(typeof method === 'string') ? method : 'init']();
    });
  };

  /**
   * jQuery plugin defaults
   * @type {Object}
   * @api public
   */
  $.fn[NAMESPACE].defaults = {
    activeStepId: null
  };

  /**
   * jQuery plugin data api
   * @api public
   */
  $(window).on('load', function (event) {
    $(SELECTOR).each(function () {
      $(this)[NAMESPACE]();
    });
  });

}(this, this.document, this.jQuery));
<|endoftext|>


<commit_before>var _ = require('lodash'),
    utils = require('../../../utils'),
    driver = utils.getDriver(),
    C = driver.constants,
    movement = require('../movement');

function _applyDamage(object, damage) {

    let damageReduce = 0, damageEffective = damage;

    if(_.any(object.body, i => !!i.boost)) {
        for(let i=0; i<object.body.length; i++) {
            if(damageEffective <= 0) {
                break;
            }
            let bodyPart = object.body[i], damageRatio = 1;
            if(bodyPart.boost && C.BOOSTS[bodyPart.type][bodyPart.boost] && C.BOOSTS[bodyPart.type][bodyPart.boost].damage) {
                damageRatio = C.BOOSTS[bodyPart.type][bodyPart.boost].damage;
            }
            let bodyPartHitsEffective = bodyPart.hits / damageRatio;
            damageReduce += Math.min(bodyPartHitsEffective, damageEffective) * (1 - damageRatio);
            damageEffective -= Math.min(bodyPartHitsEffective, damageEffective);
        }
    }

    damage -= Math.round(damageReduce);

    object.hits -= damage;
}

module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime) {

    if(!object || object.type != 'creep') return;

    if(object.spawning) {
        var spawn = _.find(roomObjects, {type: 'spawn', x: object.x, y: object.y});
        if(!spawn) {
            bulk.remove(object._id);
        }
        else {
            if(!spawn.spawning || spawn.spawning.name != object.name) {
                require('../spawns/_born-creep')(spawn, object, roomObjects, roomTerrain, bulk, stats);
            }
        }
    }
    else {

        movement.execute(object, bulk, roomController, gameTime);

        if((object.x == 0 || object.y == 0 || object.x == 49 || object.y == 49) && object.user != '2' && object.user != '3') {

            var [roomX, roomY] = utils.roomNameToXY(object.room),
                x = object.x,
                y = object.y,
                room = object.room;

            if (object.x == 0) {
                x = 49;
                room = utils.getRoomNameFromXY(roomX-1, roomY);
            }
            else if (object.y == 0) {
                y = 49;
                room = utils.getRoomNameFromXY(roomX, roomY-1);
            }
            else if (object.x == 49) {
                x = 0;
                room = utils.getRoomNameFromXY(roomX+1, roomY);
            }
            else if (object.y == 49) {
                y = 0;
                room = utils.getRoomNameFromXY(roomX, roomY+1);
            }

            bulk.update(object, {interRoom: {room, x, y}});
        }

        if(object.ageTime) { // since NPC creeps may appear right on portals without `ageTime` defined at the first tick
            var portal = _.find(roomObjects, i => i.type == 'portal' && i.x == object.x && i.y == object.y);
            if (portal) {
                bulk.update(object, {interRoom: portal.destination});
            }
        }

        if(!object.tutorial) {
            if(!object.ageTime) {
                object.ageTime = gameTime + (_.any(object.body, {type: C.CLAIM}) ? C.CREEP_CLAIM_LIFE_TIME : C.CREEP_LIFE_TIME);
                bulk.update(object, {ageTime: object.ageTime});
            }

            if(gameTime >= object.ageTime-1) {
                require('./_die')(object, roomObjects, bulk, stats, undefined, gameTime);
            }
        }

        if(!_.isEqual(object.actionLog, object._actionLog)) {
            bulk.update(object, {actionLog: object.actionLog});
        }

    }

    if(object.fatigue > 0) {
        var moves = utils.calcBodyEffectiveness(object.body, C.MOVE, 'fatigue', 1);

        object.fatigue -= moves * 2;

        if(object.fatigue < 0)
            object.fatigue = 0;

        bulk.update(object._id, {fatigue: object.fatigue});
    }

    if(_.isNaN(object.hits) || object.hits <= 0) {
        require('./_die')(object, roomObjects, bulk, stats, undefined, gameTime);
    }

    if(object.userSummoned && _.any(roomObjects, i => i.type == 'creep' && i.user != '2' && i.user != roomController.user)) {
        require('./_die')(object, roomObjects, bulk, stats, undefined, gameTime);
    }

    let oldHits = object.hits;

    if (object._damageToApply) {
        _applyDamage(object, object._damageToApply);
        delete object._damageToApply;
    }

    if (object._healToApply) {
        object.hits += object._healToApply;
        delete object._healToApply;
    }

    if(object.hits > object.hitsMax) {
        object.hits = object.hitsMax;
    }

    if(object.hits <= 0) {
        require('./_die')(object, roomObjects, bulk, undefined, undefined, gameTime);
    }
    else if(object.hits != oldHits) {

        require('./_recalc-body')(object);

        if(object.hits < oldHits) {
            require('./_drop-resources-without-space')(object, roomObjects, roomTerrain, bulk);
        }

        bulk.update(object, {
            hits: object.hits,
            body: object.body,
            energyCapacity: object.energyCapacity
        });
    }
};<commit_msg>Fix creep death stats (#85)<commit_after>var _ = require('lodash'),
    utils = require('../../../utils'),
    driver = utils.getDriver(),
    C = driver.constants,
    movement = require('../movement');

function _applyDamage(object, damage) {

    let damageReduce = 0, damageEffective = damage;

    if(_.any(object.body, i => !!i.boost)) {
        for(let i=0; i<object.body.length; i++) {
            if(damageEffective <= 0) {
                break;
            }
            let bodyPart = object.body[i], damageRatio = 1;
            if(bodyPart.boost && C.BOOSTS[bodyPart.type][bodyPart.boost] && C.BOOSTS[bodyPart.type][bodyPart.boost].damage) {
                damageRatio = C.BOOSTS[bodyPart.type][bodyPart.boost].damage;
            }
            let bodyPartHitsEffective = bodyPart.hits / damageRatio;
            damageReduce += Math.min(bodyPartHitsEffective, damageEffective) * (1 - damageRatio);
            damageEffective -= Math.min(bodyPartHitsEffective, damageEffective);
        }
    }

    damage -= Math.round(damageReduce);

    object.hits -= damage;
}

module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime) {

    if(!object || object.type != 'creep') return;

    if(object.spawning) {
        var spawn = _.find(roomObjects, {type: 'spawn', x: object.x, y: object.y});
        if(!spawn) {
            bulk.remove(object._id);
        }
        else {
            if(!spawn.spawning || spawn.spawning.name != object.name) {
                require('../spawns/_born-creep')(spawn, object, roomObjects, roomTerrain, bulk, stats);
            }
        }
    }
    else {

        movement.execute(object, bulk, roomController, gameTime);

        if((object.x == 0 || object.y == 0 || object.x == 49 || object.y == 49) && object.user != '2' && object.user != '3') {

            var [roomX, roomY] = utils.roomNameToXY(object.room),
                x = object.x,
                y = object.y,
                room = object.room;

            if (object.x == 0) {
                x = 49;
                room = utils.getRoomNameFromXY(roomX-1, roomY);
            }
            else if (object.y == 0) {
                y = 49;
                room = utils.getRoomNameFromXY(roomX, roomY-1);
            }
            else if (object.x == 49) {
                x = 0;
                room = utils.getRoomNameFromXY(roomX+1, roomY);
            }
            else if (object.y == 49) {
                y = 0;
                room = utils.getRoomNameFromXY(roomX, roomY+1);
            }

            bulk.update(object, {interRoom: {room, x, y}});
        }

        if(object.ageTime) { // since NPC creeps may appear right on portals without `ageTime` defined at the first tick
            var portal = _.find(roomObjects, i => i.type == 'portal' && i.x == object.x && i.y == object.y);
            if (portal) {
                bulk.update(object, {interRoom: portal.destination});
            }
        }

        if(!object.tutorial) {
            if(!object.ageTime) {
                object.ageTime = gameTime + (_.any(object.body, {type: C.CLAIM}) ? C.CREEP_CLAIM_LIFE_TIME : C.CREEP_LIFE_TIME);
                bulk.update(object, {ageTime: object.ageTime});
            }

            if(gameTime >= object.ageTime-1) {
                require('./_die')(object, roomObjects, bulk, undefined, undefined, gameTime);
            }
        }

        if(!_.isEqual(object.actionLog, object._actionLog)) {
            bulk.update(object, {actionLog: object.actionLog});
        }

    }

    if(object.fatigue > 0) {
        var moves = utils.calcBodyEffectiveness(object.body, C.MOVE, 'fatigue', 1);

        object.fatigue -= moves * 2;

        if(object.fatigue < 0)
            object.fatigue = 0;

        bulk.update(object._id, {fatigue: object.fatigue});
    }

    if(_.isNaN(object.hits) || object.hits <= 0) {
        require('./_die')(object, roomObjects, bulk, stats, undefined, gameTime);
    }

    if(object.userSummoned && _.any(roomObjects, i => i.type == 'creep' && i.user != '2' && i.user != roomController.user)) {
        require('./_die')(object, roomObjects, bulk, stats, undefined, gameTime);
    }

    let oldHits = object.hits;

    if (object._damageToApply) {
        _applyDamage(object, object._damageToApply);
        delete object._damageToApply;
    }

    if (object._healToApply) {
        object.hits += object._healToApply;
        delete object._healToApply;
    }

    if(object.hits > object.hitsMax) {
        object.hits = object.hitsMax;
    }

    if(object.hits <= 0) {
        require('./_die')(object, roomObjects, bulk, stats, undefined, gameTime);
    }
    else if(object.hits != oldHits) {

        require('./_recalc-body')(object);

        if(object.hits < oldHits) {
            require('./_drop-resources-without-space')(object, roomObjects, roomTerrain, bulk);
        }

        bulk.update(object, {
            hits: object.hits,
            body: object.body,
            energyCapacity: object.energyCapacity
        });
    }
};<|endoftext|>