<commit_before>/*jshint esversion: 6 */
/* globals process */
const nThen = require("nthen");
const getFolderSize = require("get-folder-size");
const Util = require("../common-util");
const Ulimit = require("ulimit");
const Decrees = require("../decrees");

var Fs = require("fs");

var Admin = module.exports;

var getFileDescriptorCount = function (Env, server, cb) {
    Fs.readdir('/proc/self/fd', function(err, list) {
        if (err) { return void cb(err); }
        cb(void 0, list.length);
    });
};

var getFileDescriptorLimit = function (env, server, cb) {
    Ulimit(cb);
};

var getCacheStats = function (env, server, cb) {
    var metaSize = 0;
    var channelSize = 0;
    var metaCount = 0;
    var channelCount = 0;

    try {
        var meta = env.metadata_cache;
        for (var x in meta) {
            if (meta.hasOwnProperty(x)) {
                metaCount++;
                metaSize += JSON.stringify(meta[x]).length;
            }
        }

        var channels = env.channel_cache;
        for (var y in channels) {
            if (channels.hasOwnProperty(y)) {
                channelCount++;
                channelSize += JSON.stringify(channels[y]).length;
            }
        }
    } catch (err) {
        return void cb(err && err.message);
    }

    cb(void 0, {
        metadata: metaCount,
        metaSize: metaSize,
        channel: channelCount,
        channelSize: channelSize,
        memoryUsage: process.memoryUsage(),
    });
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_WORKER_PROFILES'], console.log)
var getWorkerProfiles = function (Env, Server, cb) {
    cb(void 0, Env.commandTimers);
};

var getActiveSessions = function (Env, Server, cb) {
    var stats = Server.getSessionStats();
    cb(void 0, [
        stats.total,
        stats.unique
    ]);
};

var shutdown = function (Env, Server, cb) {
    if (true) {
        return void cb('E_NOT_IMPLEMENTED');
    }

    // disconnect all users and reject new connections
    Server.shutdown();

    // stop all intervals that may be running
    Object.keys(Env.intervals).forEach(function (name) {
        clearInterval(Env.intervals[name]);
    });

    // set a flag to prevent incoming database writes
    // wait until all pending writes are complete
    // then process.exit(0);
    // and allow system functionality to restart the server
};

var getRegisteredUsers = function (Env, Server, cb) {
    Env.batchRegisteredUsers('', cb, function (done) {
        var dir = Env.paths.pin;
        var folders;
        var users = 0;
        nThen(function (waitFor) {
            Fs.readdir(dir, waitFor(function (err, list) {
                if (err) {
                    waitFor.abort();
                    return void done(err);
                }
                folders = list;
            }));
        }).nThen(function (waitFor) {
            folders.forEach(function (f) {
                var dir = Env.paths.pin + '/' + f;
                Fs.readdir(dir, waitFor(function (err, list) {
                    if (err) { return; }
                    users += list.length;
                }));
            });
        }).nThen(function () {
            done(void 0, users);
        });
    });
};

var getDiskUsage = function (Env, Server, cb) {
    Env.batchDiskUsage('', cb, function (done) {
        var data = {};
        nThen(function (waitFor) {
            getFolderSize('./', waitFor(function(err, info) {
                data.total = info;
            }));
            getFolderSize(Env.paths.pin, waitFor(function(err, info) {
                data.pin = info;
            }));
            getFolderSize(Env.paths.blob, waitFor(function(err, info) {
                data.blob = info;
            }));
            getFolderSize(Env.paths.staging, waitFor(function(err, info) {
                data.blobstage = info;
            }));
            getFolderSize(Env.paths.block, waitFor(function(err, info) {
                data.block = info;
            }));
            getFolderSize(Env.paths.data, waitFor(function(err, info) {
                data.datastore = info;
            }));
        }).nThen(function () {
            done(void 0, data);
        });
    });
};

var getActiveChannelCount = function (Env, Server, cb) {
    cb(void 0, Server.getActiveChannelCount());
};

var flushCache = function (Env, Server,  cb) {
    Env.flushCache();
    cb(void 0, true);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['ARCHIVE_DOCUMENT', documentID], console.log)
var archiveDocument = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    switch (id.length) {
        case 32:
        // TODO disconnect users from active sessions
            return void Env.msgStore.archiveChannel(id, cb);
        case 48:
            return void Env.blobStore.archive.blob(id, cb);
        default:
            return void cb("INVALID_ID_LENGTH");
    }

    // archival for blob proofs isn't automated, but evict-inactive.js will
    // clean up orpaned blob proofs
    // Env.blobStore.archive.proof(userSafeKey, blobId, cb)
};

var restoreArchivedDocument = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    switch (id.length) {
        case 32:
            return void Env.msgStore.restoreArchivedChannel(id, cb);
        case 48:
            // Env.blobStore.restore.proof(userSafekey, id, cb) // XXX ....
            return void Env.blobStore.restore.blob(id, cb);
        default:
            return void cb("INVALID_ID_LENGTH");
    }
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['CLEAR_CACHED_CHANNEL_INDEX', documentID], console.log)
var clearChannelIndex = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }
    delete Env.channel_cache[id];
    cb();
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_CACHED_CHANNEL_INDEX', documentID], console.log)
var getChannelIndex = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    var index = Util.find(Env, ['channel_cache', id]);
    if (!index) { return void cb("ENOENT"); }
    cb(void 0, index);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['CLEAR_CACHED_CHANNEL_METADATA', documentID], console.log)
var clearChannelMetadata = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }
    delete Env.metadata_cache[id];
    cb();
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_CACHED_CHANNEL_METADATA', documentID], console.log)
var getChannelMetadata = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    var index = Util.find(Env, ['metadata_cache', id]);
    if (!index) { return void cb("ENOENT"); }
    cb(void 0, index);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['RESTRICT_REGISTRATION', [true]]], console.log)
var adminDecree = function (Env, Server, cb, data, unsafeKey) {
    var value = data[1];
    if (!Array.isArray(value)) { return void cb('INVALID_DECREE'); }

    var command = value[0];
    var args = value[1];

/*

The admin should have sent a command to be run:

the server adds two pieces of information to the supplied decree:

* the unsafeKey of the admin who uploaded it
* the current time

1. test the command to see if it's valid and will result in a change
2. if so, apply it and write it to the log for persistence
3. respond to the admin with an error or nothing

*/

    var decree = [command, args, unsafeKey, +new Date()];
    var changed;
    try {
        changed = Decrees.handleCommand(Env, decree) || false;
    } catch (err) {
        return void cb(err);
    }

    if (!changed) { return void cb(); }
    Env.Log.info('ADMIN_DECREE', decree);
    Decrees.write(Env, decree, cb);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['SET_LAST_EVICTION', 0], console.log)
