<commit_before>/**
 * Builder provides a fluent API for building a query.
 *
 * Since we'll be running the query on the server, we don't
 * really care about grammars or processors, or even the
 * breakdown of clauses and bindings. Instead, we'll just
 * record which methods are called and with what arguments.
 * This does mean the parameters in our function signatures
 * and docs are not as helpful as they might be - check the
 * Laravel documentation if any are unclear.
 */
export default class Builder {

    /**
     * Create a new Builder instance.
     *
     * @param {Transport} transport
     */
    constructor(transport) {

        if ( ! transport || typeof transport.get !== 'function') {
            throw new Error('Missing argument 1 for Builder, expected Transport');
        }

        /**
         * The transport class to send/receive the query/results.
         *
         * @protected
         * @type {Transport}
         */
        this.transport = transport;

        /**
         * The methods called for this query and their arguments.
         *
         * @protected
         * @type {Array[]}
         */
        this.stack = [];

        /**
         * The endpoint for this query, equivalent to the "table"
         * property in Laravel's Builder.
         *
         * @protected
         * @type {string|null}
         */
        this.endpoint = null;

        /**
         * The Model instance being queried
         *
         * @protected
         * @type {Model|null}
         */
        this._model = null;
    }

    /**
     * Add a method call to the stack.
     *
     * @protected
     * @param {string} name
     * @param {*[]} args
     * @returns {Builder}
     */
    _call(name, args) {
        this.stack.push([name, args]);
        return this;
    }

    /**
     * Set the endpoint for this query.
     *
     * @param {string} endpoint
     * @returns {Builder}
     */
    from(endpoint) {
        this.endpoint = endpoint;
        return this;
    }

    /**
     * Set the columns to be selected.
     *
     * @param {...string} columns
     * @returns {Builder}
     */
    select(...columns) {
        return this._call('select', columns);
    }

    /**
     * Add a new select column to the query.
     *
     * @param {...string} columns
     * @returns {Builder}
     */
    addSelect(...columns) {
        return this._call('addSelect', columns);
    }

    /**
     * Force the query to only return distinct results.
     *
     * @returns {Builder}
     */
    distinct() {
        return this._call('distinct', []);
    }

    /**
     * Add a "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    where(...args) {
        return this._call('where', args);
    }

    /**
     * Add a "or where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhere(...args) {
        return this._call('orWhere', args);
    }

    /**
     * Add a "where between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereBetween(...args) {
        return this._call('whereBetween', args);
    }

    /**
     * Add a "or where between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereBetween(...args) {
        return this._call('orWhereBetween', args);
    }

    /**
     * Add a "where not between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotBetween(...args) {
        return this._call('whereNotBetween', args);
    }

    /**
     * Add a "or where not between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotBetween(...args) {
        return this._call('orWhereNotBetween', args);
    }

    /**
     * Add a nested "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNested(...args) {
        return this._call('whereNested', args);
    }

    /**
     * Add a "where exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereExists(...args) {
        return this._call('whereExists', args);
    }

    /**
     * Add a "or where exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereExists(...args) {
        return this._call('orWhereExists', args);
    }

    /**
     * Add a "where not exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotExists(...args) {
        return this._call('whereNotExists', args);
    }

    /**
     * Add a "or where not exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotExists(...args) {
        return this._call('orWhereNotExists', args);
    }

    /**
     * Add a "where in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereIn(...args) {
        return this._call('whereIn', args);
    }

    /**
     * Add a "or where in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereIn(...args) {
        return this._call('orWhereIn', args);
    }

    /**
     * Add a "where not in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotIn(...args) {
        return this._call('whereNotIn', args);
    }

    /**
     * Add a "or where not in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotIn(...args) {
        return this._call('orWhereNotIn', args);
    }

    /**
     * Add a "where _ is null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNull(...args) {
        return this._call('whereNull', args);
    }

    /**
     * Add a "or where _ is null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNull(...args) {
        return this._call('orWhereNull', args);
    }

    /**
     * Add a "where _ is not null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotNull(...args) {
        return this._call('whereNotNull', args);
    }

    /**
     * Add a "or where _ is not null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotNull(...args) {
        return this._call('orWhereNotNull', args);
    }

    /**
     * Add a date "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereDate(...args) {
        return this._call('whereDate', args);
    }

    /**
     * Add a day "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereDay(...args) {
        return this._call('whereDay', args);
    }

    /**
     * Add a month "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereMonth(...args) {
        return this._call('whereMonth', args);
    }

    /**
     * Add a year "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereYear(...args) {
        return this._call('whereYear', args);
    }

    /**
     * Add a "group by" clause to the query.
     *
     * @param {...string} columns
     * @returns {Builder}
     */
    groupBy(...columns) {
        return this._call('groupBy', columns);
    }

    /**
     * Add a "having" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    having(...args) {
        return this._call('having', args);
    }

    /**
     * Add a "or having" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orHaving(...args) {
        return this._call('orHaving', args);
    }

    /**
     * Add a "order by" clause to the query.
     *
     * @param {...string} order
     * @returns {Builder}
     */
    orderBy(...order) {
        return this._call('orderBy', order);
    }

    /**
     * Add a "order by" latest date clause to the query.
     *
     * @param {string} [order='created_at']
     * @returns {Builder}
     */
    latest(order) {
        return this._call('latest', order ? [order] : []);
    }

    /**
     * Add an "order by" oldest date clause to the query.
     *
     * @param {string} [order='created_at']
     * @returns {Builder}
     */
    oldest(order) {
        return this._call('oldest', order ? [order] : []);
    }

    /**
     * Set the "offset" value of the query.
     *
     * @param {number} offset
     * @returns {Builder}
     */
    offset(offset) {
        return this._call('offset', [offset]);
    }

    /**
     * Set the "offset" value of the query.
     *
     * @param {number} skip
     * @returns {Builder}
     */
    skip(skip) {
        return this._call('skip', [skip]);
    }

    /**
     * Set the "limit" value of the query.
     *
     * @param {number} limit
     * @returns {Builder}
     */
    limit(limit) {
        return this._call('limit', [limit]);
    }

    /**
     * Set the "limit" value of the query.
     *
     * @param {number} take
     * @returns {Builder}
     */
    take(take) {
        return this._call('take', [take]);
    }

    /**
     * Set the "limit" and "offset" for a given page.
     *
     * @param {...number} forPage
     * @returns {Builder}
     */
    forPage(...forPage) {
        return this._call('forPage', forPage);
    }

    /**
     * Set the relationships that should be eager loaded.
     *
     * @param {string[]} relations
     * @returns {EloquentBuilder}
     */
    with(...relations) {
        this._call('with', relations);
        return this;
    }

    /**
     * Find a model by its primary key.
     *
     * @param {number}   id
     * @param {string[]} [columns] the columns to fetch
     * @returns {Promise}
     */
    find(id, columns) {
        if (Array.isArray(id)) {
            return this.findMany(id, columns);
        }

        return this.from(this.getEndpoint(id)).getOne();
    }

    /**
     * Find many models by their primary key.
     *
     * @param {number[]} ids
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    findMany(ids, columns) {
        return this.whereIn(this._model.getKeyName(), ids).get(columns);
    }

    /**
     * Find a model by its primary key or throw an exception.
     *
     * @param {number}   id
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    findOrFail(id, columns) {
        return this.find(id, columns).then(throwIfNotFound);
    }

    /**
     * Execute the query and get the first result.
     *
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    first(columns) {
        return this.limit(1).get(columns).then(unwrapFirst);
    }

    /**
     * Execute the query and get the first result or throw an exception.
     *
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    firstOrFail(columns) {
        return this.first(columns).then(throwIfNotFound);
    }

    /**
     * Get a single column's value from the first result of a query.
     *
     * @param {string} column
     * @returns {Promise}
     */
    value(column) {
        return this.first(column).then(function (result) {
            return result[column];
        });
    }

    /**
     * Get an array with the values of a given column.
     *
     * @param {string} column
     * @returns {Promise}
     */
    lists(column) {
        return this.get(column).then(function (results) {
            return results.map(function (result) {
                return result[column];
            });
        });
    }

    /**
     * Add a scope call to the query.
     *
     * @param {string} scopeName
     * @param {*[]} scopeArgs
     * @returns {EloquentBuilder}
     */
    scope(scopeName, scopeArgs) {
        let args = [scopeName];

        if (scopeArgs) {
            args.push(scopeArgs);
        }

        this._call('scope', args);
        return this;
    }

    /**
     * Execute the query and return a promise that resolves with an array of models.
     *
     * @param {string|string[]} [columns]
     * @returns {Promise}
     */
    get(columns) {
        if (columns) {
            this.select(columns);
        }

        return this.transport.get(this.getEndpoint(), this.stack)
            .then(results => this._model.hydrate(results));
    }

    /**
     * Execute the query and return a promise that resolves with a single result.
     *
     * @param  {string|string[]} [columns]
     * @return {Promise}
     */
    getOne(columns) {
        if (columns) {
            this.select(columns);
        }

        return this.transport.get(this.getEndpoint(), this.stack)
            .then(result => {
                if ( ! result) {
                    return null;
                }

                return this._model.newInstance(result);
            });
    }

    /**
     * Insert a new record into the database.
     *
     * @param values
     * @returns {Promise}
     */
    insert(values) {
        return this.transport.post(this.getEndpoint(), values);
    }

    /**
     * Execute the query as an "update" statement.
     *
     * There are two ways of running an update - on an existing
     * model, e.g. `post.update()`, or via the query builder, e.g.
     * `Post.where(...).update()`.
     *
     * The former is straightforward to implement. We can simply set
     * up our RESTful controller in Laravel and make a PUT request to
     * /resource/{id}. The latter is more complex because we don't have
     * an ID.
     *
     * To support this, we use `*` in place of the ID to refer to all models.
     * The various query clauses can then be sent to the server in
     * just the same way as we would do for a GET, i.e. in URL's query
     * string.
     *
     * @param  {object} values
     * @return {Promise}
     */
    update(values) {
        return this.transport.put(this.getEndpoint(this._model.getKey() || '*'), values, this.stack);
    }

