<commit_before>// matter.js
//

'use strict';

var createError  = require('../createError');
var colliderfile = require('../colliderfile');
var logErrorExit = require('../logErrorExit');
var pkg = require('../../package.json');

var fs   = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var url  = require('url');

var _ = require('lodash');
var docopt = require('docopt').docopt;
var rimraf = require('rimraf');
var which = require('which');

var doc = `
usage:
  collider matter
  collider matter clone <url> [<locale>]
  collider matter (rm | remove) <locale>

options:
  -h, --help  Show help information.
  --version   Show program version.

commands:
  clone       Clone a Matter library into the current project.
  remove, rm  Remove a Matter library from the current project.

  With no command, 'matter' shows a list of Matter libraries in the current project.
`;

module.exports = function (argv) {

  var args = docopt(doc, {
    argv: argv,
    version: `Collider CLI ${pkg.version}`,
  });

  dispatchOn(['matter'], args, matterList);
  dispatchOn(['matter', 'clone'], args, matterClone);
  dispatchOn(['matter', 'remove'], args, matterRemove);
  dispatchOn(['matter', 'rm'], args, matterRemove);
};

// FUNCTIONS
//

/**
 * Dispatch a callback when the given commands match those given to docopts.
 * @param  {Array}    commands An array of commands to match.
 * @param  {Object}   args     A docopts arguments object.
 * @param  {Function} callback The command handler to call.
 */
function dispatchOn(commands, args, callback) {
  var haystack = [];

  // For each truthy and Boolean-type arg, push its name into 'haystack'.
  _.forEach(args, function (val, key) {
    if (val === true) haystack.push(key);
  });

  // If 'commands' and 'haystack' match, then fire our callback.
  if (_.isEqual(commands.sort(), haystack.sort())) {
    callback(args);
  }
}

function matterList() {
  colliderfile.get('.', printMatterInfo);

  function printMatterInfo(data) {
    var matterLibs = data.matterLibs;
    var librarySingOrPlur = matterLibs.length > 1 ? 'libraries' : 'library';

    if (matterLibs.length > 0) {
      console.log();
      console.log(`'${data.name}' has ${matterLibs.length} Matter ${librarySingOrPlur}:`);

      matterLibs.forEach(function (library, i) {
        console.log();
        console.log(`${i + 1}. ${library.locale}`);
        console.log(`   ${library.url}`);
      });

      console.log();
    } else {
      console.log();
      console.log(`'${data.name}' has 0 Matter libraries. See 'collider matter --help'.`);
      console.log();
    }
  }
}

function matterClone(args) {
  var args = {
    url: args['<url>'],
    locale: args['<locale>'],
  };

  // Re-assign the parsed URL to 'args.url'. The original can be found at 'args.url.href'.
  args.url = url.parse(args.url);

  // Verify the clone URL protocol is 'https:' or exit.
  var protocol = args.url.protocol;
  if (protocol !== 'https:') {
    var err = createError(
      `"${protocol}" is an unsupported protocol. URLs should start with "https:".`
    );
    logErrorExit(err, true);
  }

  // Set locale to the repo. name if it wasn't given.
  if (!args.locale) {
    args.locale = getRepoNameFromParsedUrl(args.url);
  }

  // Verify locale has the correct suffix.
  if (!args.locale.endsWith('-matter')) {
    var err = createError(`Unsupported locale. "${args.locale}" should have a "-matter" suffix.`);
    logErrorExit(err, true);
  }

  // Check `git` is installed before continuing.
  which('git', function (err) {
    if (err) throw err;
    spawn('git', ['clone', '--depth', 1, args.url.href, args.locale], { stdio: 'inherit' })
      .on('close', function (code, signal) {

        // If the clone was successful:
        if (code === 0) {
          colliderfile.get('.', function (data) {

            // Push a new Matter lib. object into the colliderfile data.
            data.matterLibs.push({
              url: args.url.href,
              locale: args.locale,
            });

            // Update the colliderfile with the new data.
            colliderfile.update(data, '.', function () {

              // Link the new Matter lib's Sass partial.
              updateMatterSass(data, '.', function () {
                console.log();
                console.log(`"${args.locale}" was cloned successfully! See 'collider matter'.`);
                console.log();
              });
            });
          });
        }
      });
  });

  /**
   * Retrieve a repo. name from a GitHub clone url.
   * @param  {Object} url A URL parsed using 'url.parse()'.
   * @return {String}     The repo's name.
   */
  function getRepoNameFromParsedUrl(url) {
    if (!url.pathname) {
      throw new Error('"pathname" does not exist.');
    }

    var repoName = path.basename(url.pathname, '.git');
    return repoName;
  }
}

function matterRemove(args) {
  var locale = args['<locale>'];

  // Check that 'locale' is a Matter library before attempting to delete it.
  fs.access(`./${locale}/matter/_matter.scss`, fs.F_OK, function (err) {
    if (err) throw err;

    // Get Collider-file data.
    colliderfile.get('.', function (data) {
      var projectName    = data.name;
      var createdTime    = data.createdTime;
      var author         = data.author;
      var currMatterLibs = data.matterLibs;

      // Filter Matter library to remove from Matter array.
      var newMatterLibs = currMatterLibs.filter(function (matter) {
        return matter.locale !== locale;
      });

      // 1. Remove _matter.scss @import entry.
      // 2. Then remove the Matter Collider-file entry.
      // 3. And then remove the Matter library directory.
      updateMatterSass(data, '.', function () {

        colliderfile.update({
          name: projectName,
          createdTime: createdTime,
          author: author,
          matterLibs: newMatterLibs,
        }, '.',
        function () {
          rimraf(`./${locale}`, function (err) {
            if (err) throw err;
          });
        });
      });

    });

  });
}

/**
 * Write the necessary Sass @imports to collider/_matter.scss.
 * @param  {Object}   colliderfile A .collider file in object-form.
 * @param  {String}   projectPath  The project path.
 * @param  {Function} cb           A callback function to call on success.
 */
function updateMatterSass(colliderfile, projectPath, cb) {
  var matterLibs  = colliderfile.matterLibs;
  var sassImports = ["@import '../project/matter/matter';"];

  // Add any Matter libs. to the 'sassImports' array.
  matterLibs.forEach(function (lib) {
    sassImports.push(`@import '../${lib.locale}/matter/matter';`);
  });

  // Join array members by a newline and terminate the string with a final newline.
  var data = sassImports.join('\n');
  data += '\n';

  fs.writeFile(`${projectPath}/collider/_matter.scss`, data, function (err) {
    if (err) throw err;
    if (typeof cb === 'function') {
      cb();
    }
  });
}
<commit_msg>Add message on successful `matter remove`<commit_after>// matter.js
//

'use strict';

var createError  = require('../createError');
var colliderfile = require('../colliderfile');
var logErrorExit = require('../logErrorExit');
var pkg = require('../../package.json');

var fs   = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var url  = require('url');

var _ = require('lodash');
var docopt = require('docopt').docopt;
var rimraf = require('rimraf');
var which = require('which');

var doc = `
usage:
  collider matter
  collider matter clone <url> [<locale>]
  collider matter (rm | remove) <locale>

options:
  -h, --help  Show help information.
  --version   Show program version.

commands:
  clone       Clone a Matter library into the current project.
  remove, rm  Remove a Matter library from the current project.

  With no command, 'matter' shows a list of Matter libraries in the current project.
`;

module.exports = function (argv) {

  var args = docopt(doc, {
    argv: argv,
    version: `Collider CLI ${pkg.version}`,
  });

  dispatchOn(['matter'], args, matterList);
  dispatchOn(['matter', 'clone'], args, matterClone);
  dispatchOn(['matter', 'remove'], args, matterRemove);
  dispatchOn(['matter', 'rm'], args, matterRemove);
};

// FUNCTIONS
//

/**
 * Dispatch a callback when the given commands match those given to docopts.
 * @param  {Array}    commands An array of commands to match.
 * @param  {Object}   args     A docopts arguments object.
 * @param  {Function} callback The command handler to call.
 */
function dispatchOn(commands, args, callback) {
  var haystack = [];

  // For each truthy and Boolean-type arg, push its name into 'haystack'.
  _.forEach(args, function (val, key) {
    if (val === true) haystack.push(key);
  });

  // If 'commands' and 'haystack' match, then fire our callback.
  if (_.isEqual(commands.sort(), haystack.sort())) {
    callback(args);
  }
}

function matterList() {
  colliderfile.get('.', printMatterInfo);

  function printMatterInfo(data) {
    var matterLibs = data.matterLibs;
    var librarySingOrPlur = matterLibs.length > 1 ? 'libraries' : 'library';

    if (matterLibs.length > 0) {
      console.log();
      console.log(`'${data.name}' has ${matterLibs.length} Matter ${librarySingOrPlur}:`);

      matterLibs.forEach(function (library, i) {
        console.log();
        console.log(`${i + 1}. ${library.locale}`);
        console.log(`   ${library.url}`);
      });

      console.log();
    } else {
      console.log();
      console.log(`'${data.name}' has 0 Matter libraries. See 'collider matter --help'.`);
      console.log();
    }
  }
}

function matterClone(args) {
  var args = {
    url: args['<url>'],
    locale: args['<locale>'],
  };

  // Re-assign the parsed URL to 'args.url'. The original can be found at 'args.url.href'.
  args.url = url.parse(args.url);

  // Verify the clone URL protocol is 'https:' or exit.
  var protocol = args.url.protocol;
  if (protocol !== 'https:') {
    var err = createError(
      `"${protocol}" is an unsupported protocol. URLs should start with "https:".`
    );
    logErrorExit(err, true);
  }

  // Set locale to the repo. name if it wasn't given.
  if (!args.locale) {
    args.locale = getRepoNameFromParsedUrl(args.url);
  }

  // Verify locale has the correct suffix.
  if (!args.locale.endsWith('-matter')) {
    var err = createError(`Unsupported locale. "${args.locale}" should have a "-matter" suffix.`);
    logErrorExit(err, true);
  }

  // Check `git` is installed before continuing.
  which('git', function (err) {
    if (err) throw err;
    spawn('git', ['clone', '--depth', 1, args.url.href, args.locale], { stdio: 'inherit' })
      .on('close', function (code, signal) {

        // If the clone was successful:
        if (code === 0) {
          colliderfile.get('.', function (data) {

            // Push a new Matter lib. object into the colliderfile data.
            data.matterLibs.push({
              url: args.url.href,
              locale: args.locale,
            });

            // Update the colliderfile with the new data.
            colliderfile.update(data, '.', function () {

              // Link the new Matter lib's Sass partial.
              updateMatterSass(data, '.', function () {
                console.log();
                console.log(`"${args.locale}" was cloned successfully! See 'collider matter'.`);
                console.log();
              });
            });
          });
        }
      });
  });

  /**
   * Retrieve a repo. name from a GitHub clone url.
   * @param  {Object} url A URL parsed using 'url.parse()'.
   * @return {String}     The repo's name.
   */
  function getRepoNameFromParsedUrl(url) {
    if (!url.pathname) {
      throw new Error('"pathname" does not exist.');
    }

    var repoName = path.basename(url.pathname, '.git');
    return repoName;
  }
}