var setLastEviction = function (Env, Server, cb, data, unsafeKey) {
    var time = data && data[1];
    if (typeof(time) !== 'number') {
        return void cb('INVALID_ARGS');
    }

    Env.lastEviction = time;
    cb();
    Env.Log.info('LAST_EVICTION_TIME_SET', {
        author: unsafeKey,
        time: time,
    });
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['INSTANCE_STATUS], console.log)
var instanceStatus = function (Env, Server, cb) {
    cb(void 0, {
        restrictRegistration: Env.restrictRegistration,
        launchTime: Env.launchTime,
        currentTime: +new Date(),

        inactiveTime: Env.inactiveTime,
        accountRetentionTime: Env.accountRetentionTime,
        archiveRetentionTime: Env.archiveRetentionTime,

        defaultStorageLimit: Env.defaultStorageLimit,

        lastEviction: Env.lastEviction,
        evictionReport: Env.evictionReport,

        disableIntegratedEviction: Env.disableIntegratedEviction,
        disableIntegratedTasks: Env.disableIntegratedTasks,

        maxUploadSize: Env.maxUploadSize,
        premiumUploadSize: Env.premiumUploadSize,
    });
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_LIMITS'], console.log)
var getLimits = function (Env, Server, cb) {
    cb(void 0, Env.limits);
};

var commands = {
    ACTIVE_SESSIONS: getActiveSessions,
    ACTIVE_PADS: getActiveChannelCount,
    REGISTERED_USERS: getRegisteredUsers,
    DISK_USAGE: getDiskUsage,
    FLUSH_CACHE: flushCache,
    SHUTDOWN: shutdown,
    GET_FILE_DESCRIPTOR_COUNT: getFileDescriptorCount,
    GET_FILE_DESCRIPTOR_LIMIT: getFileDescriptorLimit,
    GET_CACHE_STATS: getCacheStats,

    ARCHIVE_DOCUMENT: archiveDocument,
    RESTORE_ARCHIVED_DOCUMENT: restoreArchivedDocument,

    CLEAR_CACHED_CHANNEL_INDEX: clearChannelIndex,
    GET_CACHED_CHANNEL_INDEX: getChannelIndex,

    CLEAR_CACHED_CHANNEL_METADATA: clearChannelMetadata,
    GET_CACHED_CHANNEL_METADATA: getChannelMetadata,

    ADMIN_DECREE: adminDecree,
    INSTANCE_STATUS: instanceStatus,
    GET_LIMITS: getLimits,
    SET_LAST_EVICTION: setLastEviction,
    GET_WORKER_PROFILES: getWorkerProfiles,
};

Admin.command = function (Env, safeKey, data, _cb, Server) {
    var cb = Util.once(Util.mkAsync(_cb));

    var admins = Env.admins;

    var unsafeKey = Util.unescapeKeyCharacters(safeKey);
    if (admins.indexOf(unsafeKey) === -1) {
        return void cb("FORBIDDEN");
    }

    var command = commands[data[0]];

    if (typeof(command) === 'function') {
        return void command(Env, Server, cb, data, unsafeKey);
    }

    return void cb('UNHANDLED_ADMIN_COMMAND');
};

<commit_msg>log when archiving content via the admin panel<commit_after>/*jshint esversion: 6 */
/* globals process */
const nThen = require("nthen");
const getFolderSize = require("get-folder-size");
const Util = require("../common-util");
const Ulimit = require("ulimit");
const Decrees = require("../decrees");

var Fs = require("fs");

var Admin = module.exports;

var getFileDescriptorCount = function (Env, server, cb) {
    Fs.readdir('/proc/self/fd', function(err, list) {
        if (err) { return void cb(err); }
        cb(void 0, list.length);
    });
};

var getFileDescriptorLimit = function (env, server, cb) {
    Ulimit(cb);
};

var getCacheStats = function (env, server, cb) {
    var metaSize = 0;
    var channelSize = 0;
    var metaCount = 0;
    var channelCount = 0;

    try {
        var meta = env.metadata_cache;
        for (var x in meta) {
            if (meta.hasOwnProperty(x)) {
                metaCount++;
                metaSize += JSON.stringify(meta[x]).length;
            }
        }

        var channels = env.channel_cache;
        for (var y in channels) {
            if (channels.hasOwnProperty(y)) {
                channelCount++;
                channelSize += JSON.stringify(channels[y]).length;
            }
        }
    } catch (err) {
        return void cb(err && err.message);
    }

    cb(void 0, {
        metadata: metaCount,
        metaSize: metaSize,
        channel: channelCount,
        channelSize: channelSize,
        memoryUsage: process.memoryUsage(),
    });
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_WORKER_PROFILES'], console.log)
var getWorkerProfiles = function (Env, Server, cb) {
    cb(void 0, Env.commandTimers);
};

var getActiveSessions = function (Env, Server, cb) {
    var stats = Server.getSessionStats();
    cb(void 0, [
        stats.total,
        stats.unique
    ]);
};

var shutdown = function (Env, Server, cb) {
    if (true) {
        return void cb('E_NOT_IMPLEMENTED');
    }

    // disconnect all users and reject new connections
    Server.shutdown();

    // stop all intervals that may be running
    Object.keys(Env.intervals).forEach(function (name) {
        clearInterval(Env.intervals[name]);
    });

    // set a flag to prevent incoming database writes
    // wait until all pending writes are complete
    // then process.exit(0);
    // and allow system functionality to restart the server
};

var getRegisteredUsers = function (Env, Server, cb) {
    Env.batchRegisteredUsers('', cb, function (done) {
        var dir = Env.paths.pin;
        var folders;
        var users = 0;
        nThen(function (waitFor) {
            Fs.readdir(dir, waitFor(function (err, list) {
                if (err) {
                    waitFor.abort();
                    return void done(err);
                }
                folders = list;
            }));
        }).nThen(function (waitFor) {
            folders.forEach(function (f) {
                var dir = Env.paths.pin + '/' + f;
                Fs.readdir(dir, waitFor(function (err, list) {
                    if (err) { return; }
                    users += list.length;
                }));
            });
        }).nThen(function () {
            done(void 0, users);
        });
    });
};

var getDiskUsage = function (Env, Server, cb) {
    Env.batchDiskUsage('', cb, function (done) {
        var data = {};
        nThen(function (waitFor) {
            getFolderSize('./', waitFor(function(err, info) {
                data.total = info;
            }));
            getFolderSize(Env.paths.pin, waitFor(function(err, info) {
                data.pin = info;
            }));
            getFolderSize(Env.paths.blob, waitFor(function(err, info) {
                data.blob = info;
            }));
            getFolderSize(Env.paths.staging, waitFor(function(err, info) {
                data.blobstage = info;
            }));
            getFolderSize(Env.paths.block, waitFor(function(err, info) {
                data.block = info;
            }));
            getFolderSize(Env.paths.data, waitFor(function(err, info) {
                data.datastore = info;
            }));
        }).nThen(function () {
            done(void 0, data);
        });
    });
};

var getActiveChannelCount = function (Env, Server, cb) {
    cb(void 0, Server.getActiveChannelCount());
};

var flushCache = function (Env, Server,  cb) {
    Env.flushCache();
    cb(void 0, true);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['ARCHIVE_DOCUMENT', documentID], console.log)
var archiveDocument = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    switch (id.length) {
        case 32:
        // TODO disconnect users from active sessions
            return void Env.msgStore.archiveChannel(id, Util.both(cb, function (err) {
                Env.Log.info("ARCHIVAL_CHANNEL_BY_ADMIN_RPC", {
                    channelId: id,
                    status: err? String(err): "SUCCESS",
                });
            }));
        case 48:
            return void Env.blobStore.archive.blob(id, Util.both(cb, function (err) {
                Env.Log.info("ARCHIVAL_BLOB_BY_ADMIN_RPC", {
                    id: id,
                    status: err? String(err): "SUCCESS",
                });
            }));
        default:
            return void cb("INVALID_ID_LENGTH");
    }

    // archival for blob proofs isn't automated, but evict-inactive.js will
    // clean up orpaned blob proofs
    // Env.blobStore.archive.proof(userSafeKey, blobId, cb)
};

var restoreArchivedDocument = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    switch (id.length) {
        case 32:
            return void Env.msgStore.restoreArchivedChannel(id, cb);
        case 48:
            // Env.blobStore.restore.proof(userSafekey, id, cb) // XXX ....
            return void Env.blobStore.restore.blob(id, cb);
        default:
            return void cb("INVALID_ID_LENGTH");
    }
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['CLEAR_CACHED_CHANNEL_INDEX', documentID], console.log)
var clearChannelIndex = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }
    delete Env.channel_cache[id];
    cb();
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_CACHED_CHANNEL_INDEX', documentID], console.log)
var getChannelIndex = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    var index = Util.find(Env, ['channel_cache', id]);
    if (!index) { return void cb("ENOENT"); }
    cb(void 0, index);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['CLEAR_CACHED_CHANNEL_METADATA', documentID], console.log)
var clearChannelMetadata = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }
    delete Env.metadata_cache[id];
    cb();
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_CACHED_CHANNEL_METADATA', documentID], console.log)
var getChannelMetadata = function (Env, Server, cb, data) {
    var id = Array.isArray(data) && data[1];
    if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); }

    var index = Util.find(Env, ['metadata_cache', id]);
    if (!index) { return void cb("ENOENT"); }
    cb(void 0, index);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['RESTRICT_REGISTRATION', [true]]], console.log)