    /**
     * Execute the query as a "delete" statement.
     *
     * See comments on update() - similar situation here.
     *
     * @return {Promise}
     */
    delete() {
        return this.transport.delete(this.getEndpoint(this._model.getKey() || '*'), this.stack);
    }

    /**
     * Get the endpoint for the query.
     *
     * @param {boolean} [withId] append a model ID to the endpoint
     * @returns {string|null}
     * @throws {Error} when endpoint is not set
     */
    getEndpoint(key) {
        if ( ! this.endpoint) {
            throw new Error('Endpoint is required but is not set.');
        }

        if (key) {
            return this.endpoint + '/' + key;
        }

        return this.endpoint;
    }

    /**
     * The Model instance being queried
     *
     * @protected
     * @return {Model} model
     */
    _getModel() {
        return this._model;
    }

    /**
     * The Model instance being queried
     *
     * @protected
     * @param {Model} model
     * @returns {void}
     */
    _setModel(model) {
        this._model = model;
        this.from(model.definition.endpoint);

        // Laravel uses the PHP __call magic to refer back to the
        // underlying model instance to handle any scope calls.
        // Since we can't do that (yet), we'll settle for simply
        // copying the scope methods from the model at runtime.
        (model.definition.scopes || []).forEach(name => {
            this[name] = function (...args) {
                this.scope(name, args);
                return this;
            };
        });
    }
};

function unwrapFirst(results)
{
    return results[0] ? results[0] : null;
}

function throwIfNotFound(result)
{
    if (result === null) {
        throw new Error('ModelNotFoundException');
    }

    return result;
}
<commit_msg>Correct return type in docblock<commit_after>/**
 * Builder provides a fluent API for building a query.
 *
 * Since we'll be running the query on the server, we don't
 * really care about grammars or processors, or even the
 * breakdown of clauses and bindings. Instead, we'll just
 * record which methods are called and with what arguments.
 * This does mean the parameters in our function signatures
 * and docs are not as helpful as they might be - check the
 * Laravel documentation if any are unclear.
 */
export default class Builder {

    /**
     * Create a new Builder instance.
     *
     * @param {Transport} transport
     */
    constructor(transport) {

        if ( ! transport || typeof transport.get !== 'function') {
            throw new Error('Missing argument 1 for Builder, expected Transport');
        }

        /**
         * The transport class to send/receive the query/results.
         *
         * @protected
         * @type {Transport}
         */
        this.transport = transport;

        /**
         * The methods called for this query and their arguments.
         *
         * @protected
         * @type {Array[]}
         */
        this.stack = [];

        /**
         * The endpoint for this query, equivalent to the "table"
         * property in Laravel's Builder.
         *
         * @protected
         * @type {string|null}
         */
        this.endpoint = null;

        /**
         * The Model instance being queried
         *
         * @protected
         * @type {Model|null}
         */
        this._model = null;
    }

    /**
     * Add a method call to the stack.
     *
     * @protected
     * @param {string} name
     * @param {*[]} args
     * @returns {Builder}
     */
    _call(name, args) {
        this.stack.push([name, args]);
        return this;
    }

    /**
     * Set the endpoint for this query.
     *
     * @param {string} endpoint
     * @returns {Builder}
     */
    from(endpoint) {
        this.endpoint = endpoint;
        return this;
    }

    /**
     * Set the columns to be selected.
     *
     * @param {...string} columns
     * @returns {Builder}
     */
    select(...columns) {
        return this._call('select', columns);
    }

    /**
     * Add a new select column to the query.
     *
     * @param {...string} columns
     * @returns {Builder}
     */
    addSelect(...columns) {
        return this._call('addSelect', columns);
    }

    /**
     * Force the query to only return distinct results.
     *
     * @returns {Builder}
     */
    distinct() {
        return this._call('distinct', []);
    }

    /**
     * Add a "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    where(...args) {
        return this._call('where', args);
    }

    /**
     * Add a "or where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhere(...args) {
        return this._call('orWhere', args);
    }

    /**
     * Add a "where between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereBetween(...args) {
        return this._call('whereBetween', args);
    }

    /**
     * Add a "or where between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereBetween(...args) {
        return this._call('orWhereBetween', args);
    }

    /**
     * Add a "where not between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotBetween(...args) {
        return this._call('whereNotBetween', args);
    }

    /**
     * Add a "or where not between" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotBetween(...args) {
        return this._call('orWhereNotBetween', args);
    }

    /**
     * Add a nested "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNested(...args) {
        return this._call('whereNested', args);
    }

    /**
     * Add a "where exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereExists(...args) {
        return this._call('whereExists', args);
    }

    /**
     * Add a "or where exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereExists(...args) {
        return this._call('orWhereExists', args);
    }

    /**
     * Add a "where not exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotExists(...args) {
        return this._call('whereNotExists', args);
    }

    /**
     * Add a "or where not exists" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotExists(...args) {
        return this._call('orWhereNotExists', args);
    }

    /**
     * Add a "where in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereIn(...args) {
        return this._call('whereIn', args);
    }

    /**
     * Add a "or where in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereIn(...args) {
        return this._call('orWhereIn', args);
    }

    /**
     * Add a "where not in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotIn(...args) {
        return this._call('whereNotIn', args);
    }

    /**
     * Add a "or where not in" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotIn(...args) {
        return this._call('orWhereNotIn', args);
    }

    /**
     * Add a "where _ is null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNull(...args) {
        return this._call('whereNull', args);
    }

    /**
     * Add a "or where _ is null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNull(...args) {
        return this._call('orWhereNull', args);
    }

    /**
     * Add a "where _ is not null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereNotNull(...args) {
        return this._call('whereNotNull', args);
    }

    /**
     * Add a "or where _ is not null" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orWhereNotNull(...args) {
        return this._call('orWhereNotNull', args);
    }

    /**
     * Add a date "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereDate(...args) {
        return this._call('whereDate', args);
    }

    /**
     * Add a day "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereDay(...args) {
        return this._call('whereDay', args);
    }

    /**
     * Add a month "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereMonth(...args) {
        return this._call('whereMonth', args);
    }

    /**
     * Add a year "where" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    whereYear(...args) {
        return this._call('whereYear', args);
    }

    /**
     * Add a "group by" clause to the query.
     *
     * @param {...string} columns
     * @returns {Builder}
     */
    groupBy(...columns) {
        return this._call('groupBy', columns);
    }

    /**
     * Add a "having" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    having(...args) {
        return this._call('having', args);
    }

    /**
     * Add a "or having" clause to the query.
     *
     * @param {...*} args
     * @returns {Builder}
     */
    orHaving(...args) {
        return this._call('orHaving', args);
    }

    /**
     * Add a "order by" clause to the query.
     *
     * @param {...string} order
     * @returns {Builder}
     */
    orderBy(...order) {
        return this._call('orderBy', order);
    }

    /**
     * Add a "order by" latest date clause to the query.
     *
     * @param {string} [order='created_at']
     * @returns {Builder}
     */
    latest(order) {
        return this._call('latest', order ? [order] : []);
    }

    /**
     * Add an "order by" oldest date clause to the query.
     *
     * @param {string} [order='created_at']
     * @returns {Builder}
     */
    oldest(order) {
        return this._call('oldest', order ? [order] : []);
    }

    /**
     * Set the "offset" value of the query.
     *
     * @param {number} offset
     * @returns {Builder}
     */
    offset(offset) {
        return this._call('offset', [offset]);
    }

    /**
     * Set the "offset" value of the query.
     *
     * @param {number} skip
     * @returns {Builder}
     */
    skip(skip) {
        return this._call('skip', [skip]);
    }

    /**
     * Set the "limit" value of the query.
     *
     * @param {number} limit
     * @returns {Builder}
     */
    limit(limit) {
        return this._call('limit', [limit]);
    }

    /**
     * Set the "limit" value of the query.
     *
     * @param {number} take
     * @returns {Builder}
     */
    take(take) {
        return this._call('take', [take]);
    }

    /**
     * Set the "limit" and "offset" for a given page.
     *
     * @param {...number} forPage
     * @returns {Builder}
     */
    forPage(...forPage) {
        return this._call('forPage', forPage);
    }

    /**
     * Set the relationships that should be eager loaded.
     *
     * @param {string[]} relations
     * @returns {Builder}
     */
    with(...relations) {
        this._call('with', relations);
        return this;
    }

    /**
     * Find a model by its primary key.
     *
     * @param {number}   id
     * @param {string[]} [columns] the columns to fetch
     * @returns {Promise}
     */
    find(id, columns) {
        if (Array.isArray(id)) {
            return this.findMany(id, columns);
        }

        return this.from(this.getEndpoint(id)).getOne();
    }

    /**
     * Find many models by their primary key.
     *
     * @param {number[]} ids
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    findMany(ids, columns) {
        return this.whereIn(this._model.getKeyName(), ids).get(columns);
    }

    /**
     * Find a model by its primary key or throw an exception.
     *
     * @param {number}   id
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    findOrFail(id, columns) {
        return this.find(id, columns).then(throwIfNotFound);
    }

    /**
     * Execute the query and get the first result.
     *
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    first(columns) {
        return this.limit(1).get(columns).then(unwrapFirst);
    }

    /**
     * Execute the query and get the first result or throw an exception.
     *
     * @param {string[]} [columns]
     * @returns {Promise}
     */
    firstOrFail(columns) {
        return this.first(columns).then(throwIfNotFound);
    }

    /**
     * Get a single column's value from the first result of a query.
     *
     * @param {string} column
     * @returns {Promise}
     */
    value(column) {
        return this.first(column).then(function (result) {
            return result[column];
        });
    }

    /**
     * Get an array with the values of a given column.
     *
     * @param {string} column
     * @returns {Promise}
     */
    lists(column) {
        return this.get(column).then(function (results) {
            return results.map(function (result) {
                return result[column];
            });
        });
    }

    /**
     * Add a scope call to the query.
     *
     * @param {string} scopeName
     * @param {*[]} scopeArgs
     * @returns {EloquentBuilder}
     */
    scope(scopeName, scopeArgs) {
        let args = [scopeName];

        if (scopeArgs) {
            args.push(scopeArgs);
        }

        this._call('scope', args);
        return this;
    }