function matterRemove(args) {
  var locale = args['<locale>'];

  // Check that 'locale' is a Matter library before attempting to delete it.
  fs.access(`./${locale}/matter/_matter.scss`, fs.F_OK, function (err) {
    if (err) throw err;

    // Get Collider-file data.
    colliderfile.get('.', function (data) {
      var projectName    = data.name;
      var createdTime    = data.createdTime;
      var author         = data.author;
      var currMatterLibs = data.matterLibs;

      // Filter Matter library to remove from Matter array.
      var newMatterLibs = currMatterLibs.filter(function (matter) {
        return matter.locale !== locale;
      });

      // 1. Remove _matter.scss @import entry.
      // 2. Then remove the Matter Collider-file entry.
      // 3. And then remove the Matter library directory.
      updateMatterSass(data, '.', function () {

        colliderfile.update({
          name: projectName,
          createdTime: createdTime,
          author: author,
          matterLibs: newMatterLibs,
        }, '.',
        function () {
          rimraf(`./${locale}`, function (err) {
            if (err) throw err;
            console.log();
            console.log(`"${locale}" was removed successfully. See 'collider matter'.`);
            console.log();
          });
        });
      });

    });

  });
}

/**
 * Write the necessary Sass @imports to collider/_matter.scss.
 * @param  {Object}   colliderfile A .collider file in object-form.
 * @param  {String}   projectPath  The project path.
 * @param  {Function} cb           A callback function to call on success.
 */
function updateMatterSass(colliderfile, projectPath, cb) {
  var matterLibs  = colliderfile.matterLibs;
  var sassImports = ["@import '../project/matter/matter';"];

  // Add any Matter libs. to the 'sassImports' array.
  matterLibs.forEach(function (lib) {
    sassImports.push(`@import '../${lib.locale}/matter/matter';`);
  });

  // Join array members by a newline and terminate the string with a final newline.
  var data = sassImports.join('\n');
  data += '\n';

  fs.writeFile(`${projectPath}/collider/_matter.scss`, data, function (err) {
    if (err) throw err;
    if (typeof cb === 'function') {
      cb();
    }
  });
}
<|endoftext|>


<commit_before>const q = require('q')
const EventEmitter = require('events').EventEmitter
const { MongoClient, ObjectId } = require('mongodb')
const Redis = require('redis')
const fs = require('fs')

const DATABASE_VERSION = 2

module.exports = function (config) {
  Object.assign(exports, config.common.storage)
  return function storageConnect () {
    if (exports._connected) {
      return q.when()
    }
    let uri

    if (config.mongo.uri) {
      uri = config.mongo.uri
    } else {
      uri = `mongodb://${config.mongo.host}:${config.mongo.port}/${config.mongo.database}`
    }
    delete config.mongo.host
    delete config.mongo.port
    delete config.mongo.database

    let redis = Redis.createClient(config.redis)
    let pub = Redis.createClient(config.redis)
    let sub = Redis.createClient(config.redis)

    let mongo = q.ninvoke(MongoClient, 'connect', uri, Object.assign({ promiseLibrary: Promise }, config.mongo))
      .then(db => {
        function wrapCollection (collection, cname) {
          let wrap = {}
          function keyToId (obj) {
            let idRegex = /^[a-f0-9]{24}$/
            if (obj instanceof Array) return obj.map(keyToId)
            if (obj._id && obj._id.$in) {
              return Object.assign({}, obj, {
                _id: {
                  $in: obj._id.$in.map(i => {
                    if (typeof i === 'string' && i.match(idRegex)) {
                      i = new ObjectId(i)
                    }
                    return i
                  })
                }
              })
            }
            if (typeof obj._id === 'string' && obj._id.match(idRegex)) {
              return Object.assign({}, obj, { _id: new ObjectId(obj._id) })
            }
            return obj
          }
          function idToKey (obj) {
            if (obj instanceof Array) return obj.map(idToKey)
            if (obj && obj._id) {
              obj._id = obj._id.toString()
            }
            return obj
          }
          ;['find', 'findOne', 'findEx', 'by', 'count', 'ensureIndex', 'remove', 'insert', 'update'].forEach(method => {
            wrap[method] = (...a) => {
              try {
                let orig = a[0]
                if (typeof a[0] === 'object') {
                  a[0] = keyToId(a[0])
                }
                if (method === 'update') {
                  a[2] = a[2] || {}
                  if (a[2].multi !== false && Object.keys(a[1]).reduce((l, v) => l && v[0] === '$', true)) {
                    a[2].multi = true
                  }
                  if (a[1].$merge) {
                    let merge = a[1].$merge
                    delete a[1].$merge
                    let flat = (obj, stack = []) => {
                      const ret = {}
                      if (typeof obj === 'object' && !Array.isArray(obj)) {
                        Object.entries(obj).forEach(([k, v]) => {
                          Object.assign(ret, flat(v, [...stack, k]))
                        })
                      } else if (stack.length) {
                        ret[stack.join('.')] = obj
                      } else {
                        return obj
                      }
                      return ret
                    }
                    a[1].$set = flat({}, merge)
                  }
                }
                let ex = method === 'findEx'
                if (ex) method = 'find'
                if (method.slice(0, 6) === 'insert') method = Array.isArray(a[0]) ? 'insertMany' : 'insertOne'

                let chain = collection[method](...a)
                if (method === 'insertOne') {
                  chain = chain.then((n) => {
                    orig._id = n.insertedId
                    return orig
                  })
                }
                if (method === 'insertMany') {
                  chain = chain.then((n) => {
                    orig.forEach((o, i) => (o._id = n.insertedIds[i]))
                    return orig
                  })
                }
                if (method === 'update') {
                  chain = chain.then((n) => Object.assign(n, { modified: n.result.nModified }))
                }
                if (ex) {
                  let opts = a[1]
                  if (opts.sort) {
                    chain = chain.sort(opts.sort)
                  }
                  if (opts.offset) {
                    chain = chain.offset(opts.offset)
                  }
                  if (opts.limit) {
                    chain = chain.limit(opts.limit)
                  }
                }
                if (method === 'find') {
                  chain = q.ninvoke(chain, 'toArray')
                }
                chain = chain.then(idToKey)
                  .catch(e => {
                    console.error('DBERR', e, ex, a)
                    console.log('DBERR', e.stack)
                  })
                return q(chain)
              } catch (e) {
                console.error('DBERR', e)
                console.log('DBERR', e.stack)
                return q(Promise.reject(e))
              }
            }
          })

          wrap.drop = (...a) => {
            return q.ninvoke(collection, 'drop', ...a).catch(e => q.resolve())
          }
          wrap.clear = wrap.drop
          wrap.removeWhere = wrap.remove
          wrap.by = (_id) => wrap.find({ _id })
          wrap.bulk = function (bulk, cb) {
            let batch = collection.initializeUnorderedBulkOp()
            try {
              bulk.forEach(i => {
                if (i.op === 'insert') {
                  return batch.insert(i.data)
                }
                let q = { _id: (i.id && i.id.length === 24) ? new ObjectId(i.id + '') : i.id }
                if (i.op === 'update') {
                  return batch.find(q).update(i.update)
                }
                if (i.op === 'remove') {
                  return batch.find(q).remove()
                }
                console.error('UNKNOWN BULK!', i)
              })
              return q.ninvoke(batch, 'execute')
            } catch (e) {
              if (cb) cb(e.message)
              console.error(e)
              return q.reject(e.message)
            }
          }
          return wrap
        }
        config.common.dbCollections.forEach(i => {
          let collection = db.collection(i)
          let indexes = config.common.dbIndexes[i]
          if (indexes) {
            for (let k in indexes) {
              collection.ensureIndex({ [k]: indexes[k] })
            }
          }
          exports.db[i] = wrapCollection(collection, i)
        })

        exports.upgradeDB()
      })

    Object.assign(exports.pubsub, {
      ee: new EventEmitter(),
      subscribed: {},
      publish (channel, data) {
        pub.publish(channel, data)
        return q.when()
      },
      subscribe (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.on(channel, cb)
        return q.when()
      },
      once (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.once(channel, cb)
        return q.when()
      }
    })
    sub.on('message', (channel, message) => {
      exports.pubsub.ee.emit(channel, message)
    })
    sub.on('pmessage', (pattern, channel, message) => {
      exports.pubsub.ee.emit(channel, message)
      exports.pubsub.ee.emit(pattern, channel, message)
    })

    Object.assign(exports.env, {
      get: q.nbind(redis.get, redis),
      mget: q.nbind(redis.mget, redis),
      set: q.nbind(redis.set, redis),
      setex: q.nbind(redis.setex, redis),
      expire: q.nbind(redis.expire, redis),
      ttl: q.nbind(redis.ttl, redis),
      del: q.nbind(redis.del, redis),
      hmget: q.nbind(redis.hmget, redis),
      hmset: q.nbind(redis.hmset, redis),
      hget: q.nbind(redis.hget, redis),
      hset: q.nbind(redis.hset, redis),
      hgetall: q.nbind(redis.hgetall, redis),
      incr: q.nbind(redis.incr, redis),
      flushall: q.nbind(redis.flushall, redis)
    })

    exports._connected = true
    exports.resetAllData = () => q.when() // Temp dummy

    Object.assign(exports.queue, require('./queue'))
    exports.queue.wrap(redis, exports.pubsub)

    let oget = exports.env.get
    exports.env.get = function (...a) {
      return oget(...a).catch(() => exports.env.hgetall(...a))
    }

    exports.resetAllData = () => {
      return exports.importDB(`${__dirname}/../../db.original.json`)
    }
    Object.assign(config.common.storage, exports)
    return mongo
  }
}