var adminDecree = function (Env, Server, cb, data, unsafeKey) {
    var value = data[1];
    if (!Array.isArray(value)) { return void cb('INVALID_DECREE'); }

    var command = value[0];
    var args = value[1];

/*

The admin should have sent a command to be run:

the server adds two pieces of information to the supplied decree:

* the unsafeKey of the admin who uploaded it
* the current time

1. test the command to see if it's valid and will result in a change
2. if so, apply it and write it to the log for persistence
3. respond to the admin with an error or nothing

*/

    var decree = [command, args, unsafeKey, +new Date()];
    var changed;
    try {
        changed = Decrees.handleCommand(Env, decree) || false;
    } catch (err) {
        return void cb(err);
    }

    if (!changed) { return void cb(); }
    Env.Log.info('ADMIN_DECREE', decree);
    Decrees.write(Env, decree, cb);
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['SET_LAST_EVICTION', 0], console.log)
var setLastEviction = function (Env, Server, cb, data, unsafeKey) {
    var time = data && data[1];
    if (typeof(time) !== 'number') {
        return void cb('INVALID_ARGS');
    }

    Env.lastEviction = time;
    cb();
    Env.Log.info('LAST_EVICTION_TIME_SET', {
        author: unsafeKey,
        time: time,
    });
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['INSTANCE_STATUS], console.log)
var instanceStatus = function (Env, Server, cb) {
    cb(void 0, {
        restrictRegistration: Env.restrictRegistration,
        launchTime: Env.launchTime,
        currentTime: +new Date(),

        inactiveTime: Env.inactiveTime,
        accountRetentionTime: Env.accountRetentionTime,
        archiveRetentionTime: Env.archiveRetentionTime,

        defaultStorageLimit: Env.defaultStorageLimit,

        lastEviction: Env.lastEviction,
        evictionReport: Env.evictionReport,

        disableIntegratedEviction: Env.disableIntegratedEviction,
        disableIntegratedTasks: Env.disableIntegratedTasks,

        maxUploadSize: Env.maxUploadSize,
        premiumUploadSize: Env.premiumUploadSize,
    });
};

// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_LIMITS'], console.log)
var getLimits = function (Env, Server, cb) {
    cb(void 0, Env.limits);
};

var commands = {
    ACTIVE_SESSIONS: getActiveSessions,
    ACTIVE_PADS: getActiveChannelCount,
    REGISTERED_USERS: getRegisteredUsers,
    DISK_USAGE: getDiskUsage,
    FLUSH_CACHE: flushCache,
    SHUTDOWN: shutdown,
    GET_FILE_DESCRIPTOR_COUNT: getFileDescriptorCount,
    GET_FILE_DESCRIPTOR_LIMIT: getFileDescriptorLimit,
    GET_CACHE_STATS: getCacheStats,

    ARCHIVE_DOCUMENT: archiveDocument,
    RESTORE_ARCHIVED_DOCUMENT: restoreArchivedDocument,

    CLEAR_CACHED_CHANNEL_INDEX: clearChannelIndex,
    GET_CACHED_CHANNEL_INDEX: getChannelIndex,

    CLEAR_CACHED_CHANNEL_METADATA: clearChannelMetadata,
    GET_CACHED_CHANNEL_METADATA: getChannelMetadata,

    ADMIN_DECREE: adminDecree,
    INSTANCE_STATUS: instanceStatus,
    GET_LIMITS: getLimits,
    SET_LAST_EVICTION: setLastEviction,
    GET_WORKER_PROFILES: getWorkerProfiles,
};

Admin.command = function (Env, safeKey, data, _cb, Server) {
    var cb = Util.once(Util.mkAsync(_cb));

    var admins = Env.admins;

    var unsafeKey = Util.unescapeKeyCharacters(safeKey);
    if (admins.indexOf(unsafeKey) === -1) {
        return void cb("FORBIDDEN");
    }

    var command = commands[data[0]];

    if (typeof(command) === 'function') {
        return void command(Env, Server, cb, data, unsafeKey);
    }

    return void cb('UNHANDLED_ADMIN_COMMAND');
};

<|endoftext|>


<commit_before>/*!
 * jsontransform
 * MIT Licensed
 */
var reform = function (obj, replace) {
    var output = {};
    for (y in replace) {
        if (typeof (replace[y]) == "string") {
            var factors = replace[y].split(".");
            output[y] = obj[factors[0]];
            factors = factors.slice(1);
            for(x in factors){
                output[y]=output[y][factors[x]];
            }
        } else {
            output[y] = reform(obj, replace[y]);
        }
    }
    return output;
}
var transform = function (i, o) {
    if (typeof (i) == "string")
        i = JSON.parse(i);
    var output;
    if (Array.isArray(i)) {
        output = [];
        for (x in i) {
            output[x] = reform(i[x], o.all);
        }
    }else{
        output = reform(i,o.all);
    }
    return output;
};
module.exports = transform;
<commit_msg>Update jsontransform.js<commit_after>/*!
 * jsontransform
 * MIT Licensed
 */
var reform = function (obj, replace) {
    var output = {};
    for (y in replace) {
        if (typeof (replace[y]) == "string") {
            var factors = replace[y].split(".");
            output[y] = obj[factors[0]];
            factors = factors.slice(1);
            for(x in factors){
                if(output[y][factors[x]]){
                    output[y]=output[y][factors[x]];
                }else{
                    delete output[y];
                    break;
                }
            }
        } else {
            output[y] = reform(obj, replace[y]);
        }
    }
    return output;
}
var transform = function (i, o) {
    if (typeof (i) == "string")
        i = JSON.parse(i);
    var output;
    if (Array.isArray(i)) {
        output = [];
        for (x in i) {
            output[x] = reform(i[x], o.all);
        }
    }else{
        output = reform(i,o.all);
    }
    return output;
};
module.exports = transform;
<|endoftext|>


<commit_before>const DIT = 100; const DAH=500; const SPACE=100;
var Torch = require('ti.light');
function sayDit(onready) {
    Torch.turnOn();
    setTimeout(function(){
        Torch.turnOff();
        setTimeout(onready,SPACE);
    },DIT);
}
function sayDah(onready) {
    Torch.turnOn();
    setTimeout(function(){
        Torch.turnOff();
        setTimeout(onready,SPACE);
    },DAH);
}
function sayBreak(onready) {
    setTimeout(onready,SPACE);
}

module.exports  = function(signal) {
    if (!signal) {
        signal = "-- --- .-. ... .";
    }
    var items = signal.split('');
    items.forEach(function(item){
        switch (item) {
            case '.':
                sayDit(callbackFunc);
            break;
            case '-':
                sayDah(callbackFunc);
            break;
            default:
                sayBreak(callbackFunc);
            break;
        }
    });
};
<commit_msg>     <commit_after>const DIT = 100; const DAH=500; const SPACE=100;
var Torch = require('ti.light');
function sayDit(onready) {
    Torch.turnOn();
    setTimeout(function(){
        Torch.turnOff();
        setTimeout(onready,SPACE);
    },DIT);
}
function sayDah(onready) {
    Torch.turnOn();
    setTimeout(function(){
        Torch.turnOff();
        setTimeout(onready,SPACE);
    },DAH);
}
function sayBreak(onready) {
    setTimeout(onready,SPACE);
}

module.exports  = function(signal) {
    if (!signal) {
        signal = "-- --- .-. ... .";
    }
    var items = signal.split('');
    items.forEach(function(item){
        var callbackFunc = function() {};
        switch (item) {
            case '.':
                sayDit(callbackFunc);
            break;
            case '-':
                sayDah(callbackFunc);
            break;
            default:
                sayBreak(callbackFunc);
            break;
        }
    });
};
<|endoftext|>


<commit_before>var Card = function(prompt, response) {
  this.init(prompt, response);
};

Card.prototype.init = function(prompt, response) {
  this.iteration = 1;
  this.setPrompt(prompt);
  this.setResponse(response);
  this.setEasinessFactor();
};

Card.prototype.setPrompt = function(prompt) {
  this.prompt = prompt;
};

Card.prototype.getPrompt = function() {
  return this.prompt;
};

Card.prototype.setResponse = function(response) {
  this.response = response;
};

Card.prototype.getResponse = function() {
  return this.response;
};

Card.prototype.setEasinessFactor = function(grade) {
  var easinessFactor;

  if (this.iteration > 1) {
    easinessFactor = this.easinessFactor + (0.1 - (5 - grade) * (0.08) + (5 - grade) * 0.02);
  } else {
    easinessFactor = 2.5;
  }

  if (easinessFactor < 1.3) {
    easinessFactor = 1.3;
  }

  this.easinessFactor = easinessFactor;
};

Card.prototype.getEasinessFactor = function() {
  return this.easinessFactor;
};

// After second iteration:
// I(n) = I(n-1) * easinessFactor
Card.prototype.setNextRepetitionInterval = function() {
  if (this.iteration === 1) {
    this.nextRepetitionInterval = 1;
  } else if (this.iteration === 2) {
    this.nextRepetitionInterval = 6;
  } else {
    this.nextRepetitionInterval = this.getNextRepetitionInterval() * this.getEasinessFactor();
  }
};

Card.prototype.getNextRepetitionInterval = function() {
  return this.nextRepetitionInterval;
};

Card.prototype.bumpIteration = function() {
  this.iteration++;
};

Card.prototype.iterate = function(grade) {
  this.setEasinessFactor(grade);
  this.setNextRepetitionInterval();
  this.bumpIteration();
};

// If nextRepetitionInterval is a fraction, round it up to the nearest integer.
//
// If the quality response was lower than 3 then start repetitions for the item
// from the beginning without changing the E-Factor (i.e. use intervals I(1),
// I(2) etc. as if the item was memorized anew).
//
// After each repetition session of a given day repeat again all items that
// scored below four in the quality assessment. Continue the repetitions until
// all of these items score at least four.

<commit_msg>export as node module<commit_after>var Card = function(prompt, response) {
  this.init(prompt, response);
};

Card.prototype.init = function(prompt, response) {
  this.iteration = 1;
  this.setPrompt(prompt);
  this.setResponse(response);
  this.setEasinessFactor();
};

Card.prototype.setPrompt = function(prompt) {
  this.prompt = prompt;
};

Card.prototype.getPrompt = function() {
  return this.prompt;
};

Card.prototype.setResponse = function(response) {
  this.response = response;
};

Card.prototype.getResponse = function() {
  return this.response;
};

Card.prototype.setEasinessFactor = function(grade) {
  var easinessFactor;

  if (this.iteration > 1) {
    easinessFactor = this.easinessFactor + (0.1 - (5 - grade) * (0.08) + (5 - grade) * 0.02);
  } else {
    easinessFactor = 2.5;
  }

  if (easinessFactor < 1.3) {
    easinessFactor = 1.3;
  }

  this.easinessFactor = easinessFactor;
};

Card.prototype.getEasinessFactor = function() {
  return this.easinessFactor;
};

// After second iteration:
// I(n) = I(n-1) * easinessFactor
Card.prototype.setNextRepetitionInterval = function() {
  if (this.iteration === 1) {
    this.nextRepetitionInterval = 1;
  } else if (this.iteration === 2) {
    this.nextRepetitionInterval = 6;
  } else {
    this.nextRepetitionInterval = this.getNextRepetitionInterval() * this.getEasinessFactor();
  }
};

Card.prototype.getNextRepetitionInterval = function() {
  return this.nextRepetitionInterval;
};

Card.prototype.bumpIteration = function() {
  this.iteration++;
};

Card.prototype.iterate = function(grade) {
  this.setEasinessFactor(grade);
  this.setNextRepetitionInterval();
  this.bumpIteration();
};

module.exports = Card;

// TODO:
//
// 1) If nextRepetitionInterval is a fraction, round it up to the nearest integer.
//
// 2) If the quality response was lower than 3 then start repetitions for the item
// from the beginning without changing the E-Factor (i.e. use intervals I(1),
// I(2) etc. as if the item was memorized anew).
//
// 3) After each repetition session of a given day repeat again all items that
// scored below four in the quality assessment. Continue the repetitions until
// all of these items score at least four.
<|endoftext|>


<commit_before>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var fs = require('fs');
var path = require('path');
var interaction = require('../util/interaction');

var utils = require('../util/utils');

var WebsitesClient = require('./websites/websitesclient');

exports.init = function (cli) {

  var log = cli.output;
  var site = cli.category('site');
  var scm = site.category('deployment');
  var diagnostic = site.category('log')
    .description('Commands to manage your Web Site diagnostics');

  diagnostic.command('download [name]')
    .description('Download diagnostic log')
    .option('-s, --subscription <id>', 'use the subscription id')
    .option('-o, --output <path>', 'output path, default is local folder')
    .execute(function (name, options, _) {
      var context = {
        subscription: cli.category('account').lookupSubscriptionId(options.subscription),
        path: options.output || '',
        site: {
          name: name
        }
      };

      if (!(/[.]zip$/i.test(context.path))) {
        context.path = path.join(context.path, 'diagnostics.zip');
      }

      if (utils.pathExistsSync(context.path)) {
        if (!site.confirm('Replace existing ' + context.path + '?  (y/n) ', _)) {
          return;
        }
      }

      var repositoryUri = site.ensureRepositoryUri(context, _);
      if (repositoryUri) {
        var buf = doDownloadDiagnostic(context, _);
        log.info('Writing to ' + context.path);
        fs.writeFile(context.path, buf, _);
      } else {
        log.error('Repository is not setup');
      }
    });

  diagnostic.command('tail [name]')
    .description('Live diagnostic log')
    .option('-s, --subscription <id>', 'use the subscription id')
    .option('-p, --path <path>', 'the log path under LogFiles folder')
    .option('-f, --filter <filter>', 'filter matching line')
    .option('--log', 'Write output as log data')
    .execute(function (name, options, _) {
      var context = {
        subscription: cli.category('account').lookupSubscriptionId(options.subscription),
        path: options.path || '',
        filter: options.filter || '',
        site: {
          name: name
        }
      };

      var repositoryUri = site.ensureRepositoryUri(context, _);
      if (repositoryUri) {
        var buf = doLogStream(context, _, function (err, line) {
          if (options.log) {
            log.data('data: ', line);
          } else {
            process.stdout.write(line);
          }
        });
        log.info(buf);
      } else {
        log.error('Repository is not setup');
      }
    });

  diagnostic.command('set [name]')
    .description('Configure diagnostics')
    .option('-a, --application', 'Use this flag to enable application diagnostics.')
    .option('-A, --disable-application', 'Use this flag to disable application diagnostics.')
    .option('-w, --web-server-logging', 'Use this flag to enable web server logging.')
    .option('-W, --disable-web-server-logging', 'Use this flag to disable web server logging.')
    .option('-e, --detailed-error-messages', 'Use this flag to enable detailed error messages.')
    .option('-E, --disable-detailed-error-messages', 'Use this flag to disable detailed error messages.')
    .option('-f, --failed-request-tracing', 'Use this flag to enable failed request tracing.')
    .option('-F, --disable-failed-request-tracing', 'Use this flag to disable failed request tracing.')
    .option('-o, --output <output>', 'Takes file or storage. When -a is specified, use this parameter to specify the output of the log.')
    .option('-l, --level <level>', 'Takes error, warning, verbose or info. When -a is specified, use this parameter to specify the log level. But default is error.')
    .option('-sa, --storageAccount <storageAccount>', 'Use this parameter to specify the storage account where the log will be stored.')
    .option('-s, --subscription <id>', 'use the subscription id')
    .execute(function (name, options, _) {
      if (!(options.webServerLogging ||
        options.disableWebServerLogging ||
        options.detailedErrorMessages ||
        options.disableDetailedErrorMessages ||
        options.failedRequestTracing ||
        options.disableFailedRequestTracing ||
        options.application ||
        options.disableApplication)) {
        throw new Error('Command needs to perform at least one diagnostic change');
      }

      var serviceManagement = createServiceManagementService(options.subscription);

      if (options.application || options.disableApplication) {
        options.output = interaction.chooseIfNotGiven(cli, 'Output: ', 'Getting output options', options.output,
            function (cb) {
              return cb(null, [ 'file', 'storage' ]);
            }, _);

        if (options.output === 'storage') {
          options.storageAccount = interaction.chooseIfNotGiven(cli, 'Storage account: ', 'Getting storage accounts', options.storageAccount,
              function (cb) {
                utils.doServiceManagementOperation(serviceManagement, 'listStorageAccounts', function (err, accounts) {
                  if (err) { return cb(err); }

                  cb(null, accounts.body.map(function (a) {
                    return a.ServiceName;
                  }));
                });
              }, _);
        }

        if (options.level) {
          options.level = options.level.toLowerCase();
          if (options.level !== 'error' &&
            options.level !== 'warning' &&
            options.level !== 'verbose' &&
            options.level !== 'info') {

            throw new Error('Invalid error level');
          }
        } else {
          // Default is error
          options.level = 'error';
        }

        var websitesClient = new WebsitesClient(cli, options.subscription);
        if (options.application === true) {
          websitesClient.enableApplicationDiagnostic(name, options.output, { level: options.level, storageAccount: options.storageAccount }, _);
        } else if (options.disableApplication === true) {
          websitesClient.disableApplicationDiagnostic(name, options.output, { level: options.level, storageAccount: options.storageAccount }, _);
        }
      }

      if (options.webServerLogging ||
        options.disableWebServerLogging ||
        options.detailedErrorMessages ||
        options.disableDetailedErrorMessages ||
        options.failedRequestTracing ||
        options.disableFailedRequestTracing) {

        var context = {
          subscription: cli.category('account').lookupSubscriptionId(options.subscription),
          site: {
            name: name
          }
        };

        site.lookupSiteNameAndWebSpace(context, _);
        var config = site.doSiteConfigGet(context, _);

        if (options.webServerLogging || options.disableWebServerLogging) {
          config.HttpLoggingEnabled = options.webServerLogging === true;
        }

        if (options.detailedErrorMessages || options.disableDetailedErrorMessages) {
          config.DetailedErrorLoggingEnabled = options.detailedErrorMessages === true;
        }

        if (options.failedRequestTracing || options.disableFailedRequestTracing) {
          config.RequestTracingEnabled = options.failedRequestTracing === true;
        }

        site.doSiteConfigPUT(config, context, _);
      }
    });

  function createServiceManagementService(subscription) {
    var account = cli.category('account');
    var subscriptionId = account.lookupSubscriptionId(subscription);
    return utils.createServiceManagementService(subscriptionId, account, log);
  }

  function doDownloadDiagnostic(context, _) {
    var channel = scm.getScmChannel(context)
                    .path('dump');
    var progress = cli.progress('Downloading diagnostic log');
    try {
      return channel.GET(_);
    } finally {
      progress.end();
    }
  }

  function doLogStream(context, _, chunkcb) {
    var channel = scm.getScmChannel(context)
                        .path('logstream');
    if (context.path) {
      channel = channel.path(context.path);
    }
    if (context.filter) {
      channel = channel.query('filter', context.filter);
    }

    return channel.GET(_, chunkcb);
  }
};
<commit_msg>700: Fix incorrect storage listing for disable<commit_after>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var fs = require('fs');
var path = require('path');
var interaction = require('../util/interaction');

var utils = require('../util/utils');

var WebsitesClient = require('./websites/websitesclient');

exports.init = function (cli) {

  var log = cli.output;
  var site = cli.category('site');
  var scm = site.category('deployment');
  var diagnostic = site.category('log')
    .description('Commands to manage your Web Site diagnostics');

  diagnostic.command('download [name]')
    .description('Download diagnostic log')
    .option('-s, --subscription <id>', 'use the subscription id')
    .option('-o, --output <path>', 'output path, default is local folder')
    .execute(function (name, options, _) {
      var context = {
        subscription: cli.category('account').lookupSubscriptionId(options.subscription),
        path: options.output || '',
        site: {
          name: name
        }
      };

      if (!(/[.]zip$/i.test(context.path))) {
        context.path = path.join(context.path, 'diagnostics.zip');
      }

      if (utils.pathExistsSync(context.path)) {
        if (!site.confirm('Replace existing ' + context.path + '?  (y/n) ', _)) {
          return;
        }
      }

      var repositoryUri = site.ensureRepositoryUri(context, _);
      if (repositoryUri) {
        var buf = doDownloadDiagnostic(context, _);
        log.info('Writing to ' + context.path);
        fs.writeFile(context.path, buf, _);
      } else {
        log.error('Repository is not setup');
      }
    });

  diagnostic.command('tail [name]')
    .description('Live diagnostic log')
    .option('-s, --subscription <id>', 'use the subscription id')
    .option('-p, --path <path>', 'the log path under LogFiles folder')
    .option('-f, --filter <filter>', 'filter matching line')
    .option('--log', 'Write output as log data')
    .execute(function (name, options, _) {
      var context = {
        subscription: cli.category('account').lookupSubscriptionId(options.subscription),
        path: options.path || '',
        filter: options.filter || '',
        site: {
          name: name
        }
      };

      var repositoryUri = site.ensureRepositoryUri(context, _);
      if (repositoryUri) {
        var buf = doLogStream(context, _, function (err, line) {
          if (options.log) {
            log.data('data: ', line);
          } else {
            process.stdout.write(line);
          }
        });
        log.info(buf);
      } else {
        log.error('Repository is not setup');
      }
    });

  diagnostic.command('set [name]')
    .description('Configure diagnostics')
    .option('-a, --application', 'Use this flag to enable application diagnostics.')
    .option('-A, --disable-application', 'Use this flag to disable application diagnostics.')
    .option('-w, --web-server-logging', 'Use this flag to enable web server logging.')
    .option('-W, --disable-web-server-logging', 'Use this flag to disable web server logging.')
    .option('-e, --detailed-error-messages', 'Use this flag to enable detailed error messages.')
    .option('-E, --disable-detailed-error-messages', 'Use this flag to disable detailed error messages.')
    .option('-f, --failed-request-tracing', 'Use this flag to enable failed request tracing.')
    .option('-F, --disable-failed-request-tracing', 'Use this flag to disable failed request tracing.')
    .option('-o, --output <output>', 'Takes file or storage. When -a is specified, use this parameter to specify the output of the log.')
    .option('-l, --level <level>', 'Takes error, warning, verbose or info. When -a is specified, use this parameter to specify the log level. But default is error.')
    .option('-sa, --storageAccount <storageAccount>', 'Use this parameter to specify the storage account where the log will be stored.')
    .option('-s, --subscription <id>', 'use the subscription id')
    .execute(function (name, options, _) {
      if (!(options.webServerLogging ||
        options.disableWebServerLogging ||
        options.detailedErrorMessages ||
        options.disableDetailedErrorMessages ||
        options.failedRequestTracing ||
        options.disableFailedRequestTracing ||
        options.application ||
        options.disableApplication)) {
        throw new Error('Command needs to perform at least one diagnostic change');
      }

      var serviceManagement = createServiceManagementService(options.subscription);

      if (options.application || options.disableApplication) {
        options.output = interaction.chooseIfNotGiven(cli, 'Output: ', 'Getting output options', options.output,
            function (cb) {
              return cb(null, [ 'file', 'storage' ]);
            }, _);

        if (options.output === 'storage' && options.application) {
          options.storageAccount = interaction.chooseIfNotGiven(cli, 'Storage account: ', 'Getting storage accounts', options.storageAccount,
              function (cb) {
                utils.doServiceManagementOperation(serviceManagement, 'listStorageAccounts', function (err, accounts) {
                  if (err) { return cb(err); }

                  cb(null, accounts.body.map(function (a) {
                    return a.ServiceName;
                  }));
                });
              }, _);
        }

        if (options.level) {
          options.level = options.level.toLowerCase();
          if (options.level !== 'error' &&
            options.level !== 'warning' &&
            options.level !== 'verbose' &&
            options.level !== 'info') {

            throw new Error('Invalid error level');
          }
        } else {
          // Default is error
          options.level = 'error';
        }

        var websitesClient = new WebsitesClient(cli, options.subscription);
        if (options.application === true) {
          websitesClient.enableApplicationDiagnostic(name, options.output, { level: options.level, storageAccount: options.storageAccount }, _);
        } else if (options.disableApplication === true) {
          websitesClient.disableApplicationDiagnostic(name, options.output, { level: options.level, storageAccount: options.storageAccount }, _);
        }
      }

      if (options.webServerLogging ||
        options.disableWebServerLogging ||
        options.detailedErrorMessages ||
        options.disableDetailedErrorMessages ||
        options.failedRequestTracing ||
        options.disableFailedRequestTracing) {

        var context = {
          subscription: cli.category('account').lookupSubscriptionId(options.subscription),
          site: {
            name: name
          }
        };

        site.lookupSiteNameAndWebSpace(context, _);
        var config = site.doSiteConfigGet(context, _);

        if (options.webServerLogging || options.disableWebServerLogging) {
          config.HttpLoggingEnabled = options.webServerLogging === true;
        }

        if (options.detailedErrorMessages || options.disableDetailedErrorMessages) {
          config.DetailedErrorLoggingEnabled = options.detailedErrorMessages === true;
        }

        if (options.failedRequestTracing || options.disableFailedRequestTracing) {
          config.RequestTracingEnabled = options.failedRequestTracing === true;
        }

        site.doSiteConfigPUT(config, context, _);
      }
    });

  function createServiceManagementService(subscription) {
    var account = cli.category('account');
    var subscriptionId = account.lookupSubscriptionId(subscription);
    return utils.createServiceManagementService(subscriptionId, account, log);
  }

  function doDownloadDiagnostic(context, _) {
    var channel = scm.getScmChannel(context)
                    .path('dump');
    var progress = cli.progress('Downloading diagnostic log');
    try {
      return channel.GET(_);
    } finally {
      progress.end();
    }
  }

  function doLogStream(context, _, chunkcb) {
    var channel = scm.getScmChannel(context)
                        .path('logstream');
    if (context.path) {
      channel = channel.path(context.path);
    }
    if (context.filter) {
      channel = channel.query('filter', context.filter);
    }

    return channel.GET(_, chunkcb);
  }
};
<|endoftext|>


<commit_before>'use strict';

const db = require('../db');
const dbConnectionHandling = require('./dbConnectionHandling');

const createCommitment = function (answerId, data) {
    data.title = data.title || `commitment${answerId}Title`;
    data.description = data.description || `commitment${answerId}Description`;
    data.website = data.website || null;
    data.modified = data.modified || data.created;
    data.modifiedAddress = data.modifiedAddress || data.created;
    data.importTC = data.importTC ? ':ImportTC' : '';
    data.region = data.region || null;
    dbConnectionHandling.getCommands().push(db.cypher().match("(user:User {userId: {adminId}})")
        .create(`(user)-[:IS_ADMIN]->(commitment:Answer:Commitment${data.importTC} {title: {title}, language: {language}, description: {description}, modified: {modified}, modifiedAddress: {modifiedAddress},
        created: {created}, answerId: {answerId}, website: {website}})
        foreach (topic in {topics} | MERGE (:Topic {name: topic})-[:TOPIC]->(commitment))`)
        .with(`commitment`)
        .match(`(region:Region {code: {region}})`)
        .merge(`(region)-[:BELONGS_TO_REGION]->(commitment)`)
        .end({
            answerId: answerId,
            adminId: data.adminId,
            title: data.title,
            description: data.description,
            language: data.language,
            topics: data.topics,
            created: data.created,
            modified: data.modified,
            modifiedAddress: data.modifiedAddress,
            website: data.website,
            region: data.region
        }).getCommand());
};

module.exports = {
    createCommitment
};<commit_msg>Changed direction of BELONGS_TO_REGION relationship.<commit_after>'use strict';

const db = require('../db');
const dbConnectionHandling = require('./dbConnectionHandling');

const createCommitment = function (answerId, data) {
    data.title = data.title || `commitment${answerId}Title`;
    data.description = data.description || `commitment${answerId}Description`;
    data.website = data.website || null;
    data.modified = data.modified || data.created;
    data.modifiedAddress = data.modifiedAddress || data.created;
    data.importTC = data.importTC ? ':ImportTC' : '';
    data.region = data.region || null;
    dbConnectionHandling.getCommands().push(db.cypher().match("(user:User {userId: {adminId}})")
        .create(`(user)-[:IS_ADMIN]->(commitment:Answer:Commitment${data.importTC} {title: {title}, language: {language}, description: {description}, modified: {modified}, modifiedAddress: {modifiedAddress},
        created: {created}, answerId: {answerId}, website: {website}})
        foreach (topic in {topics} | MERGE (:Topic {name: topic})-[:TOPIC]->(commitment))`)
        .with(`commitment`)
        .match(`(region:Region {code: {region}})`)
        .merge(`(region)<-[:BELONGS_TO_REGION]-(commitment)`)
        .end({
            answerId: answerId,
            adminId: data.adminId,
            title: data.title,
            description: data.description,
            language: data.language,
            topics: data.topics,
            created: data.created,
            modified: data.modified,
            modifiedAddress: data.modifiedAddress,
            website: data.website,
            region: data.region
        }).getCommand());
};

module.exports = {
    createCommitment
};<|endoftext|>


<commit_before>const webpack = require('webpack')
const { resolve, join } = require('path')
const projectRoot = resolve(__dirname, '../')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const TerserPlugin = require('terser-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')

const dev = process.env.NODE_ENV !== 'production'
const cordova = process.env.CORDOVA === 'true'
const { backend, proxyTable } = require('./config')

const appEnv = {
  // define the karrot environment
  __ENV: {
    DEV: dev,
    CORDOVA: cordova,
    BACKEND: JSON.stringify(backend),
    KARROT_THEME: JSON.stringify(process.env.KARROT_THEME),
    FCM_SENDER_ID: JSON.stringify(process.env.FCM_SENDER_ID),
    SENTRY_CONFIG: JSON.stringify(process.env.SENTRY_CONFIG),
    SENTRY_APP_CONFIG: JSON.stringify(process.env.SENTRY_APP_CONFIG),
    GIT_SHA1: JSON.stringify(process.env.GIT_SHA1 || process.env.CIRCLE_SHA1),
  },
  // Quasar requires process.env.THEME to be set
  'process.env.THEME': JSON.stringify('mat'),
  // vuelidate wants this
  // see https://github.com/monterail/vuelidate/issues/365
  'process.env.BUILD': JSON.stringify('web'),
}

const styleLoaders = [
  dev ? 'style-loader' : MiniCssExtractPlugin.loader,
  {
    loader: 'css-loader',
    options: { importLoaders: 1 },
  },
  {
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: loader => [
        require('autoprefixer')(),
      ],
    },
  },
]

module.exports = {
  mode: dev ? 'development' : 'production',
  devtool: dev ? 'cheap-module-eval-source-map' : 'source-map',
  entry: {
    app: './src/base/main.js',
  },
  devServer: {
    host: process.env.HOST || 'localhost',
    port: 8080,
    overlay: {
      warnings: true,
      errors: true,
    },
    historyApiFallback: true,
    proxy: proxyTable,
    contentBase: resolve(__dirname, '../src'),
    stats: {
      errorDetails: true,
    },
  },
  output: {
    path: resolve(__dirname, '../dist'),
    publicPath: dev ? '/' : '',
    filename: 'assets/js/[name].[hash].js',
    chunkFilename: 'assets/js/[id].[chunkhash].js',
    pathinfo: false,
  },
  node: false,
  resolve: {
    extensions: [
      '.mat.js', // for use inside quasar
      '.js',
      '.vue',
      '.json',
    ],
    modules: [
      resolve('src'),
      resolve('node_modules'),
    ],
    alias: {
      quasar: 'quasar-framework',
      'quasar-vue-plugin': 'quasar-framework/src/vue-plugin',
      '@': resolve(__dirname, '../src'),
      '>': resolve(__dirname, '../test'),
      variables: resolve(__dirname, '../src/base/style/quasar.variables.styl'),
      slidetoggle: resolve(__dirname, '../src/base/style/karrot.slidetoggle.styl'),
      editbox: resolve(__dirname, '../src/base/style/karrot.editbox.styl'),
    },
    symlinks: false,
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(vue|js)$/,
        loader: 'eslint-loader',
        include: projectRoot,
        exclude: /node_modules/,
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [
          join(projectRoot, 'src'),
          /quasar-framework\/src/,
          /\.mjs$/,
          /\.es6.js$/,
          /\.esm.js$/,
        ],
      },
      {
        test: /\.vue$/,
        exclude: /(node_modules)/,
        use: 'vue-loader',
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[hash:7].[ext]',
          outputPath: (dev ? '' : '/') + 'assets/images',
          publicPath: cordova ? '../images' : '',
        },
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[hash:7].[ext]',
          outputPath: (dev ? '' : '/') + 'assets/fonts',
          publicPath: cordova ? '../fonts' : '',
        },
      },
      {
        test: /\.css$/,
        use: styleLoaders,
      },
      {
        test: /\.(stylus|styl)$/,
        use: [
          ...styleLoaders,
          'stylus-loader',
        ],
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin(appEnv),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'src/base/index.html',
      minify: false,
      cordova,
    }),
    new VueLoaderPlugin(),
    ...(dev ? [
      new HardSourceWebpackPlugin({
        configHash: function (webpackConfig) {
          return require('node-object-hash')({ sort: false }).hash([
            webpackConfig,
            appEnv,
          ])
        },
      }),
    ] : [
      new MiniCssExtractPlugin({
        filename: 'assets/css/[contenthash].css',
      }),
      new BundleAnalyzerPlugin({
        analyzerMode: cordova ? 'disabled' : 'static',
        reportFilename: 'bundlesize.html',
        defaultSizes: 'gzip',
        openAnalyzer: false,
        generateStatsFile: false,
        statsFilename: 'stats.json',
        statsOptions: null,
        logLevel: 'info',
      }),
    ]),
  ],
  optimization: {
    minimizer: [
      new TerserPlugin({
        sourceMap: !dev,
        cache: true,
        parallel: true,
      }),
      new OptimizeCSSAssetsPlugin({}),
    ],
    splitChunks: {
      chunks: 'all',
      minChunks: 2,
      name: dev,
    },
    runtimeChunk: 'single',
  },
}
<commit_msg>remove unused environment variable<commit_after>const webpack = require('webpack')
const { resolve, join } = require('path')
const projectRoot = resolve(__dirname, '../')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const TerserPlugin = require('terser-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')