    /**
     * Execute the query and return a promise that resolves with an array of models.
     *
     * @param {string|string[]} [columns]
     * @returns {Promise}
     */
    get(columns) {
        if (columns) {
            this.select(columns);
        }

        return this.transport.get(this.getEndpoint(), this.stack)
            .then(results => this._model.hydrate(results));
    }

    /**
     * Execute the query and return a promise that resolves with a single result.
     *
     * @param  {string|string[]} [columns]
     * @return {Promise}
     */
    getOne(columns) {
        if (columns) {
            this.select(columns);
        }

        return this.transport.get(this.getEndpoint(), this.stack)
            .then(result => {
                if ( ! result) {
                    return null;
                }

                return this._model.newInstance(result);
            });
    }

    /**
     * Insert a new record into the database.
     *
     * @param values
     * @returns {Promise}
     */
    insert(values) {
        return this.transport.post(this.getEndpoint(), values);
    }

    /**
     * Execute the query as an "update" statement.
     *
     * There are two ways of running an update - on an existing
     * model, e.g. `post.update()`, or via the query builder, e.g.
     * `Post.where(...).update()`.
     *
     * The former is straightforward to implement. We can simply set
     * up our RESTful controller in Laravel and make a PUT request to
     * /resource/{id}. The latter is more complex because we don't have
     * an ID.
     *
     * To support this, we use `*` in place of the ID to refer to all models.
     * The various query clauses can then be sent to the server in
     * just the same way as we would do for a GET, i.e. in URL's query
     * string.
     *
     * @param  {object} values
     * @return {Promise}
     */
    update(values) {
        return this.transport.put(this.getEndpoint(this._model.getKey() || '*'), values, this.stack);
    }

    /**
     * Execute the query as a "delete" statement.
     *
     * See comments on update() - similar situation here.
     *
     * @return {Promise}
     */
    delete() {
        return this.transport.delete(this.getEndpoint(this._model.getKey() || '*'), this.stack);
    }

    /**
     * Get the endpoint for the query.
     *
     * @param {boolean} [withId] append a model ID to the endpoint
     * @returns {string|null}
     * @throws {Error} when endpoint is not set
     */
    getEndpoint(key) {
        if ( ! this.endpoint) {
            throw new Error('Endpoint is required but is not set.');
        }

        if (key) {
            return this.endpoint + '/' + key;
        }

        return this.endpoint;
    }

    /**
     * The Model instance being queried
     *
     * @protected
     * @return {Model} model
     */
    _getModel() {
        return this._model;
    }

    /**
     * The Model instance being queried
     *
     * @protected
     * @param {Model} model
     * @returns {void}
     */
    _setModel(model) {
        this._model = model;
        this.from(model.definition.endpoint);

        // Laravel uses the PHP __call magic to refer back to the
        // underlying model instance to handle any scope calls.
        // Since we can't do that (yet), we'll settle for simply
        // copying the scope methods from the model at runtime.
        (model.definition.scopes || []).forEach(name => {
            this[name] = function (...args) {
                this.scope(name, args);
                return this;
            };
        });
    }
};

function unwrapFirst(results)
{
    return results[0] ? results[0] : null;
}

function throwIfNotFound(result)
{
    if (result === null) {
        throw new Error('ModelNotFoundException');
    }

    return result;
}
<|endoftext|>


<commit_before>/**
 * toast提示
 *
 * Created by GUY on 2015/9/7.
 * @class BI.Toast
 * @extends BI.Tip
 */
BI.Toast = BI.inherit(BI.Tip, {
    _const: {
        minWidth: 200,
        hgap: 10
    },

    _defaultConfig: function () {
        return BI.extend(BI.Toast.superclass._defaultConfig.apply(this, arguments), {
            extraCls: "bi-toast",
            text: "",
            level: "success" // success或warning
        });
    },

    render: function () {
        var self = this, o = this.options;
        this.element.css({
            minWidth: this._const.minWidth / BI.pixRatio + BI.pixUnit
        });
        this.element.addClass("toast-" + o.level);
        var fn = function (e) {
            e.stopPropagation();
            e.stopEvent();
            return false;
        };
        this.element.bind({
            click: fn,
            mousedown: fn,
            mouseup: fn,
            mouseover: fn,
            mouseenter: fn,
            mouseleave: fn,
            mousemove: fn
        });
        var cls = "close-font";
        switch (o.level) {
            case "success":
                cls = "toast-success-font";
                break;
            case "error":
                cls = "toast-error-font";
                break;
            case "warning":
                cls = "toast-warning-font";
                break;
            case "normal":
            default:
                cls = "toast-message-font";
                break;
        }

        var items = [{
            type: "bi.icon_label",
            cls: cls + " toast-icon",
            width: 36
        }, {
            el: BI.isString(o.text) ? {
                type: "bi.label",
                whiteSpace: "normal",
                text: o.text,
                textHeight: 16,
                textAlign: "left"
            } : o.text,
            rgap: o.autoClose ? this._const.hgap : 0
        }];

        var columnSize = [36, "fill"];

        if (o.autoClose === false) {
            items.push({
                type: "bi.icon_button",
                cls: "close-font toast-icon",
                handler: function () {
                    self.destroy();
                },
                width: 36
            });
            columnSize.push(36);
        }

        this.text = BI.createWidget({
            type: "bi.horizontal",
            horizontalAlign: BI.HorizontalAlign.Stretch,
            element: this,
            items: items,
            vgap: 7,
            columnSize: columnSize
        });
    },

    setText: function (text) {
        this.text.setText(text);
    },

    beforeDestroy: function () {
        this.fireEvent(BI.Toast.EVENT_DESTORY);
    }
});
BI.Toast.EVENT_DESTORY = "EVENT_DESTORY";
BI.shortcut("bi.toast", BI.Toast);
<commit_msg>Pull request #2281: BI-96759 支持自定义text<commit_after>/**
 * toast提示
 *
 * Created by GUY on 2015/9/7.
 * @class BI.Toast
 * @extends BI.Tip
 */