exports.importDB = function importDB (path = './db.json') {
  let { db, env } = exports
  console.log('Importing DB')
  try {
    let olddb = JSON.parse(fs.readFileSync(path).toString())
    let ps = olddb.collections.map(oldcol => {
      let name = oldcol.name
      console.log('Collection', name)
      if (name === 'env') {
        return env.flushall().then(() => {
          let p = oldcol.data.map(row => {
            let ps = []
            for (let k in row.data) {
              let v = row.data[k]
              let type = k.slice(0, k.indexOf(':'))
              let hashTypes = [env.keys.MEMORY_SEGMENTS, env.keys.ROOM_HISTORY]
              if (hashTypes.indexOf(type) !== -1) {
                for (let kk in v) {
                  ps.push(env.hmset(k, kk, typeof v[kk] === 'object' ? JSON.stringify(v[kk]) : v[kk]))
                }
              } else {
                ps.push(env.set(k, typeof v === 'object' ? JSON.stringify(v) : v))
              }
            }
            return Promise.all(ps)
          })
          return Promise.all(p)
        })
      } else {
        return db[name].drop().then(() => Promise.all(oldcol.data.map(row => {
          delete row.meta
          delete row.$loki
          return db[name].insert(row)
        })))
      }
    })
    ps.push(db.users.update({ _id: '2' }, { $set: { _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    ps.push(db.users.update({ _id: '3' }, { $set: { _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    ps.push(db.users.update({ username: 'Screeps' }, { username: 'Screeps', usernameLower: 'screeps', gcl: 0, cpi: 0, active: false, cpuAvailable: 0, badge: { type: 12, color1: '#999999', color2: '#999999', color3: '#999999', flip: false, param: 26 } }, { upsert: true }))
    ps.push(env.set(env.keys.DATABASE_VERSION, DATABASE_VERSION))
    return Promise.all(ps)
      .then(() => console.log('Import complete. Restart the server for best results.'))
      .catch(e => importFail(e))
  } catch (e) {
    return importFail(e)
  }
}

function importFail (e) {
  let { db, env } = exports
  let ps = []
  ps.push(db.users.insert({ _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ username: 'Screeps', usernameLower: 'screeps', gcl: 0, cpi: 0, active: false, cpuAvailable: 0, badge: { type: 12, color1: '#999999', color2: '#999999', color3: '#999999', flip: false, param: 26 } }))
  ps.push(env.set('gameTime', 1))
  ps.push(env.set(env.keys.DATABASE_VERSION, DATABASE_VERSION))
  return Promise.resolve()
    .then(() => console.log('An error occured importing existing db, initializing blank server'))
    .then(() => console.error(e))
    .then(() => Promise.all(ps))
    .then(() => console.log('Server initialzed. Remember to generate rooms.'))
    .catch(err => console.error(err))
}

exports.upgradeDB = function upgradeDB () {
  let { db, env } = exports
  return env.get(env.keys.DATABASE_VERSION)
    .then(v => parseInt(v) || 1)
    .then(version => {
      let ps = []
      if (version === DATABASE_VERSION) return
      if (version < 2) {
        ps.push(db.users.update({ money: { $gt: 0 } }, { $mul: { money: 1000 } }))
        ps.push(db['market.orders'].update({}, { $mul: { price: 1000 } }))
        ps.push(db.users.update({ username: 'Screeps' }, { username: 'Screeps', usernameLower: 'screeps', gcl: 0, cpi: 0, active: false, cpuAvailable: 0, badge: { type: 12, color1: '#999999', color2: '#999999', color3: '#999999', flip: false, param: 26 } }, { upsert: true }))
      }
      return Promise.all(ps)
    })
    .then(() => env.set(env.keys.DATABASE_VERSION, DATABASE_VERSION))
}
<commit_msg>Fixed. For good this time.<commit_after>const q = require('q')
const EventEmitter = require('events').EventEmitter
const { MongoClient, ObjectId } = require('mongodb')
const Redis = require('redis')
const fs = require('fs')

const DATABASE_VERSION = 2

module.exports = function (config) {
  Object.assign(exports, config.common.storage)
  return function storageConnect () {
    if (exports._connected) {
      return q.when()
    }
    let uri

    if (config.mongo.uri) {
      uri = config.mongo.uri
    } else {
      uri = `mongodb://${config.mongo.host}:${config.mongo.port}/${config.mongo.database}`
    }
    delete config.mongo.host
    delete config.mongo.port
    delete config.mongo.database

    let redis = Redis.createClient(config.redis)
    let pub = Redis.createClient(config.redis)
    let sub = Redis.createClient(config.redis)

    let mongo = q.ninvoke(MongoClient, 'connect', uri, Object.assign({ promiseLibrary: Promise }, config.mongo))
      .then(db => {
        function wrapCollection (collection, cname) {
          let wrap = {}
          function keyToId (obj) {
            let idRegex = /^[a-f0-9]{24}$/
            if (obj instanceof Array) return obj.map(keyToId)
            if (obj._id && obj._id.$in) {
              return Object.assign({}, obj, {
                _id: {
                  $in: obj._id.$in.map(i => {
                    if (typeof i === 'string' && i.match(idRegex)) {
                      i = new ObjectId(i)
                    }
                    return i
                  })
                }
              })
            }
            if (typeof obj._id === 'string' && obj._id.match(idRegex)) {
              return Object.assign({}, obj, { _id: new ObjectId(obj._id) })
            }
            return obj
          }
          function idToKey (obj) {
            if (obj instanceof Array) return obj.map(idToKey)
            if (obj && obj._id) {
              obj._id = obj._id.toString()
            }
            return obj
          }
          ;['find', 'findOne', 'findEx', 'by', 'count', 'ensureIndex', 'remove', 'insert', 'update'].forEach(method => {
            wrap[method] = (...a) => {
              try {
                let orig = a[0]
                if (typeof a[0] === 'object') {
                  a[0] = keyToId(a[0])
                }
                if (method === 'update') {
                  a[2] = a[2] || {}
                  if (a[2].multi !== false && Object.keys(a[1]).reduce((l, v) => l && v[0] === '$', true)) {
                    a[2].multi = true
                  }
                  if (a[1].$merge) {
                    let merge = a[1].$merge
                    delete a[1].$merge
                    let flat = (obj, stack = []) => {
                      const ret = {}
                      if (typeof obj === 'object' && !Array.isArray(obj)) {
                        Object.entries(obj).forEach(([k, v]) => {
                          Object.assign(ret, flat(v, [...stack, k]))
                        })
                      } else if (stack.length) {
                        ret[stack.join('.')] = obj
                      } else {
                        return obj
                      }
                      return ret
                    }
                    a[1].$set = flat(merge)
                  }
                }
                let ex = method === 'findEx'
                if (ex) method = 'find'
                if (method.slice(0, 6) === 'insert') method = Array.isArray(a[0]) ? 'insertMany' : 'insertOne'

                let chain = collection[method](...a)
                if (method === 'insertOne') {
                  chain = chain.then((n) => {
                    orig._id = n.insertedId
                    return orig
                  })
                }
                if (method === 'insertMany') {
                  chain = chain.then((n) => {
                    orig.forEach((o, i) => (o._id = n.insertedIds[i]))
                    return orig
                  })
                }
                if (method === 'update') {
                  chain = chain.then((n) => Object.assign(n, { modified: n.result.nModified }))
                }
                if (ex) {
                  let opts = a[1]
                  if (opts.sort) {
                    chain = chain.sort(opts.sort)
                  }
                  if (opts.offset) {
                    chain = chain.offset(opts.offset)
                  }
                  if (opts.limit) {
                    chain = chain.limit(opts.limit)
                  }
                }
                if (method === 'find') {
                  chain = q.ninvoke(chain, 'toArray')
                }
                chain = chain.then(idToKey)
                  .catch(e => {
                    console.error('DBERR', e, ex, a)
                    console.log('DBERR', e.stack)
                  })
                return q(chain)
              } catch (e) {
                console.error('DBERR', e)
                console.log('DBERR', e.stack)
                return q(Promise.reject(e))
              }
            }
          })

          wrap.drop = (...a) => {
            return q.ninvoke(collection, 'drop', ...a).catch(e => q.resolve())
          }
          wrap.clear = wrap.drop
          wrap.removeWhere = wrap.remove
          wrap.by = (_id) => wrap.find({ _id })
          wrap.bulk = function (bulk, cb) {
            let batch = collection.initializeUnorderedBulkOp()
            try {
              bulk.forEach(i => {
                if (i.op === 'insert') {
                  return batch.insert(i.data)
                }
                let q = { _id: (i.id && i.id.length === 24) ? new ObjectId(i.id + '') : i.id }
                if (i.op === 'update') {
                  return batch.find(q).update(i.update)
                }
                if (i.op === 'remove') {
                  return batch.find(q).remove()
                }
                console.error('UNKNOWN BULK!', i)
              })
              return q.ninvoke(batch, 'execute')
            } catch (e) {
              if (cb) cb(e.message)
              console.error(e)
              return q.reject(e.message)
            }
          }
          return wrap
        }
        config.common.dbCollections.forEach(i => {
          let collection = db.collection(i)
          let indexes = config.common.dbIndexes[i]
          if (indexes) {
            for (let k in indexes) {
              collection.ensureIndex({ [k]: indexes[k] })
            }
          }
          exports.db[i] = wrapCollection(collection, i)
        })

        exports.upgradeDB()
      })

    Object.assign(exports.pubsub, {
      ee: new EventEmitter(),
      subscribed: {},
      publish (channel, data) {
        pub.publish(channel, data)
        return q.when()
      },
      subscribe (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.on(channel, cb)
        return q.when()
      },
      once (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.once(channel, cb)
        return q.when()
      }
    })
    sub.on('message', (channel, message) => {
      exports.pubsub.ee.emit(channel, message)
    })
    sub.on('pmessage', (pattern, channel, message) => {
      exports.pubsub.ee.emit(channel, message)
      exports.pubsub.ee.emit(pattern, channel, message)
    })

    Object.assign(exports.env, {
      get: q.nbind(redis.get, redis),
      mget: q.nbind(redis.mget, redis),
      set: q.nbind(redis.set, redis),
      setex: q.nbind(redis.setex, redis),
      expire: q.nbind(redis.expire, redis),
      ttl: q.nbind(redis.ttl, redis),
      del: q.nbind(redis.del, redis),
      hmget: q.nbind(redis.hmget, redis),
      hmset: q.nbind(redis.hmset, redis),
      hget: q.nbind(redis.hget, redis),
      hset: q.nbind(redis.hset, redis),
      hgetall: q.nbind(redis.hgetall, redis),
      incr: q.nbind(redis.incr, redis),
      flushall: q.nbind(redis.flushall, redis)
    })

    exports._connected = true
    exports.resetAllData = () => q.when() // Temp dummy

    Object.assign(exports.queue, require('./queue'))
    exports.queue.wrap(redis, exports.pubsub)

    let oget = exports.env.get
    exports.env.get = function (...a) {
      return oget(...a).catch(() => exports.env.hgetall(...a))
    }

    exports.resetAllData = () => {
      return exports.importDB(`${__dirname}/../../db.original.json`)
    }
    Object.assign(config.common.storage, exports)
    return mongo
  }
}

exports.importDB = function importDB (path = './db.json') {
  let { db, env } = exports
  console.log('Importing DB')
  try {
    let olddb = JSON.parse(fs.readFileSync(path).toString())
    let ps = olddb.collections.map(oldcol => {
      let name = oldcol.name
      console.log('Collection', name)
      if (name === 'env') {
        return env.flushall().then(() => {
          let p = oldcol.data.map(row => {
            let ps = []
            for (let k in row.data) {
              let v = row.data[k]
              let type = k.slice(0, k.indexOf(':'))
              let hashTypes = [env.keys.MEMORY_SEGMENTS, env.keys.ROOM_HISTORY]
              if (hashTypes.indexOf(type) !== -1) {
                for (let kk in v) {
                  ps.push(env.hmset(k, kk, typeof v[kk] === 'object' ? JSON.stringify(v[kk]) : v[kk]))
                }
              } else {
                ps.push(env.set(k, typeof v === 'object' ? JSON.stringify(v) : v))
              }
            }
            return Promise.all(ps)
          })
          return Promise.all(p)
        })
      } else {
        return db[name].drop().then(() => Promise.all(oldcol.data.map(row => {
          delete row.meta
          delete row.$loki
          return db[name].insert(row)
        })))
      }
    })
    ps.push(db.users.update({ _id: '2' }, { $set: { _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    ps.push(db.users.update({ _id: '3' }, { $set: { _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    ps.push(db.users.update({ username: 'Screeps' }, { username: 'Screeps', usernameLower: 'screeps', gcl: 0, cpi: 0, active: false, cpuAvailable: 0, badge: { type: 12, color1: '#999999', color2: '#999999', color3: '#999999', flip: false, param: 26 } }, { upsert: true }))
    ps.push(env.set(env.keys.DATABASE_VERSION, DATABASE_VERSION))
    return Promise.all(ps)
      .then(() => console.log('Import complete. Restart the server for best results.'))
      .catch(e => importFail(e))
  } catch (e) {
    return importFail(e)
  }
}

function importFail (e) {
  let { db, env } = exports
  let ps = []
  ps.push(db.users.insert({ _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ username: 'Screeps', usernameLower: 'screeps', gcl: 0, cpi: 0, active: false, cpuAvailable: 0, badge: { type: 12, color1: '#999999', color2: '#999999', color3: '#999999', flip: false, param: 26 } }))
  ps.push(env.set('gameTime', 1))
  ps.push(env.set(env.keys.DATABASE_VERSION, DATABASE_VERSION))
  return Promise.resolve()
    .then(() => console.log('An error occured importing existing db, initializing blank server'))
    .then(() => console.error(e))
    .then(() => Promise.all(ps))
    .then(() => console.log('Server initialzed. Remember to generate rooms.'))
    .catch(err => console.error(err))
}

exports.upgradeDB = function upgradeDB () {
  let { db, env } = exports
  return env.get(env.keys.DATABASE_VERSION)
    .then(v => parseInt(v) || 1)
    .then(version => {
      let ps = []
      if (version === DATABASE_VERSION) return
      if (version < 2) {
        ps.push(db.users.update({ money: { $gt: 0 } }, { $mul: { money: 1000 } }))
        ps.push(db['market.orders'].update({}, { $mul: { price: 1000 } }))
        ps.push(db.users.update({ username: 'Screeps' }, { username: 'Screeps', usernameLower: 'screeps', gcl: 0, cpi: 0, active: false, cpuAvailable: 0, badge: { type: 12, color1: '#999999', color2: '#999999', color3: '#999999', flip: false, param: 26 } }, { upsert: true }))
      }
      return Promise.all(ps)
    })
    .then(() => env.set(env.keys.DATABASE_VERSION, DATABASE_VERSION))
}
<|endoftext|>


<commit_before>var _ = require("lodash");
var WebSocket = require('ws');

var ws = new WebSocket('ws://localhost:5110');
var gWaitInt = 0;

var gMoveSet = [
  [0, 0],
  [0, 1],
  [0, 2],
  [1, 0],
  [1, 1],
  [1, 2],
  [2, 0],
  [2, 1],
  [2, 2]
];

var gSession = "1:51:xxxx:0";
var gUid = "51";

function sendCmd(cmd, params) {
  var baseCmd = {
    session: gSession,
    cmd: cmd
  };

  var data = _.merge(baseCmd, params);
  console.log("send:", data);
  ws.send(JSON.stringify(data));
}

function waitForGame() {
  sendCmd("match.count", {name: "tictactoe"});
}

ws.on('open', function () {
  sendCmd("channel2.add", {channel: "lobby:0"});
  sendCmd("game.playing");
  gWaitInt = setInterval(waitForGame, 5000);
});

ws.on('close', function () {
  console.log("socket closed");
  clearInterval(gWaitInt);
});

ws.on('error', function (error) {
  console.log(error);
});

function makeMove(game) {
  for (var i=0; i<3; i++) {
    for (var j=0; j<3; j++) {
      if (game.state.gameBoard[i][j] === "") {
        sendCmd("game.turn", {gameId: game.oid, move: {x: i, y: j}});
        return;
      }
    }
  }
}

ws.on('message', function (message) {
  console.log('received: %s', message);
  try {
  var msg = JSON.parse(message);
  } catch (e) {
    console.error("unabel to parse message");
    return;
  }
  if (msg.event === "match.count") {
    if (msg.data.waiting > 0) {
      sendCmd("match.add", {name: "tictactoe"});
    }
  } else if (msg.event === "match.made") {
    sendCmd("game.join", {gameId: msg.data.gameId});
    sendCmd("channel2.add", {channel: "game:" + msg.data.gameId});
  } else if (msg.event === "game.info"
    || msg.event === "game.reset"
    || msg.event === "game.join") {
    if (msg.data.whoTurn === gUid) {
      setTimeout(function () {
        makeMove(msg.data);
      }, 1000);
    }
  } else if (msg.event === "game.playing") {
    _.each(msg.data, function (gameInfo, gameId) {
      sendCmd("channel2.add", {channel: "game:" + gameId});
      if(gameInfo.whoTurn === gUid) {
        sendCmd("game.get", {gameId: gameId});  // trigger a move base on gameBoard
      }
    });
  } else if (msg.event === "game.turn.next") {
    if (msg.data.whoTurn === gUid) {
      sendCmd("game.get", {gameId: msg.data.gameId});  // trigger a move base on gameBoard
    }
  }
});<commit_msg>fix robo player 51;<commit_after>var _ = require("lodash");
var WebSocket = require('ws');

var ws = new WebSocket('ws://localhost:5110');
var gWaitInt = 0;

var gMoveSet = [
  [0, 0],
  [0, 1],
  [0, 2],
  [1, 0],
  [1, 1],
  [1, 2],
  [2, 0],
  [2, 1],
  [2, 2]
];

var gSession = "1:51:xxxx:0";
var gUid = "51";

function sendCmd(cmd, params) {
  var baseCmd = {
    session: gSession,
    cmd: cmd
  };

  var data = _.merge(baseCmd, params);
  console.log("send:", data);
  ws.send(JSON.stringify(data));
}

function waitForGame() {
  sendCmd("match.count", {name: "tictactoe"});
}

ws.on('open', function () {
  sendCmd("channel.add", {channel: "lobby:0"});
  sendCmd("game.playing");
  gWaitInt = setInterval(waitForGame, 5000);
});

ws.on('close', function () {
  console.log("socket closed");
  clearInterval(gWaitInt);
});

ws.on('error', function (error) {
  console.log(error);
});

function makeMove(game) {
  var i = 0;
  for (i = 0; i < 3; i += 1) {
    var j = 0;
    for (j = 0; j < 3; j += 1) {
      if (game.state.gameBoard[i][j] === "") {
        sendCmd("game.turn", {gameId: game.oid, move: {x: i, y: j}});
        return;
      }
    }
  }
}

ws.on('message', function (message) {
  console.log('received: %s', message);
  var msg = null;
  try {
    msg = JSON.parse(message);
  } catch (e) {
    console.error("unabel to parse message", e.toString());
    return;
  }
  if (msg.event === "match.count") {
    if (msg.data.waiting > 0) {
      sendCmd("match.add", {name: "tictactoe"});
    }
  } else if (msg.event === "match.made") {
    sendCmd("game.join", {gameId: msg.data.gameId});
    sendCmd("channel.add", {channel: "game:" + msg.data.gameId});
  } else if (msg.event === "game.get"
      || msg.event === "game.reset"
      || msg.event === "game.join") {
    if (msg.data.whoTurn === gUid) {
      setTimeout(function () {
        makeMove(msg.data);
      }, 1000);
    }
  } else if (msg.event === "game.playing") {
    _.each(msg.data, function (gameInfo, gameId) {
      sendCmd("channel.add", {channel: "game:" + gameId});
      if(gameInfo.whoTurn === gUid) {
        sendCmd("game.get", {gameId: gameId});  // trigger a move base on gameBoard
      }
    });
  } else if (msg.event === "game.turn.next") {
    if (msg.data.whoTurn === gUid) {
      sendCmd("game.get", {gameId: msg.data.gameId});  // trigger a move base on gameBoard
    }
  }
});<|endoftext|>


<commit_before>import {style, inline, Node} from "../model"
import {joinPoint, liftableRange, wrappableRange} from "../transform"
import {elt} from "../edit/dom"

export class Item {
  constructor(icon, title) {
    this.icon = icon
    this.title = title
  }
  active() { return false }
  select() { return true }
}

export class LiftItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Move out of block")
  }
  select(pm) {
    let sel = pm.selection
    return liftableRange(pm.doc, sel.from, sel.to)
  }
  apply(pm) {
    let sel = pm.selection
    let range = liftableRange(pm.doc, sel.from, sel.to)
    pm.apply({name: "lift", pos: range.from, end: range.to})
  }
}

export class JoinItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Join with above block")
  }
  select(pm) {
    return joinPoint(pm.doc, pm.selection.head)
  }
  apply(pm) {
    let point = joinPoint(pm.doc, pm.selection.head)
    if (point) pm.apply({name: "join", pos: point})
  }
}

export class SubmenuItem extends Item {
  constructor(icon, title, submenu) {
    super(icon, title)
    this.submenu = submenu
  }
  select(pm) { return this.submenu.some(i => i.select(pm)) }
  apply(pm) { return this.submenu.filter(i => i.select(pm)) }
}

export class BlockTypeItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply({name: "setType", pos: sel.from, end: sel.to, type: this.type, attrs: this.attrs})
  }
}

export class InsertBlockItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  select(pm) {
    let sel = pm.selection
    return sel.empty && pm.doc.path(sel.head.path).type.type == Node.types[this.type].type
  }
  apply(pm) {
    let sel = pm.selection
    if (sel.head.offset) {
      pm.apply({name: "split", pos: sel.head})
      sel = pm.selection
    }
    pm.apply({name: "insert", pos: sel.head.shorten(), type: this.type, attrs: this.attrs})
  }
}

export class WrapItem extends Item {
  constructor(icon, title, type) {
    super(icon, title)
    this.type = type
  }
  apply(pm) {
    let sel = pm.selection
    let range = wrappableRange(pm.doc, sel.from, sel.to)
    pm.apply({name: "wrap", pos: range.from, end: range.to, type: this.type})
  }
}

export class InlineStyleItem extends Item {
  constructor(icon, title, style, dialog) {
    super(icon, title)
    this.style = typeof style == "string" ? {type: style} : style
    this.dialog = dialog
  }
  active(pm) {
    let sel = pm.selection
    return inline.rangeHasInlineStyle(pm.doc, sel.from, sel.to, this.style.type)
  }
  apply(pm) {
    let sel = pm.selection
    if (this.active(pm))
      pm.apply({name: "removeStyle", pos: sel.from, end: sel.to, style: this.style.type})
    else if (this.dialog)
      return this.dialog
    else
      pm.apply({name: "addStyle", pos: sel.from, end: sel.to, style: this.style})
  }
}

export class ImageItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Insert image")
  }
  apply(pm) { return new ImageDialog }
}

export class Dialog {
  constructor() {
    this.id = Math.floor(Math.random() * 0xffffff).toString(16)
  }

  focus(form) {
    let input = form.querySelector("input")
    if (input) input.focus()
  }

  buildForm(pm) {
    let form = this.form(pm)
    form.appendChild(elt("button", {type: "submit", style: "display: none"}))
    return form
  }
}

export class LinkDialog extends Dialog {
  form() {
    return elt("form", null,
               elt("div", null, elt("input", {name: "href", type: "text", placeholder: "Target URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autocomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.href.value) return
    let sel = pm.selection
    pm.apply({name: "addStyle", pos: sel.from, end: sel.to,
              style: style.link(elts.href.value, elts.title.value)})
  }
}

export class ImageDialog extends Dialog {
  form(pm) {
    let alt = pm.selectedText
    return elt("form", null,
               elt("div", null, elt("input", {name: "src", type: "text", placeholder: "Image URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "alt", type: "text", value: alt, autocomplete: "off",
                                              placeholder: "Description / alternative text", size: 40})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autcomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.src.value) return
    let sel = pm.selection
    pm.apply({name: "replace", pos: sel.from, end: sel.to})
    let attrs = {src: elts.src.value, alt: elts.alt.value, title: elts.title.value}
    pm.apply({name: "insertInline", pos: sel.from, type: "image", attrs: attrs})
  }
}
<commit_msg>Make remove and insert transforms take valid inline positions<commit_after>import {style, inline, Node} from "../model"
import {joinPoint, liftableRange, wrappableRange} from "../transform"
import {elt} from "../edit/dom"

export class Item {
  constructor(icon, title) {
    this.icon = icon
    this.title = title
  }
  active() { return false }
  select() { return true }
}

export class LiftItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Move out of block")
  }
  select(pm) {
    let sel = pm.selection
    return liftableRange(pm.doc, sel.from, sel.to)
  }
  apply(pm) {
    let sel = pm.selection
    let range = liftableRange(pm.doc, sel.from, sel.to)
    pm.apply({name: "lift", pos: range.from, end: range.to})
  }
}

export class JoinItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Join with above block")
  }
  select(pm) {
    return joinPoint(pm.doc, pm.selection.head)
  }
  apply(pm) {
    let point = joinPoint(pm.doc, pm.selection.head)
    if (point) pm.apply({name: "join", pos: point})
  }
}

export class SubmenuItem extends Item {
  constructor(icon, title, submenu) {
    super(icon, title)
    this.submenu = submenu
  }
  select(pm) { return this.submenu.some(i => i.select(pm)) }
  apply(pm) { return this.submenu.filter(i => i.select(pm)) }
}

export class BlockTypeItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply({name: "setType", pos: sel.from, end: sel.to, type: this.type, attrs: this.attrs})
  }
}

export class InsertBlockItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  select(pm) {
    let sel = pm.selection
    return sel.empty && pm.doc.path(sel.head.path).type.type == Node.types[this.type].type
  }
  apply(pm) {
    let sel = pm.selection
    if (sel.head.offset) {
      pm.apply({name: "split", pos: sel.head})
      sel = pm.selection
    }
    pm.apply({name: "insert", pos: sel.head, direction: "before", type: this.type, attrs: this.attrs})
  }
}

export class WrapItem extends Item {
  constructor(icon, title, type) {
    super(icon, title)
    this.type = type
  }
  apply(pm) {
    let sel = pm.selection
    let range = wrappableRange(pm.doc, sel.from, sel.to)
    pm.apply({name: "wrap", pos: range.from, end: range.to, type: this.type})
  }
}

export class InlineStyleItem extends Item {
  constructor(icon, title, style, dialog) {
    super(icon, title)
    this.style = typeof style == "string" ? {type: style} : style
    this.dialog = dialog
  }
  active(pm) {
    let sel = pm.selection
    return inline.rangeHasInlineStyle(pm.doc, sel.from, sel.to, this.style.type)
  }
  apply(pm) {
    let sel = pm.selection
    if (this.active(pm))
      pm.apply({name: "removeStyle", pos: sel.from, end: sel.to, style: this.style.type})
    else if (this.dialog)
      return this.dialog
    else
      pm.apply({name: "addStyle", pos: sel.from, end: sel.to, style: this.style})
  }
}

export class ImageItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Insert image")
  }
  apply(pm) { return new ImageDialog }
}

export class Dialog {
  constructor() {
    this.id = Math.floor(Math.random() * 0xffffff).toString(16)
  }

  focus(form) {
    let input = form.querySelector("input")
    if (input) input.focus()
  }

  buildForm(pm) {
    let form = this.form(pm)
    form.appendChild(elt("button", {type: "submit", style: "display: none"}))
    return form
  }
}

export class LinkDialog extends Dialog {
  form() {
    return elt("form", null,
               elt("div", null, elt("input", {name: "href", type: "text", placeholder: "Target URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autocomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.href.value) return
    let sel = pm.selection
    pm.apply({name: "addStyle", pos: sel.from, end: sel.to,
              style: style.link(elts.href.value, elts.title.value)})
  }
}

export class ImageDialog extends Dialog {
  form(pm) {
    let alt = pm.selectedText
    return elt("form", null,
               elt("div", null, elt("input", {name: "src", type: "text", placeholder: "Image URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "alt", type: "text", value: alt, autocomplete: "off",
                                              placeholder: "Description / alternative text", size: 40})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autcomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.src.value) return
    let sel = pm.selection
    pm.apply({name: "replace", pos: sel.from, end: sel.to})
    let attrs = {src: elts.src.value, alt: elts.alt.value, title: elts.title.value}
    pm.apply({name: "insertInline", pos: sel.from, type: "image", attrs: attrs})
  }
}
<|endoftext|>


<commit_before>var util = require("util");
var BaseTrigger = require("./baseTrigger.js").BaseTrigger;
var ueberDB = require("ueberDB");
/*
A Karma trigger. thing++ increases karma, thing-- decreases it. Spaces are ignored/removed.
options:
command = string or array of strings (optional) - what is the command for the given function?
ueberDB = ueberDB - an *initiated* instance of ueberDB https://github.com/Pita/ueberDB if you don't want to use an sqlite db, or if you don't want to share it.
dbFile = string - path to the sqlite.db file that you want to use.
maxlength = int - what is the maximum length of a key? Default is 25.
*/

var KarmaTrigger = function() {
	KarmaTrigger.super_.apply(this, arguments);
};

util.inherits(KarmaTrigger, BaseTrigger);

var type = "KarmaTrigger";
exports.triggerType = type;
exports.create = function(name, chatBot, options) {
	var trigger = new KarmaTrigger(type, name, chatBot, options);
	trigger.options.command   = trigger.options.command || "!karma";
	trigger.options.maxlength = options.maxlength       || 25;
	trigger.db = options.ueberDB || new ueberDB.database("sqlite", {filename:options.dbFile||(chatBot.name+"/"+name+".db")}, {writeInterval:500});
	trigger.dbInitialized=false;
	return trigger;
};

KarmaTrigger.prototype._respondToFriendMessage = function(userId, message) {
	if(this._stripCommand(message)) {
		this._respondToChatMessage(userId,userId,message);
	}
	return false;
}

// Return true if a message was sent
KarmaTrigger.prototype._respondToChatMessage = function(roomId, chatterId, m) {
	var that = this;
	var cmd = this._stripCommand(m);
	if(cmd) {
		this._dbOperation('get',{key:cmd.replace(/\s/g,'').toLowerCase(),callback:function(err,value){
			if(err) {
				that._sendMessageAfterDelay(roomId,"Error obtaining karma for '"+cmd+"'.");
				that.winston.error(that.chatBot.name+"/"+that.name+": ERROR",err);
				return;
			}
			that._sendMessageAfterDelay(roomId,"'"+cmd+"' has "+(value||"no")+" karma.");
		}});
		return true;
	}
	if(m.replace(/\s/g,'').length-2 > this.options.maxlength) {
		return false;
	}
	if(m.length>2 && m.length < this.options.maxlength && m.indexOf("++")==m.length-2) {
		this._changeScore(m.substr(0,m.length-2).replace(/\s/g,''),1);
	}
	if(m.length>2 && m.length < this.options.maxlength && m.indexOf("--")==m.length-2) {
		this._changeScore(m.substr(0,m.length-2).replace(/\s/g,''),-1);
	}
	return false;
}

KarmaTrigger.prototype._dbOperation = function(type, details) {
	var that = this;
	this.winston.spam(this.chatBot.name+"/"+this.name+": "+type,details);
	if(this.dbInitialized === false) {
		this.db.init(function(err){
			if(err) {
				that.winston.error(that.chatBot.name+"/"+that.name+": ERROR",err);
			} else {
				that.dbInitialized=true;
				that._dbOperation(type, details);
			}
		});
	} else if(type === "set") {
		that.winston.debug(this.chatBot.name+"/"+this.name+": Setting!");
		this.db.set(details.key, details.value);
	} else if(type === "get") {
		this.db.get(details.key, details.callback);
	}
}
KarmaTrigger.prototype._changeScore = function(key,amount,cb) {
	var that = this;
	var callback = function(err,value){
		if(err) {
			that.winston.error(that.chatBot.name+"/"+that.name+": ERROR",err);
			return;
		} else if(!value) {
			value = 0;
		}
		var details = {
			key: key,
			value: value+amount,
			callback:cb
		}
		that._dbOperation('set', details);
	}
	var score = this._dbOperation('get',{key:key,callback:callback});
}
KarmaTrigger.prototype._stripCommand = function(message, command){
	var that = this;
	var command = command || this.options.command;
	if (command && typeof command === "string" && message && message.toLowerCase().indexOf(command.toLowerCase()) === 0) {
		return(message.substr(command.length+1));
	} else if(command instanceof Array) {
		for(var x=0;x<command.length;x++){
			if(message.toLowerCase().indexOf(command[x].toLowerCase()) === 0) {
				return that._stripCommand(message, command[x]);
			}
		}
	}
	return null;
}
<commit_msg>karmaTrigger.js for codacy<commit_after>var util = require("util");
var BaseTrigger = require("./baseTrigger.js").BaseTrigger;
var ueberDB = require("ueberDB");
/*
A Karma trigger. thing++ increases karma, thing-- decreases it. Spaces are ignored/removed.
options:
command = string or array of strings (optional) - what is the command for the given function?
ueberDB = ueberDB - an *initiated* instance of ueberDB https://github.com/Pita/ueberDB if you don't want to use an sqlite db, or if you don't want to share it.
dbFile = string - path to the sqlite.db file that you want to use.
maxlength = int - what is the maximum length of a key? Default is 25.
*/

var KarmaTrigger = function() {
	KarmaTrigger.super_.apply(this, arguments);
};

util.inherits(KarmaTrigger, BaseTrigger);

var type = "KarmaTrigger";
exports.triggerType = type;
exports.create = function(name, chatBot, options) {
	var trigger = new KarmaTrigger(type, name, chatBot, options);
	trigger.options.command   = trigger.options.command || "!karma";
	trigger.options.maxlength = options.maxlength       || 25;
	trigger.db = options.ueberDB || new ueberDB.database("sqlite", {filename:options.dbFile||(chatBot.name+"/"+name+".db")}, {writeInterval:500});
	trigger.dbInitialized=false;
	return trigger;
};

KarmaTrigger.prototype._respondToFriendMessage = function(userId, message) {
	if(this._stripCommand(message)) {
		this._respondToChatMessage(userId,userId,message);
	}
	return false;
}

// Return true if a message was sent
KarmaTrigger.prototype._respondToChatMessage = function(roomId, chatterId, m) {
	var that = this;
	var cmd = this._stripCommand(m);
	if(cmd) {
		this._dbOperation('get',{key:cmd.replace(/\s/g,'').toLowerCase(),callback:function(err,value){
			if(err) {
				that._sendMessageAfterDelay(roomId,"Error obtaining karma for '"+cmd+"'.");
				that.winston.error(that.chatBot.name+"/"+that.name+": ERROR",err);
				return;
			}
			that._sendMessageAfterDelay(roomId,"'"+cmd+"' has "+(value||"no")+" karma.");
		}});
		return true;
	}
	if(m.replace(/\s/g,'').length-2 > this.options.maxlength) {
		return false;
	}
	if(m.length>2 && m.length < this.options.maxlength && m.indexOf("++")===m.length-2) {
		this._changeScore(m.substr(0,m.length-2).replace(/\s/g,''),1);
	}
	if(m.length>2 && m.length < this.options.maxlength && m.indexOf("--")===m.length-2) {
		this._changeScore(m.substr(0,m.length-2).replace(/\s/g,''),-1);
	}
	return false;
}

KarmaTrigger.prototype._dbOperation = function(type, details) {
	var that = this;
	this.winston.spam(this.chatBot.name+"/"+this.name+": "+type,details);
	if(this.dbInitialized === false) {
		this.db.init(function(err){
			if(err) {
				that.winston.error(that.chatBot.name+"/"+that.name+": ERROR",err);
			} else {
				that.dbInitialized=true;
				that._dbOperation(type, details);
			}
		});
	} else if(type === "set") {
		that.winston.debug(this.chatBot.name+"/"+this.name+": Setting!");
		this.db.set(details.key, details.value);
	} else if(type === "get") {
		this.db.get(details.key, details.callback);
	}
}
KarmaTrigger.prototype._changeScore = function(key,amount,cb) {
	var that = this;
	var callback = function(err,value){
		if(err) {
			that.winston.error(that.chatBot.name+"/"+that.name+": ERROR",err);
			return;
		} else if(!value) {
			value = 0;
		}
		var details = {
			key: key,
			value: value+amount,
			callback:cb
		}
		that._dbOperation('set', details);
	}
	this._dbOperation('get',{key:key,callback:callback});
}
KarmaTrigger.prototype._stripCommand = function(message, command){
	var that = this;
	var command = command || this.options.command;
	if (command && typeof command === "string" && message && message.toLowerCase().indexOf(command.toLowerCase()) === 0) {
		return(message.substr(command.length+1));
	} else if(command instanceof Array) {
		for(var x=0;x<command.length;x++){
			if(message.toLowerCase().indexOf(command[x].toLowerCase()) === 0) {
				return that._stripCommand(message, command[x]);
			}
		}
	}
	return null;
}
<|endoftext|>


<commit_before>'use strict';

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

var array = util.array;
var object = util.object;
var string = util.string;

var isArray = Array.isArray;
var validateIndex = array.validateIndex;

module.exports = function (math) {

  function CrsFormat(data) {
    if (!(this instanceof CrsFormat))
      throw new SyntaxError('Constructor must be called with the new operator');

    // initialize format
    this._format = 'crs';

    // check data is a serialized json
    if (data && isArray(data.values) && isArray(data.index) && isArray(data.ptr)) {
      // initialize fields
      this._values = data.values;
      this._index = data.index;
      this._ptr = data.ptr;
      this._rows = data.rows;
      this._columns = data.columns;
    }
    else if (isArray(data)) {
      // initialize fields
      this._values = [];
      this._index = [];
      this._ptr = [];
      // discover rows & columns, do not use math.size() to avoid looping array twice
      this._rows = data.length;
      this._columns = 0;

      // loop rows
      for (var i = 0; i < data.length; i++) {
        // current row
        var row = data[i];
        // store value index in ptr
        this._ptr.push(this._values.length);
        // update columns if needed
        if (row.length > this._columns)
          this._columns = row.length;
        // loop columns
        for (var j = 0; j < row.length; j++) {
          // value at data[i][j]
          var v = row[j];
          // check value != 0
          if (!math.equal(v, 0)) {
            // store value
            this._values.push(v);
            // add column index
            this._index.push(j);
          }
        }
      }
      // store number of valus in ptr
      this._ptr.push(this._values.length);
    }
    else
      throw new SyntaxError('data must be an array');
  }

  CrsFormat.prototype.toArray = function () {
    // result
    var a = [];
    // values index
    var k = 0;
    // loop rows
    for (var i = 0; i < this._rows; i++) {
      // push row
      var r = a[i] = [];
      // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
      var k0 = this._ptr[i];
      var k1 = this._ptr[i + 1];
      // column pointer
      var p = 0;
      // check k is within [k0, k1[
      while (k >= k0 && k < k1) {
        // column index
        var j = this._index[k];
        // zero values
        for (var x = p; x < j; x++)
          r[x] = 0;
        // set value
        r[j] = this._values[k];
        // increment k
        k++;
        // update pointer
        p = j + 1;
      }
      // zero values
      for (var y = p; y < this._columns; y++)
        r[y] = 0;
    }
    return a;
  };

  CrsFormat.prototype.toJSON = function () {
    return {
      mathjs: 'CrsFormat',
      values: this._values,
      index: this._index,
      ptr: this._ptr,
      rows: this._rows,
      columns: this._columns
    };
  };

  var _getValueIndex = function(j, left, right, index) {
    // check column is on the right side
    if (right - left === 0 || j > index[right - 1])
      return right;
    // loop until we find column
    while (left < right) {
      // point in the middle (fast integer division)
      var p = ~~((left + right) / 2);
      // column @ p
      var c = index[p];
      // check we have to look on the left side, right side or we found the column
      if (j < c)
        right = p;
      else if (j > c)
        left = p + 1;
      else
        return p;
    }
    return left;
  };

  CrsFormat.prototype.get = function (i, j, d) {
    // check i, j are valid
    validateIndex(i, this._rows);
    validateIndex(j, this._columns);

    // find value index
    var k = _getValueIndex(j, this._ptr[i], this._ptr[i + 1], this._index);
    // check k is prior to next row k and it is in the correct column
    if (k < this._ptr[i + 1] && this._index[k] === j)
      return this._values[k];

    return d || 0;
  };

  var _remove = function (k, i, values, index, ptr) {
    // remove value @ k
    values.splice(k, 1);
    index.splice(k, 1);
    // update pointers
    for (var x = i + 1; x < ptr.length; x++)
      ptr[x]--;
  };

  var _insert = function (k, i, j, v, values, index, ptr) {
    // insert value
    values.splice(k, 0, v);
    // update column for k
    index.splice(k, 0, j);
    // update row pointers
    for (var x = i + 1; x < ptr.length; x++)
      ptr[x]++;
  };

  CrsFormat.prototype.set = function (i, j, v) {
    // check i, j are valid
    validateIndex(i, this._rows);
    validateIndex(j, this._columns);

    // find value index
    var k = _getValueIndex(j, this._ptr[i], this._ptr[i + 1], this._index);
    // check k is prior to next row k and it is in the correct column
    if (k < this._ptr[i + 1] && this._index[k] === j) {
      // check value != 0
      if (!math.equal(v, 0)) {
        // update value
        this._values[k] = v;
      }
      else {
        // remove value from matrix
        _remove(k, i, this._values, this._index, this._ptr);
      }
    }
    else {
      // insert value @ (i, j)
      _insert(k, i, j, v, this._values, this._index, this._ptr);
    }
  };

  CrsFormat.prototype.clone = function () {
    var m = new CrsFormat({
      values: object.clone(this._values),
      index: object.clone(this._index),
      ptr: object.clone(this._ptr),
      rows: object.clone(this._rows),
      columns: object.clone(this._columns)
    });
    return m;
  };

  /**
   * Retrieve the size of the matrix.
   * @returns {Number[]} size
   */
  CrsFormat.prototype.size = function() {
    return [this._rows, this._columns];
  };

  /**
   * Get a string representation of the matrix
   * @returns {String} str
   */
  CrsFormat.prototype.toString = function () {
    // rows & columns
    var str = string.format(this._rows) + ' x ' + string.format(this._columns) + '\n';
    // values index
    var k = 0;
    // loop rows
    for (var i = 0; i < this._rows; i++) {
      // value indexes on current row
      var k0 = this._ptr[i];
      var k1 = this._ptr[i + 1];
      // check k is within [k0, k1[
      while (k >= k0 && k < k1) {
        // column index
        var j = this._index[k];
        // append value
        str += '\n(' + string.format(i) + ', ' + string.format(j) + ') = ' + string.format(this._values[k]);
        // increment k
        k++;
      }
    }
    return str;
  };

  CrsFormat.fromJSON = function (json) {
    return new CrsFormat(json);
  };

  CrsFormat.diagonal = function (rows, columns, value) {
    // create arrays
    var values = [];
    var index = [];
    var ptr = [];
    // number of non-zero items
    var n = Math.min(rows, columns);
    // value to store
    var v = value || 1;
    // loop items
    for (var i = 0; i < n; i++) {
      // first column with data
      ptr.push(i);
      // column
      index.push(i);
      // add value
      values.push(v);
    }
    // last value should be number of values
    ptr.push(values.length);
    // create CrsFormat
    return new CrsFormat({
      values: values,
      index: index,
      ptr: ptr,
      rows: rows,
      columns: columns
    });
  };

  return CrsFormat;
};<commit_msg>Initial multiply implementation for CRS<commit_after>'use strict';

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

var array = util.array,
    isNumber = util.number.isNumber,
    isBoolean = util['boolean'].isBoolean,

    object = util.object,
    string = util.string;

var isArray = Array.isArray;
var validateIndex = array.validateIndex;

module.exports = function (math) {

  var isComplex = math.type.Complex.isComplex,
      BigNumber = math.type.BigNumber;

  function CrsFormat(data) {
    if (!(this instanceof CrsFormat))
      throw new SyntaxError('Constructor must be called with the new operator');

    // initialize format
    this._format = 'crs';

    // check data is a serialized json
    if (data && isArray(data.values) && isArray(data.index) && isArray(data.ptr)) {
      // initialize fields
      this._values = data.values;
      this._index = data.index;
      this._ptr = data.ptr;
      this._rows = data.rows;
      this._columns = data.columns;
    }
    else if (isArray(data)) {
      // initialize fields
      this._values = [];
      this._index = [];
      this._ptr = [];
      // discover rows & columns, do not use math.size() to avoid looping array twice
      this._rows = data.length;
      this._columns = 0;

      // loop rows
      for (var i = 0; i < data.length; i++) {
        // current row
        var row = data[i];
        // store value index in ptr
        this._ptr.push(this._values.length);
        // update columns if needed
        if (row.length > this._columns)
          this._columns = row.length;
        // loop columns
        for (var j = 0; j < row.length; j++) {
          // value at data[i][j]
          var v = row[j];
          // check value != 0
          if (!math.equal(v, 0)) {
            // store value
            this._values.push(v);
            // add column index
            this._index.push(j);
          }
        }
      }
      // store number of valus in ptr
      this._ptr.push(this._values.length);
    }
    else
      throw new SyntaxError('data must be an array');
  }

  CrsFormat.prototype.toArray = function () {
    // result
    var a = [];
    // values index
    var k = 0;
    // loop rows
    for (var i = 0; i < this._rows; i++) {
      // push row
      var r = a[i] = [];
      // k0 <= k < k1 where k0 = _ptr[i] && k1 = _ptr[i+1]
      var k0 = this._ptr[i];
      var k1 = this._ptr[i + 1];
      // column pointer
      var p = 0;
      // check k is within [k0, k1[
      while (k >= k0 && k < k1) {
        // column index
        var j = this._index[k];
        // zero values
        for (var x = p; x < j; x++)
          r[x] = 0;
        // set value
        r[j] = this._values[k];
        // increment k
        k++;
        // update pointer
        p = j + 1;
      }
      // zero values
      for (var y = p; y < this._columns; y++)
        r[y] = 0;
    }
    return a;
  };

  CrsFormat.prototype.toJSON = function () {
    return {
      mathjs: 'CrsFormat',
      values: this._values,
      index: this._index,
      ptr: this._ptr,
      rows: this._rows,
      columns: this._columns
    };
  };

  var _getValueIndex = function(j, left, right, index) {
    // check column is on the right side
    if (right - left === 0 || j > index[right - 1])
      return right;
    // loop until we find column
    while (left < right) {
      // point in the middle (fast integer division)
      var p = ~~((left + right) / 2);
      // column @ p
      var c = index[p];
      // check we have to look on the left side, right side or we found the column
      if (j < c)
        right = p;
      else if (j > c)
        left = p + 1;
      else
        return p;
    }
    return left;
  };

  CrsFormat.prototype.get = function (i, j, d) {
    // check i, j are valid
    validateIndex(i, this._rows);
    validateIndex(j, this._columns);

    // find value index
    var k = _getValueIndex(j, this._ptr[i], this._ptr[i + 1], this._index);
    // check k is prior to next row k and it is in the correct column
    if (k < this._ptr[i + 1] && this._index[k] === j)
      return this._values[k];

    return d || 0;
  };

  var _remove = function (k, i, values, index, ptr) {
    // remove value @ k
    values.splice(k, 1);
    index.splice(k, 1);
    // update pointers
    for (var x = i + 1; x < ptr.length; x++)
      ptr[x]--;
  };

  var _insert = function (k, i, j, v, values, index, ptr) {
    // insert value
    values.splice(k, 0, v);
    // update column for k
    index.splice(k, 0, j);
    // update row pointers
    for (var x = i + 1; x < ptr.length; x++)
      ptr[x]++;
  };

  CrsFormat.prototype.set = function (i, j, v) {
    // check i, j are valid
    validateIndex(i, this._rows);
    validateIndex(j, this._columns);

    // find value index
    var k = _getValueIndex(j, this._ptr[i], this._ptr[i + 1], this._index);
    // check k is prior to next row k and it is in the correct column
    if (k < this._ptr[i + 1] && this._index[k] === j) {
      // check value != 0
      if (!math.equal(v, 0)) {
        // update value
        this._values[k] = v;
      }
      else {
        // remove value from matrix
        _remove(k, i, this._values, this._index, this._ptr);
      }
    }
    else {
      // insert value @ (i, j)
      _insert(k, i, j, v, this._values, this._index, this._ptr);
    }
  };

  CrsFormat.prototype.clone = function () {
    var m = new CrsFormat({
      values: object.clone(this._values),
      index: object.clone(this._index),
      ptr: object.clone(this._ptr),
      rows: object.clone(this._rows),
      columns: object.clone(this._columns)
    });
    return m;
  };

  /**
   * Retrieve the size of the matrix.
   * @returns {Number[]} size
   */
  CrsFormat.prototype.size = function() {
    return [this._rows, this._columns];
  };

  /**
   * Get a string representation of the matrix
   * @returns {String} str
   */
  CrsFormat.prototype.toString = function () {
    // rows & columns
    var str = string.format(this._rows) + ' x ' + string.format(this._columns) + '\n';
    // values index
    var k = 0;
    // loop rows
    for (var i = 0; i < this._rows; i++) {
      // value indexes on current row
      var k0 = this._ptr[i];
      var k1 = this._ptr[i + 1];
      // check k is within [k0, k1[
      while (k >= k0 && k < k1) {
        // column index
        var j = this._index[k];
        // append value
        str += '\n(' + string.format(i) + ', ' + string.format(j) + ') = ' + string.format(this._values[k]);
        // increment k
        k++;
      }
    }
    return str;
  };

  CrsFormat.prototype.multiply = function (x) {
    if (arguments.length != 1) {
      throw new math.error.ArgumentsError('multiply', arguments.length, 1);
    }

    // scalar
    if (isNumber(x) || isComplex(x)|| isBoolean(x) || x instanceof BigNumber) {
      // check it is zero
      if (math.equal(x, 0)) {
        // zero ptr
        var ptr = [];
        for (var i = 0; i < this._ptr.length; i++)
          ptr[i] = 0;
        // empty CRS
        return new CrsFormat({
          mathjs: 'CrsFormat',
          values: [],
          index: [],
          ptr: ptr,
          rows: this._rows,
          columns: this._columns
        });
      }
      // multiply values
      var values = [];
      for (var j = 0; j < this._values.length; j++)
        values[j] = math.multiply(this._values[j], x);
      // create storage
      return new CrsFormat({
        mathjs: 'CrsFormat',
        values: values,
        index: object.clone(this._index),
        ptr: object.clone(this._ptr),
        rows: this._rows,
        columns: this._columns
      });
    }
  };

  CrsFormat.fromJSON = function (json) {
    return new CrsFormat(json);
  };

  CrsFormat.diagonal = function (rows, columns, value) {
    // create arrays
    var values = [];
    var index = [];
    var ptr = [];
    // number of non-zero items
    var n = Math.min(rows, columns);
    // value to store
    var v = value || 1;
    // loop items
    for (var i = 0; i < n; i++) {
      // first column with data
      ptr.push(i);
      // column
      index.push(i);
      // add value
      values.push(v);
    }
    // last value should be number of values
    ptr.push(values.length);
    // create CrsFormat
    return new CrsFormat({
      values: values,
      index: index,
      ptr: ptr,
      rows: rows,
      columns: columns
    });
  };

  return CrsFormat;
};
<|endoftext|>


<commit_before>"use babel";
import React from 'react';
import ReactDOM from 'react-dom';
import {Structure} from './Structure';
const Path = require('path');

const lupa = require('lupa');
const analysis = lupa.analysis;
const File = require('vinyl');
const getMetadata = lupa.Metadata.getMetadata;
import {StatusBar} from './StatusBar';
const d = document;
const _ = require('lodash');
const NavigationActions = require('../action-creators/NavigationActions');

// TODO move resize logic to separate component/module
const pos = (e, prev) => {
    const curr = [e.clientX, e.clientY];
    if (!prev) return curr;
    return [curr[0] - prev[0], curr[1] - prev[1]];
}
const resizeHandleStyle = {
    position: 'absolute',
    width: '8px',
    right:'-5px',
    top: 0,
    bottom: 0,
    cursor: 'col-resize'
};
//---

function getEntityFromElement(entities, el) {

    const name = el.getAttribute('data-lupa-entity-name');
    const type = el.getAttribute('data-lupa-entity-type');
    const id = el.getAttribute('data-lupa-entity-id');
    const loc = {start:{}, end:{}};
    loc.start.line = ~~el.getAttribute('data-line');
    loc.start.column = ~~el.getAttribute('data-column');
    console.log("GET ENTITY", name, type, loc);
    return entities.find(ent => {
        return ent.id == id;
        return (
            ent.name == name &&
            ent.type == type &&
            _.get(ent, 'loc.start.line') == loc.start.line &&
            _.get(ent, 'loc.start.column') == loc.start.column
        );
    })
}

export class Lupa extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            file: {
                metadata: []
            },
            w: 220,
            redButton: 0
        }
        this.handleDrag = this.handleDrag.bind(this);
    }
    componentDidMount() {
        // TODO move this from here
        const dispatch = this.props.dispatch;
        this.navigationActions = NavigationActions(dispatch, this.props.editorWrapper);
        const navigationActions = this.navigationActions;

        this.statusBarEvents = {
            onMouseLeave: () => navigationActions.RemovePreview(true),
            onMouseOut: () => navigationActions.RemovePreview(),
            onMouseOver: (entity) => navigationActions.SetPreview(entity),
            onClick: (entity) => navigationActions.GoTo(entity, false, {select: e.altKey})
        };

        window.lupaNavigationActions = navigationActions;
        setInterval(() => {
            const pos = window.lupaStore.getState().activePosition;
            const metadata = this.props.metadata;
            if (pos) {
                const entitiesAtPos = metadata.filter((item) => (
                    item.loc &&
                    item.loc.start.line <= (pos.row + 1) &&
                    item.loc.end.line >= (pos.row + 1)
                ));

                const entities = entitiesAtPos;
                const el = <StatusBar {...this.statusBarEvents}
                    entities={entities}/>;
                ReactDOM.render(el, this.props.breadcrumbsElement);
            }
        }, 300)
    }
    componentWillReceiveProps(nextProps) {
        console.log('compo will', nextProps)
    }
    // TODO move resize logic to separate module/component
    handleMouseDown(e) {
        this.start = pos(e);
        this.w0 = this.state.w;
        d.addEventListener('mousemove', this.handleDrag)
        d.addEventListener('mouseup', this.handleMouseUp.bind(this))
    }
    handleMouseUp(e) {
        d.removeEventListener('mousemove', this.handleDrag)
    }
    handleDrag(e) {
        const delta = pos(e, this.start);
        this.setState({w: Math.max(delta[0] + this.w0, 10) })
    }
    //----
    getStructureEvents(dispatch, metadata) {
        const navigationActions = this.navigationActions;
        return {
            onFocus(e) {
                const el = e.target;//.closest('.lupa-entity');

                if (el.classList.contains('lupa-entity')) {
                        navigationActions.SetPreview(el);

                        const entity = getEntityFromElement(metadata, el);
                        // if (entity) {
                        dispatch({
                            type: 'setActiveEntity',
                            entity: entity
                        })
                        // }
                        console.log("ENT FOC", el.getAttribute('data-lupa-entity-name'));
                }
            },
            onMouseLeave(e) {
                navigationActions.RemovePreview(true);
            },
            // TODO https://jsfiddle.net/6s7tufL5/2/
            onMouseOut(e) {
                navigationActions.RemovePreview();
            },

            onMouseOver(e) {
                navigationActions.SetPreview(e);
            },

            onBlur(e) {
                navigationActions.RemovePreview(true);
            },

            onClick(e) {
                navigationActions.GoTo(e, false, {select: e.altKey});
            }
        }
    }

    render() {
        // TODO move resize logic to separate module/component
        return

            <button
             style={{background: '#b00',
                maxHeight: !this.props.indexed? '1000px': '0',
                boxShadow: !this.props.indexed? '0 0 3px yellow' : 'none',
                transition: '0.7s all',
                width: '60%',
                margin: '10px',
                border: 'none',
                overflow: 'hidden',
                lineHeight: 1,
                padding: !this.props.indexed? '12px 6px': 0,
                textTransform: 'none',
                textAlign: 'center',
                color: 'yellow', borderRadius: 10}}
              onClick={()=> {
                  if (!this.props.indexed) {
                      this.props.dispatch({
                          type: 'indexProject'
                      })
                  }
                  //if (this.props.indexed)
                  this.setState({redButton: this.state.redButton + 1});
              }}
             className="btn cta lupa-index-project">
             {this.props.indexed == 1? 🚀 indexing... 🚀{/*Please do not press
 this button again.*/} : 'Index project'}
             </button>
            <Structure
                metadata={this.props.metadata}
                allMetadata={this.props.allMetadata}
                showInfo={this.state.redButton < 2}
                {...this.getStructureEvents(this.props.dispatch, this.props.metadata)}
                />

    }
}

Lupa.propTypes = {
    editorWrapper: React.PropTypes.shape({
        RememberPosition: React.PropTypes.func.isRequired
    }).isRequired
}
<commit_msg>correct...<commit_after>"use babel";
import React from 'react';
import ReactDOM from 'react-dom';
import {Structure} from './Structure';
const Path = require('path');

const lupa = require('lupa');
const analysis = lupa.analysis;
const File = require('vinyl');
const getMetadata = lupa.Metadata.getMetadata;
import {StatusBar} from './StatusBar';
const d = document;
const _ = require('lodash');
const NavigationActions = require('../action-creators/NavigationActions');

// TODO move resize logic to separate component/module
const pos = (e, prev) => {
    const curr = [e.clientX, e.clientY];
    if (!prev) return curr;
    return [curr[0] - prev[0], curr[1] - prev[1]];
}
const resizeHandleStyle = {
    position: 'absolute',
    width: '8px',
    right:'-5px',
    top: 0,
    bottom: 0,
    cursor: 'col-resize'
};
//---

function getEntityFromElement(entities, el) {

    const name = el.getAttribute('data-lupa-entity-name');
    const type = el.getAttribute('data-lupa-entity-type');
    const id = el.getAttribute('data-lupa-entity-id');
    const loc = {start:{}, end:{}};
    loc.start.line = ~~el.getAttribute('data-line');
    loc.start.column = ~~el.getAttribute('data-column');
    console.log("GET ENTITY", name, type, loc);
    return entities.find(ent => {
        return ent.id == id;
        return (
            ent.name == name &&
            ent.type == type &&
            _.get(ent, 'loc.start.line') == loc.start.line &&
            _.get(ent, 'loc.start.column') == loc.start.column
        );
    })
}

export class Lupa extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            file: {
                metadata: []
            },
            w: 220,
            redButton: 0
        }
        this.handleDrag = this.handleDrag.bind(this);
    }
    componentDidMount() {
        // TODO move this from here
        const dispatch = this.props.dispatch;
        this.navigationActions = NavigationActions(dispatch, this.props.editorWrapper);
        const navigationActions = this.navigationActions;

        this.statusBarEvents = {
            onMouseLeave: () => navigationActions.RemovePreview(true),
            onMouseOut: () => navigationActions.RemovePreview(),
            onMouseOver: (entity) => navigationActions.SetPreview(entity),
            onClick: (entity, e) => navigationActions.GoTo(entity, false, {select: e.altKey})
        };

        window.lupaNavigationActions = navigationActions;
        setInterval(() => {
            const pos = window.lupaStore.getState().activePosition;
            const metadata = this.props.metadata;
            if (pos) {
                const entitiesAtPos = metadata.filter((item) => (
                    item.loc &&
                    item.loc.start.line <= (pos.row + 1) &&
                    item.loc.end.line >= (pos.row + 1)
                ));

                const entities = entitiesAtPos;
                const el = <StatusBar {...this.statusBarEvents}
                    entities={entities}/>;
                ReactDOM.render(el, this.props.breadcrumbsElement);
            }
        }, 300)
    }
    componentWillReceiveProps(nextProps) {
        console.log('compo will', nextProps)
    }
    // TODO move resize logic to separate module/component
    handleMouseDown(e) {
        this.start = pos(e);
        this.w0 = this.state.w;
        d.addEventListener('mousemove', this.handleDrag)
        d.addEventListener('mouseup', this.handleMouseUp.bind(this))
    }
    handleMouseUp(e) {
        d.removeEventListener('mousemove', this.handleDrag)
    }
    handleDrag(e) {
        const delta = pos(e, this.start);
        this.setState({w: Math.max(delta[0] + this.w0, 10) })
    }
    //----
    getStructureEvents(dispatch, metadata) {
        const navigationActions = this.navigationActions;
        return {
            onFocus(e) {
                const el = e.target;//.closest('.lupa-entity');

                if (el.classList.contains('lupa-entity')) {
                        navigationActions.SetPreview(el);

                        const entity = getEntityFromElement(metadata, el);
                        // if (entity) {
                        dispatch({
                            type: 'setActiveEntity',
                            entity: entity
                        })
                        // }
                        console.log("ENT FOC", el.getAttribute('data-lupa-entity-name'));
                }
            },
            onMouseLeave(e) {
                navigationActions.RemovePreview(true);
            },
            // TODO https://jsfiddle.net/6s7tufL5/2/
            onMouseOut(e) {
                navigationActions.RemovePreview();
            },

            onMouseOver(e) {
                navigationActions.SetPreview(e);
            },

            onBlur(e) {
                navigationActions.RemovePreview(true);
            },

            onClick(e) {
                navigationActions.GoTo(e, false, {select: e.altKey});
            }
        }
    }

    render() {
        // TODO move resize logic to separate module/component
        return

            <button
             style={{background: '#b00',
                maxHeight: !this.props.indexed? '1000px': '0',
                boxShadow: !this.props.indexed? '0 0 3px yellow' : 'none',
                transition: '0.7s all',
                width: '60%',
                margin: '10px',
                border: 'none',
                overflow: 'hidden',
                lineHeight: 1,
                padding: !this.props.indexed? '12px 6px': 0,
                textTransform: 'none',
                textAlign: 'center',
                color: 'yellow', borderRadius: 10}}
              onClick={()=> {
                  if (!this.props.indexed) {
                      this.props.dispatch({
                          type: 'indexProject'
                      })
                  }
                  //if (this.props.indexed)
                  this.setState({redButton: this.state.redButton + 1});
              }}
             className="btn cta lupa-index-project">
             {this.props.indexed == 1? 🚀 indexing... 🚀{/*Please do not press
 this button again.*/} : 'Index project'}
             </button>
            <Structure
                metadata={this.props.metadata}
                allMetadata={this.props.allMetadata}
                showInfo={this.state.redButton < 2}
                {...this.getStructureEvents(this.props.dispatch, this.props.metadata)}
                />

    }
}

Lupa.propTypes = {
    editorWrapper: React.PropTypes.shape({
        RememberPosition: React.PropTypes.func.isRequired
    }).isRequired
}
<|endoftext|>