const dev = process.env.NODE_ENV !== 'production'
const cordova = process.env.CORDOVA === 'true'
const { backend, proxyTable } = require('./config')

const appEnv = {
  // define the karrot environment
  __ENV: {
    DEV: dev,
    CORDOVA: cordova,
    BACKEND: JSON.stringify(backend),
    KARROT_THEME: JSON.stringify(process.env.KARROT_THEME),
    FCM_SENDER_ID: JSON.stringify(process.env.FCM_SENDER_ID),
    SENTRY_CONFIG: JSON.stringify(process.env.SENTRY_CONFIG),
    GIT_SHA1: JSON.stringify(process.env.GIT_SHA1 || process.env.CIRCLE_SHA1),
  },
  // Quasar requires process.env.THEME to be set
  'process.env.THEME': JSON.stringify('mat'),
  // vuelidate wants this
  // see https://github.com/monterail/vuelidate/issues/365
  'process.env.BUILD': JSON.stringify('web'),
}

const styleLoaders = [
  dev ? 'style-loader' : MiniCssExtractPlugin.loader,
  {
    loader: 'css-loader',
    options: { importLoaders: 1 },
  },
  {
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: loader => [
        require('autoprefixer')(),
      ],
    },
  },
]

module.exports = {
  mode: dev ? 'development' : 'production',
  devtool: dev ? 'cheap-module-eval-source-map' : 'source-map',
  entry: {
    app: './src/base/main.js',
  },
  devServer: {
    host: process.env.HOST || 'localhost',
    port: 8080,
    overlay: {
      warnings: true,
      errors: true,
    },
    historyApiFallback: true,
    proxy: proxyTable,
    contentBase: resolve(__dirname, '../src'),
    stats: {
      errorDetails: true,
    },
  },
  output: {
    path: resolve(__dirname, '../dist'),
    publicPath: dev ? '/' : '',
    filename: 'assets/js/[name].[hash].js',
    chunkFilename: 'assets/js/[id].[chunkhash].js',
    pathinfo: false,
  },
  node: false,
  resolve: {
    extensions: [
      '.mat.js', // for use inside quasar
      '.js',
      '.vue',
      '.json',
    ],
    modules: [
      resolve('src'),
      resolve('node_modules'),
    ],
    alias: {
      quasar: 'quasar-framework',
      'quasar-vue-plugin': 'quasar-framework/src/vue-plugin',
      '@': resolve(__dirname, '../src'),
      '>': resolve(__dirname, '../test'),
      variables: resolve(__dirname, '../src/base/style/quasar.variables.styl'),
      slidetoggle: resolve(__dirname, '../src/base/style/karrot.slidetoggle.styl'),
      editbox: resolve(__dirname, '../src/base/style/karrot.editbox.styl'),
    },
    symlinks: false,
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(vue|js)$/,
        loader: 'eslint-loader',
        include: projectRoot,
        exclude: /node_modules/,
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [
          join(projectRoot, 'src'),
          /quasar-framework\/src/,
          /\.mjs$/,
          /\.es6.js$/,
          /\.esm.js$/,
        ],
      },
      {
        test: /\.vue$/,
        exclude: /(node_modules)/,
        use: 'vue-loader',
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[hash:7].[ext]',
          outputPath: (dev ? '' : '/') + 'assets/images',
          publicPath: cordova ? '../images' : '',
        },
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[hash:7].[ext]',
          outputPath: (dev ? '' : '/') + 'assets/fonts',
          publicPath: cordova ? '../fonts' : '',
        },
      },
      {
        test: /\.css$/,
        use: styleLoaders,
      },
      {
        test: /\.(stylus|styl)$/,
        use: [
          ...styleLoaders,
          'stylus-loader',
        ],
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin(appEnv),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'src/base/index.html',
      minify: false,
      cordova,
    }),
    new VueLoaderPlugin(),
    ...(dev ? [
      new HardSourceWebpackPlugin({
        configHash: function (webpackConfig) {
          return require('node-object-hash')({ sort: false }).hash([
            webpackConfig,
            appEnv,
          ])
        },
      }),
    ] : [
      new MiniCssExtractPlugin({
        filename: 'assets/css/[contenthash].css',
      }),
      new BundleAnalyzerPlugin({
        analyzerMode: cordova ? 'disabled' : 'static',
        reportFilename: 'bundlesize.html',
        defaultSizes: 'gzip',
        openAnalyzer: false,
        generateStatsFile: false,
        statsFilename: 'stats.json',
        statsOptions: null,
        logLevel: 'info',
      }),
    ]),
  ],
  optimization: {
    minimizer: [
      new TerserPlugin({
        sourceMap: !dev,
        cache: true,
        parallel: true,
      }),
      new OptimizeCSSAssetsPlugin({}),
    ],
    splitChunks: {
      chunks: 'all',
      minChunks: 2,
      name: dev,
    },
    runtimeChunk: 'single',
  },
}
<|endoftext|>