BI.Toast = BI.inherit(BI.Tip, {
    _const: {
        minWidth: 200,
        hgap: 10
    },

    _defaultConfig: function () {
        return BI.extend(BI.Toast.superclass._defaultConfig.apply(this, arguments), {
            extraCls: "bi-toast",
            text: "",
            level: "success" // success或warning
        });
    },

    render: function () {
        var self = this, o = this.options;
        this.element.css({
            minWidth: this._const.minWidth / BI.pixRatio + BI.pixUnit
        });
        this.element.addClass("toast-" + o.level);
        var fn = function (e) {
            e.stopPropagation();
            e.stopEvent();
            return false;
        };
        this.element.bind({
            click: fn,
            mousedown: fn,
            mouseup: fn,
            mouseover: fn,
            mouseenter: fn,
            mouseleave: fn,
            mousemove: fn
        });
        var cls = "close-font";
        switch (o.level) {
            case "success":
                cls = "toast-success-font";
                break;
            case "error":
                cls = "toast-error-font";
                break;
            case "warning":
                cls = "toast-warning-font";
                break;
            case "normal":
            default:
                cls = "toast-message-font";
                break;
        }

        var items = [{
            type: "bi.icon_label",
            cls: cls + " toast-icon",
            width: 36
        }, {
            el: BI.isPlainObject(o.text) ? o.text : {
                type: "bi.label",
                whiteSpace: "normal",
                text: o.text,
                textHeight: 16,
                textAlign: "left"
            },
            rgap: o.autoClose ? this._const.hgap : 0
        }];

        var columnSize = [36, "fill"];

        if (o.autoClose === false) {
            items.push({
                type: "bi.icon_button",
                cls: "close-font toast-icon",
                handler: function () {
                    self.destroy();
                },
                width: 36
            });
            columnSize.push(36);
        }

        this.text = BI.createWidget({
            type: "bi.horizontal",
            horizontalAlign: BI.HorizontalAlign.Stretch,
            element: this,
            items: items,
            vgap: 7,
            columnSize: columnSize
        });
    },

    setText: function (text) {
        this.text.setText(text);
    },

    beforeDestroy: function () {
        this.fireEvent(BI.Toast.EVENT_DESTORY);
    }
});
BI.Toast.EVENT_DESTORY = "EVENT_DESTORY";
BI.shortcut("bi.toast", BI.Toast);
<|endoftext|>


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

  // From Sizzle
  //   https://github.com/jquery/sizzle/blob/master/sizzle.js
  var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g;
  var match = {
    ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g,
    CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g,
    TAG: /^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g,
    ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/g,
    PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/g
  };

  // Internal: Parse CSS selector into parts.
  //
  // Adopted from Sizzle.
  //
  // selector - CSS selector String.
  //
  // Returns an Array of Strings.
  function parse(selector) {
    var m, rest = selector, parts = [];

    do {
      chunker.exec("");
      if (m = chunker.exec(rest)) {
        rest = m[3];
        parts.push(m[1]);
        if (m[2]) {
          break;
        }
      }
    } while (m);

    return parts;
  }

  // Internal: Compute the specificity of a selector.
  //
  // parts - Parsed selector Array.
  //
  // Returns an 3 tuple Array of Numbers.
  function computeSpecificity(parts) {
    var a = 0, b = 0, c = 0;

    var part, m, i, len;
    for (i = 0, len = parts.length; i < len; i++) {
      part = parts[i];

      if (m = part.match(match.ID)) a += m.length;
      if (m = part.match(match.ATTR)) b += m.length;
      if (m = part.match(match.CLASS)) b += m.length;
      if (m = part.match(match.TAG)) c += m.length;
      if (m = part.match(match.PSEUDO)) c += m.length;
    }

    return [a, b, c];
  }

  // Internal: Determine the primary category and key of a selector.
  //
  // Attempts to mirror WebKit's RuleSet::addRule rule set mappings.
  // https://github.com/WebKit/webkit/blob/master/Source/WebCore/css/StyleResolver.cpp
  //
  // parts - Parsed selector Array.
  //
  // Returns a pair with first 'id', 'class', 'tag', or 'universal'.
  // Then a String key value
  function detectCategoryAndKey(parts) {
    var m, last = parts[parts.length-1];
    if (!last) {
      return ['universal', '*'];
    } else if (m = last.match(match.ID)) {
      return ['id', m[0].slice(1)];
    } else if (m = last.match(match.CLASS)) {
      return ['class', m[0].slice(1)];
    } else if (m = last.match(match.TAG)) {
      return ['tag', m[0]];
    } else {
      return ['universal', '*'];
    }
  }

  // Internal: Analyze and score the selector efficiency.
  //
  // 1 being the most efficient and 10 being the least.
  //
  // parts - Parsed selector Array.
  //
  // Returns an Object with a score, Number 1 through 10 and
  // an Array of reason strings.
  function analyze(parts) {
    var last = parts[parts.length-1];
    var score = 1;
    var messages = [];

    if (!last) {
    }

    // ID category
    else if (last.match(match.ID)) {
      // Check for redundant class name
      if (last.match(match.CLASS)) {
        messages.push("ID is overly qualified by a class name");
        score++;
      }

      // Check for redundant tag name
      if (last.match(match.TAG)) {
        messages.push("ID is overly qualified by a tag name");
        score++;
      }

      // Check for redundant descendant selectors
      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("ID is overly qualified by a child selector");
          score++;
        } else {
          messages.push("ID is overly qualified by a descendant selector");
          score++;
        }
      }
    }

    // Class category
    else if (last.match(match.CLASS)) {
      score += 1;

      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("Uses a child selector with a rightmost class selector");
          score += 2;
        } else {
          messages.push("Uses a descendant selector with a rightmost class selector");
          score += 4;
        }
      }
    }

    // Tag category
    else if (last.match(match.TAG)) {
      score += 2;

      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("Uses a child selector with a rightmost tag selector");
          score += 4;
        } else {
          messages.push("Uses a descendant selector with a rightmost tag selector");
          score += 5;
        }
      }
    }

    // Universal category
    else {
      score += 3;

      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("Uses a child selector with a rightmost universal selector");
          score += 5;
        } else {
          messages.push("Uses a descendant selector with a rightmost universal selector");
          score += 6;
        }
      }
    }

    if (score < 1 || score > 10) {
      throw "score out of range";
    }

    return {score: score, messages: messages};
  }

  // Public: Explains a CSS selector.
  //
  // selector - CSS selector String.
  //
  // Returns an Object.
  function cssExplainSelector(selector) {
    var parts       = parse(selector);
    var specificity = computeSpecificity(parts);
    var category    = detectCategoryAndKey(parts);
    var analysis    = analyze(parts);

    return {
      selector: selector,
      parts: parts,
      category: category[0],
      key: category[1],
      specificity: specificity,
      score: analysis.score,
      messages: analysis.messages
    };
  }

  // Public: Explains a CSS selector.
  //
  // selector - CSS selector String.
  // multiple - Boolean to allow multiple rules
  //
  // Returns an Object.
  function cssExplain(selector, multiple) {
    if (multiple === false) {
      return cssExplain(selector, true)[0];
    } else if (typeof selector == 'object' && 'length' in selector) {
      var i, results = [];
      for (i = 0; i < selector.length; i++) {
        results = results.concat(cssExplain(selector[i], true));
      }
      return results;
    } else if (typeof selector === 'string') {
      if (selector.match(/,/)) {
        return cssExplain(selector.split(/\s*,\s*/), multiple || false);
      } else {
        return cssExplainSelector(selector);
      }
    } else {
      throw "unknown selector type";
    }
  }

  function cssExplainStyleSheets() {
    var rules, i, j, results = [];

    for (i = 0; i < document.styleSheets.length; i++) {
      rules = document.styleSheets[i].cssRules;
      if (!rules) continue;

      for (j = 0; j < rules.length; j++) {
        results = results.concat(cssExplain(rules[j].selectorText, true));
      }
    }

    return results;
  }

  if (typeof exports !== 'undefined') {
    exports.cssExplain = cssExplain;
  } else {
    window.cssExplain = cssExplain;
    window.cssExplainStyleSheets = cssExplainStyleSheets;
  }
})();
<commit_msg>Support css rule objects as selector inputs<commit_after>(function() {
  "use strict";

  // From Sizzle
  //   https://github.com/jquery/sizzle/blob/master/sizzle.js
  var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g;
  var match = {
    ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g,
    CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g,
    TAG: /^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g,
    ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/g,
    PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/g
  };

  // Internal: Parse CSS selector into parts.
  //
  // Adopted from Sizzle.
  //
  // selector - CSS selector String.
  //
  // Returns an Array of Strings.
  function parse(selector) {
    var m, rest = selector, parts = [];

    do {
      chunker.exec("");
      if (m = chunker.exec(rest)) {
        rest = m[3];
        parts.push(m[1]);
        if (m[2]) {
          break;
        }
      }
    } while (m);

    return parts;
  }

  // Internal: Compute the specificity of a selector.
  //
  // parts - Parsed selector Array.
  //
  // Returns an 3 tuple Array of Numbers.
  function computeSpecificity(parts) {
    var a = 0, b = 0, c = 0;

    var part, m, i, len;
    for (i = 0, len = parts.length; i < len; i++) {
      part = parts[i];

      if (m = part.match(match.ID)) a += m.length;
      if (m = part.match(match.ATTR)) b += m.length;
      if (m = part.match(match.CLASS)) b += m.length;
      if (m = part.match(match.TAG)) c += m.length;
      if (m = part.match(match.PSEUDO)) c += m.length;
    }

    return [a, b, c];
  }

  // Internal: Determine the primary category and key of a selector.
  //
  // Attempts to mirror WebKit's RuleSet::addRule rule set mappings.
  // https://github.com/WebKit/webkit/blob/master/Source/WebCore/css/StyleResolver.cpp
  //
  // parts - Parsed selector Array.
  //
  // Returns a pair with first 'id', 'class', 'tag', or 'universal'.
  // Then a String key value
  function detectCategoryAndKey(parts) {
    var m, last = parts[parts.length-1];
    if (!last) {
      return ['universal', '*'];
    } else if (m = last.match(match.ID)) {
      return ['id', m[0].slice(1)];
    } else if (m = last.match(match.CLASS)) {
      return ['class', m[0].slice(1)];
    } else if (m = last.match(match.TAG)) {
      return ['tag', m[0]];
    } else {
      return ['universal', '*'];
    }
  }

  // Internal: Analyze and score the selector efficiency.
  //
  // 1 being the most efficient and 10 being the least.
  //
  // parts - Parsed selector Array.
  //
  // Returns an Object with a score, Number 1 through 10 and
  // an Array of reason strings.
  function analyze(parts) {
    var last = parts[parts.length-1];
    var score = 1;
    var messages = [];

    if (!last) {
    }

    // ID category
    else if (last.match(match.ID)) {
      // Check for redundant class name
      if (last.match(match.CLASS)) {
        messages.push("ID is overly qualified by a class name");
        score++;
      }

      // Check for redundant tag name
      if (last.match(match.TAG)) {
        messages.push("ID is overly qualified by a tag name");
        score++;
      }

      // Check for redundant descendant selectors
      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("ID is overly qualified by a child selector");
          score++;
        } else {
          messages.push("ID is overly qualified by a descendant selector");
          score++;
        }
      }
    }

    // Class category
    else if (last.match(match.CLASS)) {
      score += 1;

      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("Uses a child selector with a rightmost class selector");
          score += 2;
        } else {
          messages.push("Uses a descendant selector with a rightmost class selector");
          score += 4;
        }
      }
    }

    // Tag category
    else if (last.match(match.TAG)) {
      score += 2;

      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("Uses a child selector with a rightmost tag selector");
          score += 4;
        } else {
          messages.push("Uses a descendant selector with a rightmost tag selector");
          score += 5;
        }
      }
    }

    // Universal category
    else {
      score += 3;

      if (parts.length > 1) {
        if (parts[parts.length-2] === '>') {
          messages.push("Uses a child selector with a rightmost universal selector");
          score += 5;
        } else {
          messages.push("Uses a descendant selector with a rightmost universal selector");
          score += 6;
        }
      }
    }

    if (score < 1 || score > 10) {
      throw "score out of range";
    }

    return {score: score, messages: messages};
  }

  // Public: Explains a CSS selector.
  //
  // selector - CSS selector String.
  //
  // Returns an Object.
  function cssExplainSelector(selector) {
    var parts       = parse(selector);
    var specificity = computeSpecificity(parts);
    var category    = detectCategoryAndKey(parts);
    var analysis    = analyze(parts);

    return {
      selector: selector,
      parts: parts,
      category: category[0],
      key: category[1],
      specificity: specificity,
      score: analysis.score,
      messages: analysis.messages
    };
  }

  // Public: Explains a CSS selector.
  //
  // obj      - CSS selector String.
  // multiple - Boolean to return multiple rules results.
  //
  // Returns an Object.
  function cssExplain(obj, multiple) {
    if (multiple === false) {
      return cssExplain(obj, true)[0];
    } else if (typeof obj == 'object' && 'length' in obj) {
      var i, results = [];
      for (i = 0; i < obj.length; i++) {
        results = results.concat(cssExplain(obj[i], true));
      }
      return results;
    } else if (typeof obj == 'object' && 'cssRules' in obj) {
      return cssExplain(obj.cssRules, multiple);
    } else if (typeof obj == 'object' && 'selectorText' in obj) {
      return cssExplain(obj.selectorText, multiple);
    } else if (typeof obj === 'string') {
      if (obj.match(/,/)) {
        return cssExplain(obj.split(/\s*,\s*/), multiple || false);
      } else {
        return cssExplainSelector(obj);
      }
    } else {
      throw "unknown selector type";
    }
  }

  if (typeof exports !== 'undefined') {
    exports.cssExplain = cssExplain;
  } else {
    window.cssExplain = cssExplain;
  }
})();
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var result = require('./result');
var orm = require('orm');
var multiparty = require('multiparty');
var util = require('util');
var fs = require('fs');
//Todo
var source_url = {check: '/gakf/addCheck.html', review: '/gakf/sickDetail.html'};
var target_url = {check: '/gakf/check.html', review: '/gakf/flowSick.html'};

//根据ID获取医生信息
router.get('/info', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    req.models.doctor.get(doctor_id, function (err, item) {
        if (err || !item) {
            res.json(result(false, err.msg, {}));
        } else {
            res.json(result(true, '', item));
        }
    });
});

//获取出院的病人
router.get('/out_sicks', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    if (!doctor_id) {
        res.json(result(false, 'no doctor_id', {}));
        return;
    }
    var sick_array = [];
    req.models.sick.find({
        doctor_id: doctor_id,
        out_day: orm.lte(new Date())
    }, function (err, data) {
        if (err || !data) {
            console.error(err);
            res.json(result(false, '', {}));
        } else {
            for (var i = 0; i< data.length; i++) {
                data[i].out_dur = data[i].out_duration();
                sick_array.push(data[i]);
            }
            req.models.sick.find({
                doctor_id : doctor_id,
                in_day: orm.gt(new Date())
            }, function(err, data2) {
                if (err || !data) {
                    res.json(result(true, '', sick_array));
                } else {
                    for (var i = 0; i < data2.length; i++) {
                        data2[i].out_dur = 0;
                        sick_array.push(data2[i]);
                    }
                    res.json(result(true, '', sick_array));
                }
            });

        }
    });
});

//获取入院的病人
router.get('/in_sicks', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    if (!doctor_id) {
        res.json(result(false, 'no doctor_id', {}));
        return;
    }
    req.models.sick.find({
        doctor_id: doctor_id,
        in_day: orm.lte(new Date()),
        out_day: orm.gte(new Date())
    }, function (err, data) {
        if (err || !data) {
            console.error(err);
            res.json(result(false, '', {}));
        } else {
            for (var i = 0; i< data.length; i++) {
                data[i].in_dur = data[i].in_duration();
            }
            res.json(result(true, '', data));
        }
    });
});

//获取该医生所有的病人
router.get('/sicks', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    if (!doctor_id) {
        res.json(result(false, 'no doctor_id', {}));
        return;
    }
    req.models.sick.find({doctor_id: doctor_id}, function (err, data) {
        if (err || !data) {
            console.error(err);
            res.json(result(false, '', {}));
        } else {
            for (var i = 0; i< data.length; i++) {
                data[i].in_dur = data[i].in_duration();
            }
            res.json(result(true, '', data));
        }
    });
});