<commit_before>const findBaseLength = () => {
  for (let n = 2; ; n += 2) {
    const b = Math.pow(10, n);
    if (2 * b - 2 == 2 * b - 1 || -2 * b + 2 == -2 * b + 1)
      return n - 2;
  }
};

export function extend(baseOps, baseLength = 0) {

  const BASE_LENGTH = (baseLength & ~1) || findBaseLength();

  const BASE = Math.pow(10, BASE_LENGTH);
  const HALFBASE = Math.sqrt(BASE);

  const ZEROES = ('' + BASE).slice(1);

  const zeroFill = s => ZEROES.slice(s.length) + s;

  class LongInt {
    constructor(sign, digits) {
      if (digits.some(d => d < 0 || d >= BASE))
        throw new Error(`illegal long integer digits ${digits}`);
      this.sign = sign;
      this.digits = digits;
    }

    toString() {
      if (_isZero(this))
        return '0';
      else if (this.sign < 0)
        return '-' + negative(this).toString();
      else {
        const s = [];
        let t = this.digits;
        while (t.length > 0) {
          const q = _idiv(t, [10]);
          const r = _minus(t, _times(q, [10]));
          s.push(r[0] || 0);
          t = q;
        }
        return s.reverse().join('');
      }
    }
  };

  const make = (s, d) => {
    if (d.length > 1)
      return new LongInt(s, d);
    else if (d.length == 1)
      return s * d[0];
    else
      return 0;
  }

  const shouldPromote = n => Math.abs(n) >= BASE;

  const promote = function promote(n) {
    const sign = (n > 0) - (n < 0);
    n = Math.abs(n);

    const digits = [];
    while (n > 0) {
      digits.push(n % BASE);
      n = Math.floor(n / BASE);
    }

    return new LongInt(sign, digits);
  };

  const toJS = n => {
    if (n.sign == 0)
      return 0;
    else
      return (n.sign * n.digits[0] * Math.pow(BASE, n.digits.length - 1));
  };

  const _last = a => a[a.length - 1];

  const parse = function parse(literal) {
    if (!literal.match(/^[+-]?\d{1,3}(_?\d{3})*$/))
      throw new Error("expected an integer literal, got "+literal);

    const s = literal.replace(/^[+-]/, '').replace(/_/g, '');

    let digits = [];
    for (let i = 0; i < s.length; ++i)
      digits = _plus(_times(digits, [10]), [parseInt(s[i])]);

    while (digits.length > 0 && _last(digits) == 0)
      digits.pop();

    const sign = digits.length == 0 ? 0 : literal[0] == '-' ? -1 : 1;

    return make(sign, digits);
  };

  const negative = n => make(-n.sign, n.digits);
  const abs      = n => sgn(n) ? make(1, n.digits) : n;
  const sgn      = n => n.sign;
  const _isZero  = n => n.sign == 0;
  const isEven   = n => _isZero(n) || n.digits[0] % 2 == 0;

  const _cmp = function _cmp(r, s) {
    if (r.length != s.length)
      return r.length - s.length;

    for (let i = r.length - 1; i >= 0; --i)
      if (r[i] != s[i])
        return r[i] - s[i];

    return 0;
  };

  const _plus = function _plus(r, s) {
    const result = [];
    let carry = 0;
    let i = 0;
    while (i < r.length || i < s.length || carry) {
      const digit = (r[i] || 0) + (s[i] || 0) + carry;
      carry = digit >= BASE;
      result.push(digit % BASE);
      ++i;
    }
    return result;
  };

  const _minus = function _minus(r, s) {
    const result = [];
    let borrow = 0;
    let i = 0;
    while (i < r.length || i < s.length) {
      const digit = (r[i] || 0) - (s[i] || 0) - borrow;
      borrow = digit < 0;
      result.push((digit + BASE) % BASE);
      ++i;
    }
    if (borrow)
      throw new Error("panic: internal function called with bad arguments");

    while (_last(result) == 0)
      result.pop();
    return result;
  };

  const cmp = function cmp(a, b) {
    if (_isZero(a))
      return -b.sign;
    else if (_isZero(b))
      return a.sign;
    else if (a.sign != b.sign)
      return a.sign;
    else
      return a.sign * _cmp(a.digits, b.digits);
  };

  const _negative = n => new LongInt(-n.sign, n.digits);

  const plus = function plus(a, b) {
    if (_isZero(a))
      return b;
    else if (_isZero(b))
      return a;
    else if (a.sign != b.sign)
      return minus(a, _negative(b));
    else
      return make(a.sign, _plus(a.digits, b.digits));
  };

  const minus = function minus(a, b) {
    if (_isZero(a))
      return negative(b);
    else if (_isZero(b))
      return a;
    else if (a.sign != b.sign)
      return plus(a, _negative(b));
    else {
      const d = _cmp(a.digits, b.digits);
      if (d == 0)
        return 0;
      else if (d < 0)
        return make(-a.sign, _minus(b.digits, a.digits));
      else
        return make(a.sign, _minus(a.digits, b.digits));
    }
  }

  const _lo = d => d % HALFBASE;
  const _hi = d => Math.floor(d / HALFBASE);

  const _digitByDigit = function _digitByDigit(a, b) {
    if (b < BASE / a)
      return [a*b, 0];
    else {
      const alo = _lo(a);
      const ahi = _hi(a);
      const blo = _lo(b);
      const bhi = _hi(b);

      const m = alo * bhi + blo * ahi;
      const lo = alo * blo + _lo(m) * HALFBASE;

      return [lo % BASE, ahi * bhi + _hi(m) + (lo >= BASE)];
    }
  };

  const _seqByDigit = function _seqByDigit(s, d) {
    const result = [];
    let carry = 0;
    for (let i = 0; i < s.length; ++i) {
      const t = _digitByDigit(d, s[i]);
      result.push((t[0] + carry) % BASE);
      carry = t[1] + (t[0] + carry >= BASE);
    }
    if (carry)
      result.push(carry);
    return result;
  };

  const _times = function _times(r, s) {
    const result = [];
    let tmp = [];
    for (let i = 0; i < r.length; ++i) {
      tmp = _plus(tmp, _seqByDigit(s, r[i]));
      result.push(tmp.shift());
    }
    for (let i = 0; i < tmp.length; ++i)
      result.push(tmp[i]);
    return result;
  };

  const times = function times(a, b) {
    if (_isZero(a))
      return a;
    else if (_isZero(b))
      return b;
    else
      return make(a.sign * b.sign, _times(a.digits, b.digits));
  };

  const _idiv = function _idiv(r, s) {
    const scale = Math.floor((BASE - 1) / _last(s));
    const rs = _seqByDigit(r, scale);
    const ss = _seqByDigit(s, scale);
    const m = ss.length;
    const d = _last(ss) + 1;

    let q = [];
    let h = [];
    let t = rs;

    let f, n, ssf;

    while (true) {
      while (_last(q) == 0)
        q.pop();

      if (_cmp(h, ss) >= 0) {
        n = _last(h) * (h.length > m ? BASE : 1);
        f = Math.floor(n / d) || 1;
        ssf = _seqByDigit(ss, f);
        if (_cmp(h, ssf) < 0) {
          --f;
          ssf = _minus(ssf, ss);
        }
        q = _plus(q, [f]);
        h = _minus(h, ssf);
      } else if (t.length) {
        q.unshift(0);
        h.unshift(_last(t))
        t.pop();
      } else
        return q;
    }
  };

  const idiv = function idiv(a, b) {
    if (b.sign == 0)
      throw new Error('division by zero');

    const d = _cmp(a.digits, b.digits);

    if (d < 0)
      return 0;
    else if (d == 0)
      return a.sign * b.sign;
    else {
      const s = a.sign * b.sign;
      if (s > 0)
        return make(s, _idiv(a.digits, b.digits));
      else
        return make(s, _idiv(_plus(a.digits, _minus(b.digits, [1])), b.digits));
    }
  };

  const gcd = (a, b) => {
    a = Math.abs(a);
    b = Math.abs(b);

    while (b > 0)
      [a, b] = [b, a % b];

    return a;
  };

  const checkedOperator = (longMethod, nativeMethod) => (x, y) => {
    const t = nativeMethod(x, y);
    if (shouldPromote(x) || shouldPromote(y) || shouldPromote(t))
      return longMethod(promote(x), promote(y));
    else
      return t;
  };

  return baseOps.register({
    isInteger: {
      LongInt: x => true,
      Integer: x => true
    },
    isRational: {
      LongInt: x => true,
      Integer: x => true
    },
    isReal: {
      LongInt: x => true,
      Integer: x => true
    },
    integer: {
      String : parse,
      LongInt: x => x,
      Integer: x => x
    },
    toJS: {
      LongInt: toJS,
      Integer: x => x
    },
    negative: {
      LongInt: negative,
      Integer: x => -x
    },
    abs: {
      LongInt: abs,
      Integer: x => Math.abs(x)
    },
    sgn: {
      LongInt: sgn,
      Integer: x => (x > 0) - (x < 0)
    },
    isEven: {
      LongInt: isEven,
      Integer: x => x % 2 == 0
    },
    floor: {
      LongInt: x => x,
      Integer: x => x
    },
    ceil: {
      LongInt: x => x,
      Integer: x => x
    },
    round: {
      LongInt: x => x,
      Integer: x => x
    },
    cmp: {
      LongInt: {
        LongInt: cmp,
        Integer: (x, y) => cmp(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => cmp(promote(x), y),
        Integer: (x, y) => (x > y) - (x < y)
      }
    },
    plus: {
      LongInt: {
        LongInt: plus,
        Integer: (x, y) => plus(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => plus(promote(x), y),
        Integer: checkedOperator(plus, (x, y) => x + y)
      }
    },
    minus: {
      LongInt: {
        LongInt: minus,
        Integer: (x, y) => minus(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => minus(promote(x), y),
        Integer: checkedOperator(minus, (x, y) => x - y)
      }
    },
    times: {
      LongInt: {
        LongInt: times,
        Integer: (x, y) => times(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => times(promote(x), y),
        Integer: checkedOperator(times, (x, y) => x * y)
      }
    },
    idiv: {
      LongInt: {
        LongInt: idiv,
        Integer: (x, y) => idiv(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => idiv(promote(x), y),
        Integer: (x, y) => Math.floor(x / y)
      }
    },
    mod: {
      Integer: {
        Integer: (x, y) => x % y + (x % y < 0 ? y : 0)
      }
    },
    gcd: {
      Integer: {
        Integer: gcd
      }
    },
    __repr__: { LongInt: x => ({ sign: x.sign, digits: x.digits }) },
    __Integer__: { Object: ({ Integer: n }) => n },
    __LongInt__: { Object: ({ LongInt: obj }) => make(obj.sign, obj.digits) }
  });
};

if (require.main == module) {
  const ops = extend(require('./base').arithmetic());
  const timer = require('../common/util').timer();

  const N = 59;
  let t = 1;

  for (let i = 1; i < N; ++i) {
    t = ops.times(t, i);
    console.log(`${t}`);
  }

  console.log(`${ops.idiv(ops.plus(t, 1), t)}`);
  console.log(`${ops.idiv(ops.negative(ops.plus(t, 1)), t)}`);
  console.log(`${ops.integer(t.toString())}`);
  console.log(`${ops.idiv(ops.plus(t, 1), ops.negative(t))}`);
  console.log(`${ops.idiv(ops.negative(ops.plus(t, 1)), ops.negative(t))}`);

  for (let i = 1; i < N; ++i) {
    t = ops.idiv(t, i);
    console.log(`${t}`);
  }

  console.log(`${ops.integer('-12_345_678_901_234_567_890')}`);

  console.log();
  console.log(`Computation time: ${timer()} msec`);
}
<commit_msg>switch to a power of 2 (instead of 10) for long int base<commit_after>const findBaseLength = () => {
  for (let n = 2; ; n += 2) {
    const b = Math.pow(2, n);
    if (2 * b - 2 == 2 * b - 1 || -2 * b + 2 == -2 * b + 1)
      return n - 2;
  }
};

export function extend(baseOps, baseLength = 0) {

  const BASE_LENGTH = (baseLength & ~1) || findBaseLength();

  const BASE = Math.pow(2, BASE_LENGTH);
  const HALFBASE = Math.sqrt(BASE);

  const ZEROES = ('' + BASE).slice(1);

  const zeroFill = s => ZEROES.slice(s.length) + s;

  class LongInt {
    constructor(sign, digits) {
      if (digits.some(d => d < 0 || d >= BASE))
        throw new Error(`illegal long integer digits ${digits}`);
      this.sign = sign;
      this.digits = digits;
    }

    toString() {
      if (_isZero(this))
        return '0';
      else if (this.sign < 0)
        return '-' + negative(this).toString();
      else {
        const s = [];
        let t = this.digits;
        while (t.length > 0) {
          const q = _idiv(t, [10]);
          const r = _minus(t, _times(q, [10]));
          s.push(r[0] || 0);
          t = q;
        }
        return s.reverse().join('');
      }
    }
  };

  const make = (s, d) => {
    if (d.length > 1)
      return new LongInt(s, d);
    else if (d.length == 1)
      return s * d[0];
    else
      return 0;
  }

  const shouldPromote = n => Math.abs(n) >= BASE;

  const promote = function promote(n) {
    const sign = (n > 0) - (n < 0);
    n = Math.abs(n);

    const digits = [];
    while (n > 0) {
      digits.push(n % BASE);
      n = Math.floor(n / BASE);
    }

    return new LongInt(sign, digits);
  };

  const toJS = n => {
    if (n.sign == 0)
      return 0;
    else
      return (n.sign * n.digits[0] * Math.pow(BASE, n.digits.length - 1));
  };

  const _last = a => a[a.length - 1];

  const parse = function parse(literal) {
    if (!literal.match(/^[+-]?\d{1,3}(_?\d{3})*$/))
      throw new Error("expected an integer literal, got "+literal);

    const s = literal.replace(/^[+-]/, '').replace(/_/g, '');

    let digits = [];
    for (let i = 0; i < s.length; ++i)
      digits = _plus(_times(digits, [10]), [parseInt(s[i])]);

    while (digits.length > 0 && _last(digits) == 0)
      digits.pop();

    const sign = digits.length == 0 ? 0 : literal[0] == '-' ? -1 : 1;

    return make(sign, digits);
  };

  const negative = n => make(-n.sign, n.digits);
  const abs      = n => sgn(n) ? make(1, n.digits) : n;
  const sgn      = n => n.sign;
  const _isZero  = n => n.sign == 0;
  const isEven   = n => _isZero(n) || n.digits[0] % 2 == 0;

  const _cmp = function _cmp(r, s) {
    if (r.length != s.length)
      return r.length - s.length;

    for (let i = r.length - 1; i >= 0; --i)
      if (r[i] != s[i])
        return r[i] - s[i];

    return 0;
  };

  const _plus = function _plus(r, s) {
    const result = [];
    let carry = 0;
    let i = 0;
    while (i < r.length || i < s.length || carry) {
      const digit = (r[i] || 0) + (s[i] || 0) + carry;
      carry = digit >= BASE;
      result.push(digit % BASE);
      ++i;
    }
    return result;
  };

  const _minus = function _minus(r, s) {
    const result = [];
    let borrow = 0;
    let i = 0;
    while (i < r.length || i < s.length) {
      const digit = (r[i] || 0) - (s[i] || 0) - borrow;
      borrow = digit < 0;
      result.push((digit + BASE) % BASE);
      ++i;
    }
    if (borrow)
      throw new Error("panic: internal function called with bad arguments");

    while (_last(result) == 0)
      result.pop();
    return result;
  };

  const cmp = function cmp(a, b) {
    if (_isZero(a))
      return -b.sign;
    else if (_isZero(b))
      return a.sign;
    else if (a.sign != b.sign)
      return a.sign;
    else
      return a.sign * _cmp(a.digits, b.digits);
  };

  const _negative = n => new LongInt(-n.sign, n.digits);

  const plus = function plus(a, b) {
    if (_isZero(a))
      return b;
    else if (_isZero(b))
      return a;
    else if (a.sign != b.sign)
      return minus(a, _negative(b));
    else
      return make(a.sign, _plus(a.digits, b.digits));
  };

  const minus = function minus(a, b) {
    if (_isZero(a))
      return negative(b);
    else if (_isZero(b))
      return a;
    else if (a.sign != b.sign)
      return plus(a, _negative(b));
    else {
      const d = _cmp(a.digits, b.digits);
      if (d == 0)
        return 0;
      else if (d < 0)
        return make(-a.sign, _minus(b.digits, a.digits));
      else
        return make(a.sign, _minus(a.digits, b.digits));
    }
  }

  const _lo = d => d % HALFBASE;
  const _hi = d => Math.floor(d / HALFBASE);

  const _digitByDigit = function _digitByDigit(a, b) {
    if (b < BASE / a)
      return [a*b, 0];
    else {
      const alo = _lo(a);
      const ahi = _hi(a);
      const blo = _lo(b);
      const bhi = _hi(b);

      const m = alo * bhi + blo * ahi;
      const lo = alo * blo + _lo(m) * HALFBASE;

      return [lo % BASE, ahi * bhi + _hi(m) + (lo >= BASE)];
    }
  };

  const _seqByDigit = function _seqByDigit(s, d) {
    const result = [];
    let carry = 0;
    for (let i = 0; i < s.length; ++i) {
      const t = _digitByDigit(d, s[i]);
      result.push((t[0] + carry) % BASE);
      carry = t[1] + (t[0] + carry >= BASE);
    }
    if (carry)
      result.push(carry);
    return result;
  };

  const _times = function _times(r, s) {
    const result = [];
    let tmp = [];
    for (let i = 0; i < r.length; ++i) {
      tmp = _plus(tmp, _seqByDigit(s, r[i]));
      result.push(tmp.shift());
    }
    for (let i = 0; i < tmp.length; ++i)
      result.push(tmp[i]);
    return result;
  };

  const times = function times(a, b) {
    if (_isZero(a))
      return a;
    else if (_isZero(b))
      return b;
    else
      return make(a.sign * b.sign, _times(a.digits, b.digits));
  };

  const _idiv = function _idiv(r, s) {
    const scale = Math.floor((BASE - 1) / _last(s));
    const rs = _seqByDigit(r, scale);
    const ss = _seqByDigit(s, scale);
    const m = ss.length;
    const d = _last(ss) + 1;

    let q = [];
    let h = [];
    let t = rs;

    let f, n, ssf;

    while (true) {
      while (_last(q) == 0)
        q.pop();

      if (_cmp(h, ss) >= 0) {
        n = _last(h) * (h.length > m ? BASE : 1);
        f = Math.floor(n / d) || 1;
        ssf = _seqByDigit(ss, f);
        if (_cmp(h, ssf) < 0) {
          --f;
          ssf = _minus(ssf, ss);
        }
        q = _plus(q, [f]);
        h = _minus(h, ssf);
      } else if (t.length) {
        q.unshift(0);
        h.unshift(_last(t))
        t.pop();
      } else
        return q;
    }
  };

  const idiv = function idiv(a, b) {
    if (b.sign == 0)
      throw new Error('division by zero');

    const d = _cmp(a.digits, b.digits);

    if (d < 0)
      return 0;
    else if (d == 0)
      return a.sign * b.sign;
    else {
      const s = a.sign * b.sign;
      if (s > 0)
        return make(s, _idiv(a.digits, b.digits));
      else
        return make(s, _idiv(_plus(a.digits, _minus(b.digits, [1])), b.digits));
    }
  };

  const gcd = (a, b) => {
    a = Math.abs(a);
    b = Math.abs(b);

    while (b > 0)
      [a, b] = [b, a % b];

    return a;
  };

  const checkedOperator = (longMethod, nativeMethod) => (x, y) => {
    const t = nativeMethod(x, y);
    if (shouldPromote(x) || shouldPromote(y) || shouldPromote(t))
      return longMethod(promote(x), promote(y));
    else
      return t;
  };

  return baseOps.register({
    isInteger: {
      LongInt: x => true,
      Integer: x => true
    },
    isRational: {
      LongInt: x => true,
      Integer: x => true
    },
    isReal: {
      LongInt: x => true,
      Integer: x => true
    },
    integer: {
      String : parse,
      LongInt: x => x,
      Integer: x => x
    },
    toJS: {
      LongInt: toJS,
      Integer: x => x
    },
    negative: {
      LongInt: negative,
      Integer: x => -x
    },
    abs: {
      LongInt: abs,
      Integer: x => Math.abs(x)
    },
    sgn: {
      LongInt: sgn,
      Integer: x => (x > 0) - (x < 0)
    },
    isEven: {
      LongInt: isEven,
      Integer: x => x % 2 == 0
    },
    floor: {
      LongInt: x => x,
      Integer: x => x
    },
    ceil: {
      LongInt: x => x,
      Integer: x => x
    },
    round: {
      LongInt: x => x,
      Integer: x => x
    },
    cmp: {
      LongInt: {
        LongInt: cmp,
        Integer: (x, y) => cmp(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => cmp(promote(x), y),
        Integer: (x, y) => (x > y) - (x < y)
      }
    },
    plus: {
      LongInt: {
        LongInt: plus,
        Integer: (x, y) => plus(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => plus(promote(x), y),
        Integer: checkedOperator(plus, (x, y) => x + y)
      }
    },
    minus: {
      LongInt: {
        LongInt: minus,
        Integer: (x, y) => minus(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => minus(promote(x), y),
        Integer: checkedOperator(minus, (x, y) => x - y)
      }
    },
    times: {
      LongInt: {
        LongInt: times,
        Integer: (x, y) => times(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => times(promote(x), y),
        Integer: checkedOperator(times, (x, y) => x * y)
      }
    },
    idiv: {
      LongInt: {
        LongInt: idiv,
        Integer: (x, y) => idiv(x, promote(y))
      },
      Integer: {
        LongInt: (x, y) => idiv(promote(x), y),
        Integer: (x, y) => Math.floor(x / y)
      }
    },
    mod: {
      Integer: {
        Integer: (x, y) => x % y + (x % y < 0 ? y : 0)
      }
    },
    gcd: {
      Integer: {
        Integer: gcd
      }
    },
    __repr__: { LongInt: x => ({ sign: x.sign, digits: x.digits }) },
    __Integer__: { Object: ({ Integer: n }) => n },
    __LongInt__: { Object: ({ LongInt: obj }) => make(obj.sign, obj.digits) }
  });
};

if (require.main == module) {
  const ops = extend(require('./base').arithmetic());
  const timer = require('../common/util').timer();

  const N = 59;
  let t = 1;

  for (let i = 1; i < N; ++i) {
    t = ops.times(t, i);
    console.log(`${t}`);
  }

  console.log(`${ops.idiv(ops.plus(t, 1), t)}`);
  console.log(`${ops.idiv(ops.negative(ops.plus(t, 1)), t)}`);
  console.log(`${ops.integer(t.toString())}`);
  console.log(`${ops.idiv(ops.plus(t, 1), ops.negative(t))}`);
  console.log(`${ops.idiv(ops.negative(ops.plus(t, 1)), ops.negative(t))}`);

  for (let i = 1; i < N; ++i) {
    t = ops.idiv(t, i);
    console.log(`${t}`);
  }

  console.log(`${ops.integer('-12_345_678_901_234_567_890')}`);

  console.log();
  console.log(`Computation time: ${timer()} msec`);
}
<|endoftext|>


<commit_before>/**
 *
 * This wait command is your universal weapon if you want to wait on
 * something. It expects a condition and waits until that condition
 * is fulfilled with an truthy value. A condition can be either a promise
 * or a command that returns a promise.
 *
 * A common example is to wait until a certain element contains a certain
 * text.
 *
 * <example>
    :example.html

I am some text

    :waitUntil.js
    client.waitUntil(function() {
      return this.getText('#someText').then(function(text) {
        return text === 'I am now different'
      });
    });
 * </example>
 *
 *
 * @param {Function|Promise} condition  condition to wait on
 * @param {Number=}          ms         timeout in ms (default: 500)
 * @param {Number=}          interval   interval between condition checks (default: 250)
 *
 * @uses utility/pause
 * @type utility
 *
 */

import { CommandError } from '../utils/ErrorHandler'
import Timer from '../utils/Timer'

export default function (condition, timeout, interval) {
    /*!
     * ensure that timeout and interval are set properly
     */
    if (typeof timeout !== 'number') {
        timeout = this.options.waitforTimeout
    }

    if (typeof interval !== 'number') {
        interval = this.options.waitforInterval
    }

    let fn

    if (typeof condition === 'function') {
        fn = condition
    } else {
        fn = () => Promise.resolve(condition)
    }

    let timer = new Timer(interval, timeout, fn, true)

    return timer.catch(function (e) {
        throw new CommandError(`Promise was rejected with the following reason: ${e}`)
    })
}
<commit_msg>Bind condition with this value<commit_after>/**
 *
 * This wait command is your universal weapon if you want to wait on
 * something. It expects a condition and waits until that condition
 * is fulfilled with an truthy value. A condition can be either a promise
 * or a command that returns a promise.
 *
 * A common example is to wait until a certain element contains a certain
 * text.
 *
 * <example>
    :example.html

I am some text

    :waitUntil.js
    client.waitUntil(function() {
      return this.getText('#someText').then(function(text) {
        return text === 'I am now different'
      });
    });
 * </example>
 *
 *
 * @param {Function|Promise} condition  condition to wait on
 * @param {Number=}          ms         timeout in ms (default: 500)
 * @param {Number=}          interval   interval between condition checks (default: 250)
 *
 * @uses utility/pause
 * @type utility
 *
 */

import { CommandError } from '../utils/ErrorHandler'
import Timer from '../utils/Timer'

export default function (condition, timeout, interval) {
    /*!
     * ensure that timeout and interval are set properly
     */
    if (typeof timeout !== 'number') {
        timeout = this.options.waitforTimeout
    }

    if (typeof interval !== 'number') {
        interval = this.options.waitforInterval
    }

    let fn

    if (typeof condition === 'function') {
        fn = condition.bind(this)
    } else {
        fn = () => Promise.resolve(condition)
    }

    let timer = new Timer(interval, timeout, fn, true)

    return timer.catch(function (e) {
        throw new CommandError(`Promise was rejected with the following reason: ${e}`)
    })
}
<|endoftext|>


<commit_before>/*!
 * chai
 * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

var exports = module.exports = {};

exports.version = '0.2.4';

exports.Assertion = require('./assertion');
exports.AssertionError = require('./error');

exports.inspect = require('./utils/inspect');

exports.use = function (fn) {
  fn(this);
  return this;
};

exports.fail = function (actual, expected, message, operator, stackStartFunction) {
  throw new exports.AssertionError({
    message: message,
    actual: actual,
    expected: expected,
    operator: operator,
    stackStartFunction: stackStartFunction
  });
};

var expect = require('./interface/expect');
exports.use(expect);

var should = require('./interface/should');
exports.use(should);

var assert = require('./interface/assert');
exports.use(assert);
<commit_msg>Make `chai.use` a no-op if the function has already been used.<commit_after>/*!
 * chai
 * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

var used = [];
var exports = module.exports = {};

exports.version = '0.2.4';

exports.Assertion = require('./assertion');
exports.AssertionError = require('./error');

exports.inspect = require('./utils/inspect');

exports.use = function (fn) {
  if (used.indexOf(fn) === -1) {
    fn(this);
    used.push(fn);
  }

  return this;
};

exports.fail = function (actual, expected, message, operator, stackStartFunction) {
  throw new exports.AssertionError({
    message: message,
    actual: actual,
    expected: expected,
    operator: operator,
    stackStartFunction: stackStartFunction
  });
};

var expect = require('./interface/expect');
exports.use(expect);

var should = require('./interface/should');
exports.use(should);

var assert = require('./interface/assert');
exports.use(assert);
<|endoftext|>