//查房
router.post('/check', function (req, res, next) {

        var sick_id, doctor_id, description, title, pic, hasErr;
        try {
            sick_id = req.param('sick_id');
            doctor_id = req.param('doctor_id');
            title = req.param('title');
            description = req.param('description');
            pic = req.param('pics');
            if (!(pic instanceof Array)) {
                var temp = [];
                temp = pic.split(",");
                pic=temp;
            }
            console.log('description=' + description + ', pics=' + pic);
        } catch (e) {
            console.error(e);
            hasErr = e;
        }
        if (hasErr) {
            console.log('parse param error: ' + hasErr);
            res.redirect(source_url.check + '?err=1sick_id=' + sick_id + '&doctor_id=' + doctor_id);
        } else {
            var sc = {
                title: title,
                sick_id: sick_id, doctor_id: doctor_id, day: new Date(), description: description, pics: pic
            };
            console.log('sc=' + JSON.stringify(sc));
            req.models.sickcheck.create(sc, function (err, item) {
                if (err) {
                    console.error(err);
                    res.redirect(source_url.check + '?err=1&sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                } else {
                    res.redirect(target_url.check + '?sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                }
            });

        }

});

//随访
router.post('/out_check', function (req, res, next) {
    var sick_id, doctor_id, description, title, pic, hasErr;
        try {
            sick_id = req.param('sick_id');
            doctor_id = req.param('doctor_id');
            title = req.param('title');
            description = req.param('description');
            pic = req.param('pics');
            if (!(pic instanceof Array)) {
                var temp = [];
                temp = pic.split(",");
                pic=temp;
            }
            console.log('description=' + description + ', pics=' + pic);
        } catch (e) {
            console.error(e);
            hasErr = e;
        }
        if (hasErr) {
            console.log('parse param error: ' + hasErr);
            res.redirect(source_url.review + '?err=1sick_id=' + sick_id + '&doctor_id=' + doctor_id);
        } else {
            var sc = {
                title: title,
                sick_id: sick_id, doctor_id: doctor_id, day: new Date(), description: description, pics: pic
            };
            console.log('sc=' + JSON.stringify(sc));
            req.models.sickreview.create(sc, function (err, item) {
                if (err) {
                    console.error(err);
                    res.redirect(source_url.review + '?err=1&sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                } else {
                    res.redirect(target_url.review + '?sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                }
            });

        }
});

router.get('/checkList', function(req, res, next){
    var sick_id = req.param('sick_id');
    var doctor_id = req.param('doctor_id');
    var pageNo = req.param('pageNo') || 0, pageSize = req.param('pageSize') || 10;
    var query = {};
    if (sick_id) {
        query.sick_id = sick_id;
    }
    if (doctor_id) {
        query.doctor_id = doctor_id;
    }
    req.models.sickcheck.find(query).order('-id').limit(pageSize).offset(pageSize*pageNo).run(function(err, data) {
        if (err) {
            res.json(result(false,'get sickcheck err', err));
        } else {
            res.json(result(true,'',data));
        }
    });
});

router.get('/outCheckList', function(req, res, next){
    var sick_id = req.param('sick_id');
    var doctor_id = req.param('doctor_id');
    var pageNo = req.param('pageNo') || 0, pageSize = req.param('pageSize') || 10;
    var query = {};
    if (sick_id) {
        query.sick_id = sick_id;
}
    if (doctor_id) {
        query.doctor_id = doctor_id;
    }
    req.models.sickreview.find(query).order('-id').limit(pageSize).offset(pageSize*pageNo).run(function(err, data) {
        if (err) {
            res.json(result(false,'get sickcheck err', err));
        } else {
            res.json(result(true,'',data));
        }
    });
});

router.get('/hospital', function(req, res, next){
    req.models.hospital.find({}, function(err, data){
        if (err) {
            res.json(result(false, 'err', err));
        } else {
            res.json(result(true, '', data));
        }
    });
});

router.get('/hospitalDoctor', function(req, res, next) {
    var name = req.param('name');
    if (!name) {
        console.info('empty name');
        res.json(result(false, 'empty name', {}));
    } else {
        req.models.hospitalDoctor.find({'name': name}).order('area').order('room').run(function(err, data) {
            if (err) {
                res.json(result(false, 'err', err));
            } else {
                res.json(result(true, '', data));
            }
        });
    }
});

router.get('/requestList', function(req, res, next){
    var doctor_id = req.param('doctor_id');
    req.models.sickRequest.find({'doctor_id': doctor_id}, function(err, items){
        if (err) {
            res.json(result(false, 'err', err));
        } else {
            res.json(result(true,'',items));
        }
    });
});

router.get('/verify', function(req, res, next) {
    var sick_id = req.param('sick_id');
    var doctor_id = req.param('doctor_id');
    var isok = req.param('isok')?'t':'f';

    req.models.sick.get(sick_id, function(err, sick) {
        sick.save({status:isok}, function(err) {
        if (err) {
            res.json(result(false,'err', err));
        } else {
            req.models.sickRequest.find({'doctor_id':doctor_id, 'sick_id':sick_id}, function(err, data){
                if (err) {
                    res.json(result(false, 'err', err));
                } else {
                    if (data && data.length > 0) {
                        data[0].save({'status': 't'}, function(err) {
                            if (err) {
                                res.json(result(false,'err',err));
                            } else {
                                res.json(result(true, '', {}));
                            }
                        })
                    } else {
                        res.json(result(false, 'sick request not found', {}));
                    }
                }
            });
        }
        });
    });

});

module.exports = router;
<commit_msg>bug fixed<commit_after>var express = require('express');
var router = express.Router();
var result = require('./result');
var orm = require('orm');
var multiparty = require('multiparty');
var util = require('util');
var fs = require('fs');
//Todo
var source_url = {check: '/gakf/addCheck.html', review: '/gakf/sickDetail.html'};
var target_url = {check: '/gakf/check.html', review: '/gakf/flowSick.html'};

//根据ID获取医生信息
router.get('/info', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    req.models.doctor.get(doctor_id, function (err, item) {
        if (err || !item) {
            res.json(result(false, err.msg, {}));
        } else {
            res.json(result(true, '', item));
        }
    });
});

//获取出院的病人
router.get('/out_sicks', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    if (!doctor_id) {
        res.json(result(false, 'no doctor_id', {}));
        return;
    }
    var sick_array = [];
    req.models.sick.find({
        doctor_id: doctor_id,
        out_day: orm.lte(new Date())
    }, function (err, data) {
        if (err || !data) {
            console.error(err);
            res.json(result(false, '', {}));
        } else {
            for (var i = 0; i< data.length; i++) {
                data[i].out_dur = data[i].out_duration();
                sick_array.push(data[i]);
            }
            req.models.sick.find({
                doctor_id : doctor_id,
                in_day: null,
            }, function(err, data2) {
                if (err || !data) {
                    res.json(result(true, '', sick_array));
                } else {
                    for (var i = 0; i < data2.length; i++) {
                        data2[i].out_dur = 0;
                        sick_array.push(data2[i]);
                    }
                    res.json(result(true, '', sick_array));
                }
            });

        }
    });
});

//获取入院的病人
router.get('/in_sicks', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    if (!doctor_id) {
        res.json(result(false, 'no doctor_id', {}));
        return;
    }
    req.models.sick.find({
        doctor_id: doctor_id,
        in_day: orm.lte(new Date()),
        out_day: orm.gte(new Date())
    }, function (err, data) {
        if (err || !data) {
            console.error(err);
            res.json(result(false, '', {}));
        } else {
            for (var i = 0; i< data.length; i++) {
                data[i].in_dur = data[i].in_duration();
            }
            res.json(result(true, '', data));
        }
    });
});

//获取该医生所有的病人
router.get('/sicks', function (req, res, next) {
    var doctor_id = req.param('doctor_id');
    if (!doctor_id) {
        res.json(result(false, 'no doctor_id', {}));
        return;
    }
    req.models.sick.find({doctor_id: doctor_id}, function (err, data) {
        if (err || !data) {
            console.error(err);
            res.json(result(false, '', {}));
        } else {
            for (var i = 0; i< data.length; i++) {
                data[i].in_dur = data[i].in_duration();
            }
            res.json(result(true, '', data));
        }
    });
});

//查房
router.post('/check', function (req, res, next) {

        var sick_id, doctor_id, description, title, pic, hasErr;
        try {
            sick_id = req.param('sick_id');
            doctor_id = req.param('doctor_id');
            title = req.param('title');
            description = req.param('description');
            pic = req.param('pics');
            if (!(pic instanceof Array)) {
                var temp = [];
                temp = pic.split(",");
                pic=temp;
            }
            console.log('description=' + description + ', pics=' + pic);
        } catch (e) {
            console.error(e);
            hasErr = e;
        }
        if (hasErr) {
            console.log('parse param error: ' + hasErr);
            res.redirect(source_url.check + '?err=1sick_id=' + sick_id + '&doctor_id=' + doctor_id);
        } else {
            var sc = {
                title: title,
                sick_id: sick_id, doctor_id: doctor_id, day: new Date(), description: description, pics: pic
            };
            console.log('sc=' + JSON.stringify(sc));
            req.models.sickcheck.create(sc, function (err, item) {
                if (err) {
                    console.error(err);
                    res.redirect(source_url.check + '?err=1&sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                } else {
                    res.redirect(target_url.check + '?sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                }
            });

        }

});

//随访
router.post('/out_check', function (req, res, next) {
    var sick_id, doctor_id, description, title, pic, hasErr;
        try {
            sick_id = req.param('sick_id');
            doctor_id = req.param('doctor_id');
            title = req.param('title');
            description = req.param('description');
            pic = req.param('pics');
            if (!(pic instanceof Array)) {
                var temp = [];
                temp = pic.split(",");
                pic=temp;
            }
            console.log('description=' + description + ', pics=' + pic);
        } catch (e) {
            console.error(e);
            hasErr = e;
        }
        if (hasErr) {
            console.log('parse param error: ' + hasErr);
            res.redirect(source_url.review + '?err=1sick_id=' + sick_id + '&doctor_id=' + doctor_id);
        } else {
            var sc = {
                title: title,
                sick_id: sick_id, doctor_id: doctor_id, day: new Date(), description: description, pics: pic
            };
            console.log('sc=' + JSON.stringify(sc));
            req.models.sickreview.create(sc, function (err, item) {
                if (err) {
                    console.error(err);
                    res.redirect(source_url.review + '?err=1&sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                } else {
                    res.redirect(target_url.review + '?sick_id=' + sick_id + '&doctor_id=' + doctor_id);
                }
            });

        }
});

router.get('/checkList', function(req, res, next){
    var sick_id = req.param('sick_id');
    var doctor_id = req.param('doctor_id');
    var pageNo = req.param('pageNo') || 0, pageSize = req.param('pageSize') || 10;
    var query = {};
    if (sick_id) {
        query.sick_id = sick_id;
    }
    if (doctor_id) {
        query.doctor_id = doctor_id;
    }
    req.models.sickcheck.find(query).order('-id').limit(pageSize).offset(pageSize*pageNo).run(function(err, data) {
        if (err) {
            res.json(result(false,'get sickcheck err', err));
        } else {
            res.json(result(true,'',data));
        }
    });
});

router.get('/outCheckList', function(req, res, next){
    var sick_id = req.param('sick_id');
    var doctor_id = req.param('doctor_id');
    var pageNo = req.param('pageNo') || 0, pageSize = req.param('pageSize') || 10;
    var query = {};
    if (sick_id) {
        query.sick_id = sick_id;
}
    if (doctor_id) {
        query.doctor_id = doctor_id;
    }
    req.models.sickreview.find(query).order('-id').limit(pageSize).offset(pageSize*pageNo).run(function(err, data) {
        if (err) {
            res.json(result(false,'get sickcheck err', err));
        } else {
            res.json(result(true,'',data));
        }
    });
});

router.get('/hospital', function(req, res, next){
    req.models.hospital.find({}, function(err, data){
        if (err) {
            res.json(result(false, 'err', err));
        } else {
            res.json(result(true, '', data));
        }
    });
});

router.get('/hospitalDoctor', function(req, res, next) {
    var name = req.param('name');
    if (!name) {
        console.info('empty name');
        res.json(result(false, 'empty name', {}));
    } else {
        req.models.hospitalDoctor.find({'name': name}).order('area').order('room').run(function(err, data) {
            if (err) {
                res.json(result(false, 'err', err));
            } else {
                res.json(result(true, '', data));
            }
        });
    }
});

router.get('/requestList', function(req, res, next){
    var doctor_id = req.param('doctor_id');
    req.models.sickRequest.find({'doctor_id': doctor_id}, function(err, items){
        if (err) {
            res.json(result(false, 'err', err));
        } else {
            res.json(result(true,'',items));
        }
    });
});

router.get('/verify', function(req, res, next) {
    var sick_id = req.param('sick_id');
    var doctor_id = req.param('doctor_id');
    var isok = req.param('isok')?'t':'f';

    req.models.sick.get(sick_id, function(err, sick) {
        sick.save({status:isok}, function(err) {
        if (err) {
            res.json(result(false,'err', err));
        } else {
            req.models.sickRequest.find({'doctor_id':doctor_id, 'sick_id':sick_id}, function(err, data){
                if (err) {
                    res.json(result(false, 'err', err));
                } else {
                    if (data && data.length > 0) {
                        data[0].save({'status': 't'}, function(err) {
                            if (err) {
                                res.json(result(false,'err',err));
                            } else {
                                res.json(result(true, '', {}));
                            }
                        })
                    } else {
                        res.json(result(false, 'sick request not found', {}));
                    }
                }
            });
        }
        });
    });

});

module.exports = router;
<|endoftext|>


<commit_before>function randint(low, high) {
  return Math.floor(Math.random() * (high - low + 1)) + low;
}

function regularPolygon(x, y, n, rad, rot) {
  var xlist = [];
  var ylist = [];
  for (i = 0; i < n; i++){
    xlist[i] = x + rad * Math.cos(2*Math.PI*i/n - rot);
    ylist[i] = y + rad * Math.sin(2*Math.PI*i/n - rot);
  }
  return [xlist, ylist];
}

function distanceSquared(a, b) {
  return Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2)
}

function Shape(x, y, radius, shape, color) {
  this.x = x;
  this.y = y;
  this.radius = radius;
  this.shape = shape;
  this.color = color;
  this.points = []

  this.draw = function (ctx) {
    ctx.fillStyle = this.color;
    if (this.shape == 'circle'){
      this.points[0] = this.radius;
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, 2*Math.PI);
      ctx.closePath();
      ctx.fill();
    } else if (typeof this.shape == 'number'){
      pointList = regularPolygon(this.x, this.y, this.shape, this.radius, Math.random()*2*Math.PI);
      xlist = pointList[0];
      ylist = pointList[1];
      ctx.beginPath();
      ctx.moveTo(xlist[0], ylist[0]);
      this.points[0] = [xlist[0], ylist[0]];
      for (i = 1; i<this.shape; i++){
        ctx.lineTo(xlist[i], ylist[i]);
        this.points[i] = [xlist[i], ylist[i]];
      }
      ctx.fill();
    }
  }
}

function Painting(shapes){
  this.shapes = shapes;
  this.draw = function(ctx){
    for (i in this.shapes) {
      var s = this.shapes[i];
      s.draw(ctx);
    }
  }
}

/**
 * Generate a painting.
 */
function generatePainting(num, width, height, radius, shapesLibrary, colorsLibrary) {
  var shapeList = []
  for (i = 0; i < num; i++) {
    ind = randint(0, 3);
    shp = shapesLibrary[ind];
    clr = colorsLibrary[ind];
    shapeList.push(new Shape(randint(0, width), randint(0, height), radius, shp, clr));
  }
  return shapeList;
}

function spaceFitness(painting){
  shapes = painting.shapes;
  var sum = 0;
  for (i=0; i<shapes.length; i++){
    for (j=i+1; j<shapes.length; j++){
      sum += distanceSquared(shapes[i], shapes[j]);
    }
  }
  numConnections = shapes.length*(shapes.length-1)/2
  console.log(numConnections);
  var avgDist = sum/numConnections;
  return avgDist;
}

function main() {
  var a_canvas = document.getElementById("a");
  var ctx = a_canvas.getContext("2d");
  var IMAGE_WIDTH = a_canvas.width;
  var IMAGE_HEIGHT = a_canvas.height;
  var NUM_SHAPES = 300;
  var NUM_TRIALS = 100;
  var shapesLibrary = ['circle', 4, 6, 8]
  var colorsLibrary = ['#FF6600', '#DD0000', '#00E3BE', '#6600CC']
  var fitnessArray = [];
  var population = [];

  /**
   * Generate a population of paintings.
   */
  for (trial=0; trial<NUM_TRIALS; trial++){
    var painting = new Painting(generatePainting(NUM_SHAPES, IMAGE_WIDTH, IMAGE_HEIGHT, 30, shapesLibrary, colorsLibrary));
    population[trial] = painting;
    fitnessArray[trial] = spaceFitness(painting);
    if (trial==NUM_TRIALS-1) {
      painting.draw(ctx);
    }
  }
  console.log(population);
  console.log(fitnessArray);
}

main();
<commit_msg>Added a not-quite kernel density estimation<commit_after>function randint(low, high) {
  return Math.floor(Math.random() * (high - low + 1)) + low;
}

function regularPolygon(x, y, n, rad, rot) {
  var xlist = [];
  var ylist = [];
  for (i = 0; i < n; i++){
    xlist[i] = x + rad * Math.cos(2*Math.PI*i/n - rot);
    ylist[i] = y + rad * Math.sin(2*Math.PI*i/n - rot);
  }
  return [xlist, ylist];
}

function distanceSquared(a, b) {
  return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}

function avgKernelDensity(painting){

  function singleKernelDensity(reference, set) {
    var sum = -1;
    for (j=0; j<set.length; j++) {
      sum += Math.exp(-distanceSquared(reference, set[j]) / 2000);
    }
    return sum;
  }

  var total = 0;
  shapes = painting.shapes;
  for (i=0; i<shapes.length; i++) {
    total += singleKernelDensity(shapes[i], shapes);
  }
  avg = total / shapes.length;
  return avg;
}

function Shape(x, y, radius, shape, color) {
  this.x = x;
  this.y = y;
  this.radius = radius;
  this.shape = shape;
  this.color = color;
  this.points = []

  this.draw = function (ctx) {
    ctx.fillStyle = this.color;
    if (this.shape == 'circle'){
      this.points[0] = this.radius;
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, 2*Math.PI);
      ctx.closePath();
      ctx.fill();
    } else if (typeof this.shape == 'number'){
      pointList = regularPolygon(this.x, this.y, this.shape, this.radius, Math.random()*2*Math.PI);
      xlist = pointList[0];
      ylist = pointList[1];
      ctx.beginPath();
      ctx.moveTo(xlist[0], ylist[0]);
      this.points[0] = [xlist[0], ylist[0]];
      for (i = 1; i<this.shape; i++){
        ctx.lineTo(xlist[i], ylist[i]);
        this.points[i] = [xlist[i], ylist[i]];
      }
      ctx.fill();
    }
  }
}

function Painting(shapes){
  this.shapes = shapes;
  this.draw = function(ctx){
    for (i in this.shapes) {
      var s = this.shapes[i];
      s.draw(ctx);
    }
  }
}

function generatePainting(num, width, height, radius, shapesLibrary, colorsLibrary) {
  var shapeList = []
  for (i = 0; i < num; i++) {
    ind = randint(0, 3);
    shp = shapesLibrary[ind];
    clr = colorsLibrary[ind];
    shapeList.push(new Shape(randint(0, width), randint(0, height), radius, shp, clr));
  }
  return shapeList;
}

function spaceFitness(painting){
  shapes = painting.shapes;
  var sum = 0;
  for (i=0; i<shapes.length; i++){
    for (j=i+1; j<shapes.length; j++){
      sum += distanceSquared(shapes[i], shapes[j]);
    }
  }
  numConnections = shapes.length*(shapes.length-1)/2
  var avgDist = sum/numConnections;
  return avgDist;
}

function main() {
  var a_canvas = document.getElementById("a");
  var ctx = a_canvas.getContext("2d");
  var IMAGE_WIDTH = a_canvas.width;
  var IMAGE_HEIGHT = a_canvas.height;
  var NUM_SHAPES = 300;
  var NUM_TRIALS = 100;
  var shapesLibrary = ['circle', 4, 6, 8]
  var colorsLibrary = ['#FF6600', '#DD0000', '#00E3BE', '#6600CC']
  var fitnessArray = [];
  var population = [];

  /**
   * Generate a population of paintings.
   */
  for (trial=0; trial<NUM_TRIALS; trial++){
    var painting = new Painting(generatePainting(NUM_SHAPES, IMAGE_WIDTH, IMAGE_HEIGHT, 30, shapesLibrary, colorsLibrary));
    population[trial] = painting;
    fitnessArray[trial] = spaceFitness(painting);
    if (trial==NUM_TRIALS-1) {
      painting.draw(ctx);
    }
  }

  console.log(avgKernelDensity(painting));
}

main();
<|endoftext|>


<commit_before>var express = require('express');
var bodyParser = require('body-parser');
var colors = require('colors');
var mongo = require('./mongo');

// new session handling
var session = require('express-session');
var FileStore = require('session-file-store')(session);

var app = express();

app.use(session({
    name: 'server-session-cookie-id',
    secret: Math.random().toString(36).substring(7),
    store: new FileStore(),
    saveUninitialized: true,
    resave: true
}));

// configuration strings
var config = require('./config.js');

// routes
var main_routes = require('../routes/main_routes');
app.use('/api', main_routes);

var info_routes = require('../routes/info_routes');
app.use('/info', info_routes);

load information from CUNYFirst server
mongo.populateDatabase(function(err) {
    if(err) {
        console.log('Cron Job unable to run.');
    } else {
        console.log('Cron Job ran successfully.');
    }
});

// connect public directory to node app
app.use(express.static('../../public'));

// listen for http requests on port
app.listen(8000);
console.log("Running on 8000".white);<commit_msg>Fixed mistake<commit_after>var express = require('express');
var bodyParser = require('body-parser');
var colors = require('colors');
var mongo = require('./mongo');

// new session handling
var session = require('express-session');
var FileStore = require('session-file-store')(session);

var app = express();

app.use(session({
    name: 'server-session-cookie-id',
    secret: Math.random().toString(36).substring(7),
    store: new FileStore(),
    saveUninitialized: true,
    resave: true
}));

// configuration strings
var config = require('./config.js');

// routes
var main_routes = require('../routes/main_routes');
app.use('/api', main_routes);

var info_routes = require('../routes/info_routes');
app.use('/info', info_routes);

// load information from CUNYFirst server
mongo.populateDatabase(function(err) {
    if(err) {
        console.log('Cron Job unable to run.');
    } else {
        console.log('Cron Job ran successfully.');
    }
});

// connect public directory to node app
app.use(express.static('../../public'));

// listen for http requests on port
app.listen(8000);
console.log("Running on 8000".white);<|endoftext|>


<commit_before>var wompt  = require("./includes")
   ,constants = wompt.env.constants
   ,events = require("events")
   ,util = require("util")
   ,logger = wompt.logger;

function Channel(config){
	var channel = this;

	this.last_activity = new Date();
	this.name = config.name;
	this.messages = new wompt.MessageList(this);
	this.clients = new wompt.ClientPool();

	// Called from the context of the client
	this._message_from_client = function(msg){
		msg.from_client = this;
		this.user.touch();
		channel.receive_message(msg);
	}

	this._client_disconnected = function(){
		var client = this;
		channel.touch();
		delete client.meta_data;
		if(client.user.visible){
			// Anonymous clients are treated independently for the userlist (anon count = anonymous clients)
			if(!client.user.authenticated() || channel.clients.other_clients_from_same_user(client).length == 0)
				channel.broadcast_user_list_change({'part': client.user});
		}
	}
}

var proto = {
	add_client: function(client, token, joinMsg){
		this.touch();
		client.meta_data = {
			channel: this,
			token: token
		};

		this.clients.add(client);

		if(client.user.visible){
			// Anonymous clients are treated independently for the userlist (anon count = anonymous clients)
			if(!client.user.authenticated() || this.clients.other_clients_from_same_user(client).length == 0)
				this.broadcast_user_list_change({
					join: client.user,
					except: client
				});
		}

		client.on('message', this._message_from_client);
		client.on('disconnect', this._client_disconnected);

		this.send_initial_data(client, joinMsg);
	},

	touch: function(type){
		this.touched = new Date();
	},

	send_initial_data: function(client, joinMsg){
		client.bufferSends(function(){
			if(!this.messages.is_empty())
				client.send({action: 'batch', messages: this.messages.since(joinMsg.last_timestamp)});

			client.send({action: 'who',	users: this.get_user_list(client)});
		}, this);
	},

	receive_message: function(data){
		this.touch();
		var responder = this.action_responders[data.action];
		if(responder)
			responder.call(this, data);
		else
			throw "No such action handler:" + data.action;
	},

	action_responders: {
		post: function(data){
			if(data.from_client.user.readonly) return;
			if(data.msg && data.msg.length > constants.messages.max_length) return;
			var message = {
				t: new Date().getTime(),
				action: 'message',
				msg: data.msg,
				from:{
					name: data.from_client.user.doc.name,
					id: data.from_client.user.id()
				}
			};
			this.broadcast_message(message, {first:data.from_client});
		}
	},

	get_user_list: function(client){
		var users = {anonymous:{count:0}}, list = this.clients.list;

		for(var id in list){
			var cl = list[id],
			    doc = cl.user.doc,
			    uid = cl.user.id();

			if(cl.user.visible && doc && !users[uid]){
				users[uid]={
					name: doc.name || 'anonymous'
				};
			}else {
				users.anonymous.count++;
			}
		}

		if(users.anonymous.count == 0) delete users.anonymous;

		return users;
	},

	broadcast_user_list_change: function(opt){
		var action;

		if(opt.part) action='part';
		else if(opt.join) action='join';

		var users = {}, user = opt.part || opt.join;
		if(user.authenticated()){
			users[user.id()] = {
				'name': user.doc.name || user.doc.email
			}
		} else {
			users.anonymous = {count:1};
		}

		var message = {
			t: new Date().getTime(),
			action:action,
			users: users
		};
		this.broadcast_message(message, opt.except);
	},

	broadcast_message: function(msg, except){
		this.emit('msg', msg);
		this.clients.broadcast(msg, except);
	},

	clean_up: function(){
		delete this.messages;
		delete this.clients;
		this.emit('destroy');
	}
}

util.inherits(Channel, events.EventEmitter);
for(var k in proto) Channel.prototype[k] = proto[k];

Channel.generalizeName = function(name){
	return name.toLowerCase();
}

Channel.hashName = function(name){
	return wompt.util.md5(name);
}

exports.Channel = Channel;
<commit_msg>Dont log anonymous joins / parts to the channel log<commit_after>var wompt  = require("./includes")
   ,constants = wompt.env.constants
   ,events = require("events")
   ,util = require("util")
   ,logger = wompt.logger;

function Channel(config){
	var channel = this;

	this.last_activity = new Date();
	this.name = config.name;
	this.messages = new wompt.MessageList(this);
	this.clients = new wompt.ClientPool();

	// Called from the context of the client
	this._message_from_client = function(msg){
		msg.from_client = this;
		this.user.touch();
		channel.receive_message(msg);
	}

	this._client_disconnected = function(){
		var client = this;
		channel.touch();
		delete client.meta_data;
		if(client.user.visible){
			// Anonymous clients are treated independently for the userlist (anon count = anonymous clients)
			if(!client.user.authenticated() || channel.clients.other_clients_from_same_user(client).length == 0)
				channel.broadcast_user_list_change({'part': client.user});
		}
	}
}

var proto = {
	add_client: function(client, token, joinMsg){
		this.touch();
		client.meta_data = {
			channel: this,
			token: token
		};

		this.clients.add(client);

		if(client.user.visible){
			// Anonymous clients are treated independently for the userlist (anon count = anonymous clients)
			if(!client.user.authenticated() || this.clients.other_clients_from_same_user(client).length == 0)
				this.broadcast_user_list_change({
					join: client.user,
					except: client
				});
		}

		client.on('message', this._message_from_client);
		client.on('disconnect', this._client_disconnected);

		this.send_initial_data(client, joinMsg);
	},

	touch: function(type){
		this.touched = new Date();
	},

	send_initial_data: function(client, joinMsg){
		client.bufferSends(function(){
			if(!this.messages.is_empty())
				client.send({action: 'batch', messages: this.messages.since(joinMsg.last_timestamp)});

			client.send({action: 'who',	users: this.get_user_list(client)});
		}, this);
	},

	receive_message: function(data){
		this.touch();
		var responder = this.action_responders[data.action];
		if(responder)
			responder.call(this, data);
		else
			throw "No such action handler:" + data.action;
	},

	action_responders: {
		post: function(data){
			if(data.from_client.user.readonly) return;
			if(data.msg && data.msg.length > constants.messages.max_length) return;
			var message = {
				t: new Date().getTime(),
				action: 'message',
				msg: data.msg,
				from:{
					name: data.from_client.user.doc.name,
					id: data.from_client.user.id()
				}
			};
			this.broadcast_message(message, {first:data.from_client});
		}
	},

	get_user_list: function(client){
		var users = {anonymous:{count:0}}, list = this.clients.list;

		for(var id in list){
			var cl = list[id],
			    doc = cl.user.doc,
			    uid = cl.user.id();

			if(cl.user.visible && doc && !users[uid]){
				users[uid]={
					name: doc.name || 'anonymous'
				};
			}else {
				users.anonymous.count++;
			}
		}

		if(users.anonymous.count == 0) delete users.anonymous;

		return users;
	},

	broadcast_user_list_change: function(opt){
		var action, dont_emit;

		if(opt.part) action='part';
		else if(opt.join) action='join';

		var users = {}, user = opt.part || opt.join;
		if(user.authenticated()){
			users[user.id()] = {
				'name': user.doc.name || user.doc.email
			}
		} else {
			users.anonymous = {count:1};
			// anonymous join / parts shouldn't be emitted (and thus logged to disk)
			dont_emit = true;
		}

		var message = {
			t: new Date().getTime(),
			action:action,
			users: users
		};
		this.broadcast_message(message, opt.except, dont_emit);
	},

	broadcast_message: function(msg, except, dont_emit){
		if(!dont_emit)
			this.emit('msg', msg);
		this.clients.broadcast(msg, except);
	},

	clean_up: function(){
		delete this.messages;
		delete this.clients;
		this.emit('destroy');
	}
}

util.inherits(Channel, events.EventEmitter);
for(var k in proto) Channel.prototype[k] = proto[k];

Channel.generalizeName = function(name){
	return name.toLowerCase();
}

Channel.hashName = function(name){
	return wompt.util.md5(name);
}

exports.Channel = Channel;
<|endoftext|>


<commit_before>const path = require('path');
const dedent = require('dedent');
const argv = require('minimist')(process.argv.slice(2));

const { warn, error } = require('./helpers/log');
const prepareSentry = require('./helpers/sentry');

const isSilent = argv._.includes('help') || argv._.includes('init') || argv._.includes('print-config');

const readJSON = (file) => {
    const fileName = `${file}.json`;

    if (file === 'env' && !isSilent) {
        warn('[DEPREACTION NOTICE] Please rename your file env.json to appConfig.json');
    }

    try {
        return require(path.join(process.cwd(), fileName));
    } catch (e) {
        !isSilent && warn(`Missing file ${fileName}`);
        if (/SyntaxError/.test(e.stack)) {
            error(e);
        }
    }
};

/**
 * Extract the config of a project
 * - env: from env.json for sentry, and some custom config for the app
 *     appConfig: {
 *         name: 'Web',
 *         etc.
 *     }
 * - pkg: from package.json for sentry
 * @return {Object}   { env: Object, pkg: Object }
 */
const CONFIG_ENV = (() => {
    const pkg = require(path.join(process.cwd(), 'package.json'));
    // @todo load value from the env as it's done for proton-i19n
    return {
        env: readJSON('appConfig') || readJSON('env') || {},
        pkg
    };
})();

const ENV_CONFIG = Object.keys(CONFIG_ENV.env).reduce(
    (acc, key) => {
        if (key === 'appConfig') {
            acc.app = CONFIG_ENV.env[key];
            return acc;
        }
        const { api, secure, ...sentry } = CONFIG_ENV.env[key];
        acc.sentry[key] = sentry;
        api && (acc.api[key] = api);
        secure && (acc.secure[key] = secure);
        return acc;
    },
    { sentry: {}, api: {}, secure: {}, pkg: CONFIG_ENV.pkg, app: {} }
);

const API_TARGETS = {
    prod: 'https://mail.protonmail.com/api',
    local: 'https://protonmail.dev/api',
    localhost: 'https://localhost/api',
    build: '/api',
    ...ENV_CONFIG.api
};

const SECURE_URL = {
    prod: 'https://secure.protonmail.com',
    blue: 'https://secure.protonmail.blue',
    ...ENV_CONFIG.secure
};

function main({ api = 'dev' }) {
    const apiUrl = API_TARGETS[api] || API_TARGETS.prod;
    const secureUrl = SECURE_URL[api] || SECURE_URL.prod;

    const json = {
        clientId: ENV_CONFIG.app.clientId || 'WebMail',
        appName: ENV_CONFIG.app.appName || ENV_CONFIG.pkg.name || 'protonmail',
        version: ENV_CONFIG.app.version || ENV_CONFIG.pkg.version || '3.16.20',
        apiUrl
    };

    const { SENTRY_RELEASE = '', SENTRY_DSN = '' } = prepareSentry(ENV_CONFIG, json, api);

    const config = dedent`
    export const CLIENT_ID = '${json.clientId}';
    export const CLIENT_TYPE = ${ENV_CONFIG.app.clientType || 1};
    export const CLIENT_SECRET = '${ENV_CONFIG.app.clientSecret || ''}';
    export const APP_VERSION = '${json.version}';
    export const APP_NAME = '${json.appName}';
    export const API_URL = '${apiUrl}';
    export const SECURE_URL = '${secureUrl}';
    export const API_VERSION = '3';
    export const DATE_VERSION = '${new Date().toGMTString()}';
    export const CHANGELOG_PATH = 'assets/changelog.tpl.html';
    export const VERSION_PATH = 'assets/version.json';
    export const SENTRY_RELEASE = '${SENTRY_RELEASE}';
    export const SENTRY_DSN = '${SENTRY_DSN}';
    `;

    return {
        config,
        apiUrl,
        json,
        path: path.join(process.cwd(), 'src', 'app', 'config.js')
    };
}

module.exports = main;
<commit_msg>Import secure from the config<commit_after>const path = require('path');
const dedent = require('dedent');
const argv = require('minimist')(process.argv.slice(2));

const { warn, error } = require('./helpers/log');
const prepareSentry = require('./helpers/sentry');

const isSilent = argv._.includes('help') || argv._.includes('init') || argv._.includes('print-config');

const readJSON = (file) => {
    const fileName = `${file}.json`;

    if (file === 'env' && !isSilent) {
        warn('[DEPREACTION NOTICE] Please rename your file env.json to appConfig.json');
    }

    try {
        return require(path.join(process.cwd(), fileName));
    } catch (e) {
        !isSilent && warn(`Missing file ${fileName}`);
        if (/SyntaxError/.test(e.stack)) {
            error(e);
        }
    }
};

/**
 * Extract the config of a project
 * - env: from env.json for sentry, and some custom config for the app
 *     appConfig: {
 *         name: 'Web',
 *         etc.
 *     }
 * - pkg: from package.json for sentry
 * @return {Object}   { env: Object, pkg: Object }
 */
const CONFIG_ENV = (() => {
    const pkg = require(path.join(process.cwd(), 'package.json'));
    // @todo load value from the env as it's done for proton-i19n
    return {
        env: readJSON('appConfig') || readJSON('env') || {},
        pkg
    };
})();

const ENV_CONFIG = Object.keys(CONFIG_ENV.env).reduce(
    (acc, key) => {
        if (key === 'appConfig') {
            acc.app = CONFIG_ENV.env[key];
            return acc;
        }
        const { api, secure, ...sentry } = CONFIG_ENV.env[key];
        acc.sentry[key] = sentry;
        api && (acc.api[key] = api);
        secure && (acc.secure[key] = secure);
        return acc;
    },
    { sentry: {}, api: {}, secure: {}, pkg: CONFIG_ENV.pkg, app: {} }
);

const API_TARGETS = {
    prod: 'https://mail.protonmail.com/api',
    local: 'https://protonmail.dev/api',
    localhost: 'https://localhost/api',
    build: '/api',
    ...ENV_CONFIG.api
};

const SECURE_URL = ENV_CONFIG.secure;

function main({ api = 'dev' }) {
    const apiUrl = API_TARGETS[api] || API_TARGETS.prod;
    const secureUrl = SECURE_URL[api] || SECURE_URL.prod;

    const json = {
        clientId: ENV_CONFIG.app.clientId || 'WebMail',
        appName: ENV_CONFIG.app.appName || ENV_CONFIG.pkg.name || 'protonmail',
        version: ENV_CONFIG.app.version || ENV_CONFIG.pkg.version || '3.16.20',
        apiUrl
    };

    const { SENTRY_RELEASE = '', SENTRY_DSN = '' } = prepareSentry(ENV_CONFIG, json, api);

    const config = dedent`
    export const CLIENT_ID = '${json.clientId}';
    export const CLIENT_TYPE = ${ENV_CONFIG.app.clientType || 1};
    export const CLIENT_SECRET = '${ENV_CONFIG.app.clientSecret || ''}';
    export const APP_VERSION = '${json.version}';
    export const APP_NAME = '${json.appName}';
    export const API_URL = '${apiUrl}';
    export const SECURE_URL = '${secureUrl}';
    export const API_VERSION = '3';
    export const DATE_VERSION = '${new Date().toGMTString()}';
    export const CHANGELOG_PATH = 'assets/changelog.tpl.html';
    export const VERSION_PATH = 'assets/version.json';
    export const SENTRY_RELEASE = '${SENTRY_RELEASE}';
    export const SENTRY_DSN = '${SENTRY_DSN}';
    `;

    return {
        config,
        apiUrl,
        json,
        path: path.join(process.cwd(), 'src', 'app', 'config.js')
    };
}

module.exports = main;
<|endoftext|>