<commit_before>var MongoClient = require('mongodb').MongoClient,
    assert = require('assert');
var exec = require('child_process').exec,
    fs = require('fs'),
    log4js = require('log4js'),
    logger = log4js.getLogger('Core'),
    movesem = require('semaphore')(1),
    deletesem = require('semaphore')(1),
    config = require('config'),
    App = require('./class/app.js').App;

log4js.configure({
  appenders: [
    { type: 'console' },
    { type: 'file', filename: 'play.log' }
  ]
});

var accessDB = function(appVersion, outputDir, dest, htmlPath, tempCommentPath, dirpluginPATH, callback) {
  var hostName = config.get('dbConfig.host'),
      portNumber = config.get('dbConfig.port'),
      dbName = config.get('dbConfig.db'),
      collectionName = config.get('dbConfig.collection');
  var mongoURL = 'mongodb://' + hostName + ':' + portNumber + '/' + dbName;

  MongoClient.connect(mongoURL, function(err, db) {
    assert.equal(null, err);
    logger.info("accessDB::Connected correctly to server for " + appVersion.ID);

    var collection = db.collection(collectionName);
    findDoc(db, collection, appVersion, function(results) {
      if (results.length === 0) {
        insertDoc(db, collection, appVersion, function() {
          logger.info("accessDB::Successfully made directory " + appVersion.path);
          makeDir(appVersion, function() {
            movesem.take(function() {
              moveAPK(dest, appVersion, movesem, function() {
                moveHTML(htmlPath, dirpluginPATH, appVersion, movesem, db, function() {
                  moveComment(tempCommentPath, dirpluginPATH, appVersion, movesem, function() {
                    runScraper(dirpluginPATH, appVersion, function() {
                      movesem.leave();
                      logger.debug("init::Finish download " + appVersion.ID);
                      callback();
                      db.close();
                    })
                  })
                })
              })
            })
          });
        })
      }
      else {
        delAll(appVersion, tempCommentPath, htmlPath, dest, db, function() {
          callback();
        });
      }
    })
  });
}
var insertDoc = function(db, collection, appVersion, callback) {
  if (fs.existsSync(appVersion.path)) {
    collection.insert({'n': appVersion.name, 'verc': appVersion.verc, 'vern': appVersion.vern, 'path': appVersion.path, 'id': appVersion.ID }, function(err, r) {
      assert.equal(err, null);
      callback();
    });
  }
  else {
    return logger.error("insertDoc::File path " + appVersion.path + " does not exist.");
  }
}

var findDoc = function(db, collection, appVersion, callback) {
  collection.find({'n': appVersion.name, 'verc': appVersion.verc, 'vern': appVersion.vern }).toArray(function(err, docs) {
    assert.equal(err, null);
    callback(docs);
  });
}

var makeDir = function(appVersion) {
  makenewCOMMAND = "mkdir -p " + appVersion.path;
  exec(makenewCOMMAND, function(error, stdout, stderr) {
    if (stderr || error) {
      logger.error("accessDB::Making new directory failed for " + appVersion.path);
      return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
    }
    logger.info("accessDB::Successfully made directory " + appVersion.path);
    callback();
  });
}

var moveAPK = function(dest, appVersion, movesem) {
  moveCOMMAND = "mv " + dest + ' ' + appVersion.path + appVersion.ID + '.apk';
  exec(moveCOMMAND, function(error, stdout, stderr) {
    if (stderr || error) { logger.error("accessDB::" + stderr); movesem.leave(); }
    logger.info("accessDB::Moved APK to " + appVersion.path);
    callback();
  });
}

var moveHTML = function(htmlPath, dirpluginPATH, appVersion, movesem, db) {
  if (fs.existsSync(htmlPath)) {
    moveHTMLCOMMAND = "mv " + htmlPath + ' ' + dirpluginPATH + appVersion.ID + '.html';
    exec(moveHTMLCOMMAND, function(error, stdout, stderr) {
      if (stderr || error) {
        movesem.leave();
        return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
      }
      callback();
    });
  }
  else {
    movesem.leave();
    callback();
    db.close();
    return logger.error("accessDB::" + htmlPath + " doesn't exist")
  }
}

var moveComment = function(tempCommentPath, dirpluginPATH, appVersion, movesem) {
  if (tempCommentPath != null) {
    moveCommentCOMMAND = "mv " + tempCommentPath + ' ' + dirpluginPATH + appVersion.ID + '.json5';
    exec(moveCommentCOMMAND, function(error, stdout, stderr) {
      if (stderr || error) {
        movesem.leave();
        return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
      }
      callback();
    });
  }
}

var delAll = function(appVersion, tempCommentPath, htmlPath, dest, db) {
  logger.warn("accessDB::APK already exists for " + appVersion.name + "-" + appVersion.verc);

  deletesem.take(function() {
    DELETEJSON = "rm " + tempCommentPath;
    exec(DELETEJSON, function(error, stdout, stderr) {
      if (stderr || error) { logger.error("accessDB::" + stderr); }
      DELETEHTML = "rm " + htmlPath;
      exec(DELETEHTML, function(error, stdout, stderr) {
        if (stderr || error) {
          logger.error("accessDB::Deleting the HTML failed for " + appVersion.ID)
          logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
        }
        COMMAND = "rm " + dest;
        exec(COMMAND, function(error, stdout, stderr) {
          if (stderr || error) {
            logger.error("accessDB::Deleting the APK failed for " + appVersion.ID);
            deletesem.leave();
            return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
          }
          deletesem.leave();
          callback();
        });
      });
      db.close();
    })
  })
}

var runScraper = function(path, appVersion, callback) {
  var scraper = config.get('scraper'),
      COMMAND = scraper + " " + appVersion.ID + " -o " + path;
  logger.info("accessDB::runScraper:Scraping data for " + appVersion.name + " saved into " + path);
  exec(COMMAND, function(error, stdout, stderr) {
    if (stderr || error) {
      movesem.leave();
      return logger.error("accessDB::runScraper:" + stderr + ". Error:" + error);
    }
    logger.info("accessDB::runScraper:Finished scraping data for " + appVersion.name + " saved into " + path);
    callback();
  });
}

module.exports = accessDB;
<commit_msg>Fix db typos<commit_after>var MongoClient = require('mongodb').MongoClient,
    assert = require('assert');
var exec = require('child_process').exec,
    fs = require('fs'),
    log4js = require('log4js'),
    logger = log4js.getLogger('Core'),
    movesem = require('semaphore')(1),
    deletesem = require('semaphore')(1),
    config = require('config'),
    App = require('./class/app.js').App;

log4js.configure({
  appenders: [
    { type: 'console' },
    { type: 'file', filename: 'play.log' }
  ]
});

var accessDB = function(appVersion, outputDir, dest, htmlPath, tempCommentPath, dirpluginPATH, callback) {
  var hostName = config.get('dbConfig.host'),
      portNumber = config.get('dbConfig.port'),
      dbName = config.get('dbConfig.db'),
      collectionName = config.get('dbConfig.collection');
  var mongoURL = 'mongodb://' + hostName + ':' + portNumber + '/' + dbName;

  MongoClient.connect(mongoURL, function(err, db) {
    assert.equal(null, err);
    logger.info("accessDB::Connected correctly to server for " + appVersion.ID);

    var collection = db.collection(collectionName);
    findDoc(db, collection, appVersion, function(results) {
      if (results.length === 0) {
        makeDir(appVersion, function() {
          insertDoc(db, collection, appVersion, function() {
            logger.info("accessDB::Successfully made directory " + appVersion.path);
            movesem.take(function() {
              moveAPK(dest, appVersion, movesem, function() {
                moveHTML(htmlPath, dirpluginPATH, appVersion, movesem, db, function() {
                  moveComment(tempCommentPath, dirpluginPATH, appVersion, movesem, function() {
                    runScraper(appVersion, function() {
                      movesem.leave();
                      logger.debug("init::Finish download " + appVersion.ID);
                      callback();
                      db.close();
                    })
                  })
                })
              })
            })
          });
        })
      }
      else {
        delAll(appVersion, tempCommentPath, htmlPath, dest, db, function() {
          callback();
        });
      }
    })
  });
}
var insertDoc = function(db, collection, appVersion, callback) {
  if (fs.existsSync(appVersion.path)) {
    collection.insert({'n': appVersion.name, 'verc': appVersion.verc, 'vern': appVersion.vern, 'path': appVersion.path, 'id': appVersion.ID }, function(err, r) {
      assert.equal(err, null);
      callback();
    });
  }
  else {
    return logger.error("insertDoc::File path " + appVersion.path + " does not exist.");
  }
}

var findDoc = function(db, collection, appVersion, callback) {
  collection.find({'n': appVersion.name, 'verc': appVersion.verc, 'vern': appVersion.vern }).toArray(function(err, docs) {
    assert.equal(err, null);
    callback(docs);
  });
}

var makeDir = function(appVersion, callback) {
  makenewCOMMAND = "mkdir -p " + appVersion.path;
  exec(makenewCOMMAND, function(error, stdout, stderr) {
    if (stderr || error) {
      logger.error("accessDB::Making new directory failed for " + appVersion.path);
      return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
    }
    logger.info("accessDB::Successfully made directory " + appVersion.path);
    callback();
  });
}

var moveAPK = function(dest, appVersion, movesem, callback) {
  moveCOMMAND = "mv " + dest + ' ' + appVersion.path + appVersion.ID + '.apk';
  exec(moveCOMMAND, function(error, stdout, stderr) {
    if (stderr || error) { logger.error("accessDB::" + stderr); movesem.leave(); }
    logger.info("accessDB::Moved APK to " + appVersion.path);
    callback();
  });
}

var moveHTML = function(htmlPath, dirpluginPATH, appVersion, movesem, db, callback) {
  if (fs.existsSync(htmlPath)) {
    moveHTMLCOMMAND = "mv " + htmlPath + ' ' + dirpluginPATH + appVersion.ID + '.html';
    exec(moveHTMLCOMMAND, function(error, stdout, stderr) {
      if (stderr || error) {
        movesem.leave();
        return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
      }
      callback();
    });
  }
  else {
    movesem.leave();
    callback();
    db.close();
    return logger.error("accessDB::" + htmlPath + " doesn't exist")
  }
}

var moveComment = function(tempCommentPath, dirpluginPATH, appVersion, movesem, callback) {
  if (tempCommentPath != null) {
    moveCommentCOMMAND = "mv " + tempCommentPath + ' ' + dirpluginPATH + appVersion.ID + '.json5';
    exec(moveCommentCOMMAND, function(error, stdout, stderr) {
      if (stderr || error) {
        movesem.leave();
        return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
      }
      callback();
    });
  }
}

var delAll = function(appVersion, tempCommentPath, htmlPath, dest, db, callback) {
  logger.warn("accessDB::APK already exists for " + appVersion.name + "-" + appVersion.verc);

  deletesem.take(function() {
    DELETEJSON = "rm " + tempCommentPath;
    exec(DELETEJSON, function(error, stdout, stderr) {
      if (stderr || error) { logger.error("accessDB::" + stderr); }
      DELETEHTML = "rm " + htmlPath;
      exec(DELETEHTML, function(error, stdout, stderr) {
        if (stderr || error) {
          logger.error("accessDB::Deleting the HTML failed for " + appVersion.ID)
          logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
        }
        COMMAND = "rm " + dest;
        exec(COMMAND, function(error, stdout, stderr) {
          if (stderr || error) {
            logger.error("accessDB::Deleting the APK failed for " + appVersion.ID);
            deletesem.leave();
            return logger.error("accessDB::stderr:" + stderr + ". Error:" + error);
          }
          deletesem.leave();
          callback();
        });
      });
      db.close();
    })
  })
}

var runScraper = function(appVersion, callback) {
  var scraper = config.get('scraper'),
      COMMAND = scraper + " " + appVersion.ID + " -o " + appVersion.path;
  logger.info("accessDB::runScraper:Scraping data for " + appVersion.name + " saved into " + appVersion.path);
  exec(COMMAND, function(error, stdout, stderr) {
    if (stderr || error) {
      movesem.leave();
      return logger.error("accessDB::runScraper:" + stderr + ". Error:" + error);
    }
    logger.info("accessDB::runScraper:Finished scraping data for " + appVersion.name + " saved into " + appVersion.path);
    callback();
  });
}

module.exports = accessDB;
<|endoftext|>


<commit_before>/* File system primitives.
 * Copyright © 2011 Jan Keromnes, Thaddee Tyl. All rights reserved.
 * The following code is covered by the GPLv2 license. */

var nodefs = require ('fs'),
    nodepath = require ('path'),
    util = require('util'),
    CodeMirrorServer = require('operational-transformation').CodeMirrorServer,
    async = require('async');

var driver = require('./driver'),  // Driver.
    type = require('./type');      // Type system.

// Gather information for the profiler.
//
// Numbers are to computer science what a telescope is to an astrophysicist.

var bench = {
  openFiles: 0,
  totalOpenFilesEver: 0,
  size: 0,
  nbops: {},        // Number of operations per second (for each file).
  nbop: {},         // Number of operations (for each file).
  maxops: ["", 0],
  maxop: ["", 0],
  count: {},        // Number of users (for each file).
  latestFile: "",   // Latest file modified.
};

function profile (param) {
  var data = [
    {doc:'Number of open files', data:bench.openFiles, unit:'files'},
    { doc:'Number of opened files ever',
      data:bench.totalOpenFilesEver,
      unit:'files' },
    {doc:'Core Size (warning -- overstating)', data:bench.size, unit:'bytes'},
    {doc:'Max frenzy for a single file', data:bench.maxops, unit:'op/s'},
    {doc:'Max activity for a single file', data:bench.maxop, unit:'operations'},
    {doc:'Last modified file', data:bench.latestFile},
  ];
  if (param && param.path) {
    data.push({
      doc: 'Frenzy at ' + param.path,
      data: bench.nbops[param.path] || 0,
      unit: 'operations/sec',
    });
    data.push({
      doc: 'Activity at ' + param.path,
      data: bench.nbop[param.path] || 0,
      unit: 'operations',
    });
    data.push({
      doc: 'Number of users at ' + param.path,
      data: bench.count[param.path] || 0,
      unit: 'users'
    });
  }
  return data;
};

// Directory primitives.

// `path` is a String identifying a unique virtual path to the file.
//
// This is the constructor for the File object.
//
//     newFile ( '/path/to/myfile', function(err, file) {
//       …
//     });
//
// - `f.path` is the path (as a String).
// - `f.meta` contains meta information, like the `type`.
// - `f.isOfType` is a method that takes a mime type (as a String).
//   Open the file before using it. Close it when you stop accessing it.
// - `f.open` will count one more user editing that file.
// - `f.close` will count one less user. (That doesn't really matter
//   for folders.)
// - `f.rm` will remove the file for good (if nobody is using it).
// - `f.driver` contains additional functionality associated to files of this
//   type.
// - `f.content`, the content as a string for text files,
//   or an object with a property for each file, that links to the corresponding
//   <File> object, for directories.
//
function File (path) {
  this.path = path;
  this.count = 0;   // Number of users modifying the content.
  this.content = null;
  this.type = null;
  this.meta = {};   // Default: empty (may be overriden by what is on disk).

  this.writo = null;    // Regular write timeout.
  this.nbops = 0;       // Number of operations since last period.
}

var fileFromPath = {};  // From (fake) paths to already loaded files.

function file (vpath, cb) {
  var path = driver.normalize(vpath);
  if (fileFromPath[path] !== undefined) {
    cb(null, fileFromPath[path]);
    return;
  }

  var that = fileFromPath[path] = new File(path);
  type.guessType(that.path, function (err, td) {
    if (err) {
      //console.error("While guessing type of", that.path, err.stack);
      delete fileFromPath[path];
      cb(err);
      return;
    }
    if (td === undefined) {
      that.type = type.fromName['text'];
    } else {
      that.type = td;    // `td`: type descriptor (Number).
    }
    that.driver = type.driver(that.type);

    driver.loadMeta(that.path, function (err, meta) {
      if (err && err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
        console.error('error', err.code, 'with metadata of', that.path);
        // The metadata will be written to disk because it doesn't have a type.
        that.meta = {};
      } else {
        that.meta = meta || {};
      }

      if (that.meta.type === undefined) {
        that.meta.type = type.nameFromType[that.type];
        that.writeMeta();
      }
      if (that.meta['Last-Modified'] === undefined) {
        that.touch();
        that.writeMeta();
      }
      cb(null, that);
    });
  });
}

// Checks whether a `file` is of type `typename` (or falls back into it).
//
// - `file`: a File.
// - `mimeType`: a string, case-perfect match of a defined Type.
//
// Warning: this is not *cycle-safe* just yet. This is only an issue if you
// have mistakenly created a loop in the type system.
// It can really screw everything up though.
File.prototype.isOfType = function (mimeType) {
  if (this.type === undefined) {
    console.error('fs:isoftype: file %s has no type.', this.path);
  }
  return type.isCompatible(this.type, type.fromName[mimeType]);
};

// We try to write the file to disk every half minute.
File.writePeriod = 30000;

// The following function is meant to be bound to a file.
// It writes the file to disk if there were modifications.
function writeAtPeriod() {
  if (!bench.nbop[this.path])  bench.nbop[this.path] = 0;
  bench.nbop[this.path] += this.nbops;
  bench.nbops[this.path] = this.nbops / File.writePeriod * 1000;
  if (bench.maxops[1] <= this.nbops) {
    bench.maxops = [this.path, bench.nbops[this.path]];
  }
  if (bench.maxop[1] <= bench.nbop[this.path]) {
    bench.maxop = [this.path, bench.nbop[this.path]];
  }
  if (this.nbops > 0) {
    this.write();
  }
  this.nbops = 0;
}

// When you open a file, its content becomes synchronous, immediately available.
// Use it when you need to use readSync and writeSync.
File.prototype.open = function (cb) {
  //console.log('opening file', this.path);
  // If this file had no user, populate the content.
  if (this.count <= 0) {
    var that = this;
    this.driver.read(this.path, function(err, data) {
      if (err !== null) {
        console.error('fs:open:', err.message);
      } else {
        that.content = data;
        // Strings are UCS-2 (or UTF-16): characters are 2 bytes.
        if (data.length)  bench.size += that.content.length * 2;

        // Counts.
        that.count++;
        bench.openFiles++;
        bench.totalOpenFilesEver++;
        bench.count[that.path] = 1;

        if (that.driver.write) {
          that.writo = setInterval(writeAtPeriod.bind(that), File.writePeriod);
        }
      }
      cb(err, data);
    });
  } else {
    // Counts.
    this.count++;
    bench.openFiles++;
    bench.totalOpenFilesEver++;
    bench.count[this.path]++;
    cb(null);
  }
};

File.prototype.close = function () {
  //console.log('closing file', this.path);
  if (this.count <= 0) {
    console.error('fs:file: count is negative (%s). Keeping it at 0.',
        this.count);
  } else {
    this.count--;
    bench.openFiles--;
    bench.count[this.path]--;
  }

  if (this.count === 0) {
    var self = this;
    if (this.driver.write) {
      clearInterval(this.writo);
      this.write(function (err) {
        if (err) console.error('fs:write:', err.message);
        self.content = null;    // Let it be garbage-collected.
      });
    } else this.content = null;
    delete fileFromPath[this.path];
  }
};

File.prototype.write = function (cb) {
  if (this.content !== null && this.driver.write) {
    this.driver.write(this.path, this.content, this.meta, cb);
  }
};

File.prototype.writeMeta = function (cb) {
  driver.dumpMeta(this.path, this.meta, cb);
};

File.prototype.touch = function () {
  this.meta['Last-Modified'] = Date.now();
};

File.prototype.ot = function (io, cb) {
  var channel = io.of(this.path),
      file = this;
  this.open(function (err) {
    if (err) {
      cb(err); file.close(); return;
    } else if (!channel.codeMirrorServer) {
      channel.codeMirrorServer = new CodeMirrorServer(
          file.content,
          channel,
          [],
          function (socket, cb) { cb(true); }
      );

      channel.on('connection', function (socket) {
        // Call this function after the server send the user information to
        // the new client, such that the user
        // doesn't receive his own information.
        process.nextTick(function () {
          channel.codeMirrorServer.setName(socket, '' + (+new Date()));
        });

        socket.on('disconnect', function () { file.close(); });

        socket.on('operation', function () {
          file.nbops++;
          file.content = channel.codeMirrorServer.str;
          file.touch();
          bench.latestFile = file.path;
        });
      });

      cb(null);
    } else {
      cb(null);
    }
  });
};

File.prototype.rm = function (cb) {
  if (this.driver.rm) {
    // We have removed the file, but we need the parent folder to acknowledge it
    var parentPath = nodepath.dirname(this.path);
    if (fileFromPath[parentPath] !== undefined) {
      // We only do this if it is loaded in memory.
      var subfile = this;
      file(parentPath, function(err, parent) {
        if (parent.count > 0) {
          // The content is loaded.
          var subfileIndex = parent.content.indexOf(
            nodepath.basename(subfile.path));
          parent.content.splice(subfileIndex, 1);
        }
      });
    }

    this.driver.rm(this.path, cb);
  } else {
    console.error("Fs:File:rm: Cannot rm file %s of driver %s.",
        this.path, util.inspect(this.driver));
  }
};

// The following two functions are directory-only.

File.prototype.mkdir = function (name, cb) {
  if (this.isOfType('dir')) {
    // We don't want name to have slashes (avoid attacks).
    if (name.indexOf('/') !== -1) {
      console.error("fs:file:mkdir: cannot make folder %s which has a /.", name);
    } else {
      var self = this;
      this.driver.mkdir(this.path + '/' + name + '/', function (err) {
        if (!err) { self.touch(); }
        cb(err);
      });
    }
  } else {
    console.error("fs:file:mkdir: tried to make folder %s from non-folder %s.",
        name, this.path);
  }
};

File.prototype.mkfile = function (name, cb) {
  if (this.driver.mkfile) {
    // We don't want name to have slashes (avoid attacks).
    if (name.indexOf('/') !== -1) {
      console.error("fs:file:mkdir: cannot make folder %s which has a /.", name);
    } else {
      var self = this;
      this.driver.mkfile(this.path + '/' + name, function (err) {
        if (!err) { self.touch(); }
        cb(err);
      });
    }
  } else {
    console.error("fs:file:mkfile: tried to make file %s from non-folder %s.",
        name, this.path);
  }
};

// We may want to have all the files (as actual file objects) of a folder.
File.prototype.files = function (cb) {
  if (!this.isOfType('dir')) {
    cb(new Error("You can only get the files of a directory."));
    return;
  }

  var folder = this;

  folder.open(function(err) {
    if (err) { cb(err); return; }

    // Now we can use the content.
    async.map(folder.content, function(item, cb2) {
      file(folder.path + '/' + item, function(err, f) {
        if (err) { cb2(err); return; }
        cb2(null, f);
      });
    }, function(err, files) {
      // We are finished now.  All files are processed!
      cb(err, files);   // Return from continuation.
      folder.close();
    });
  });
};

// `Subfiles` gives all the leafs of the tree recursively, as relative paths.
//
// The callback `cb` is of the form `function(err, leafs) { … }`.
File.prototype.subfiles = function (cb, depth) {
  depth = depth !== undefined? depth: Infinity;

  // This function is meant to return [] if this is not a directory.
  if (!this.isOfType('dir')) { cb(null, []); return; }

  var folder = this,
      paths = [];

  folder.open(function(err) {
    async.forEach(folder.content, function(item, cb2) {
      file(folder.path + '/' + item, function(err, f) {
        if (err) { cb2(err); return; }
        var isDir = f.isOfType('dir');
        paths.push(item + (isDir? '/': ''));

        if (depth > 0 && isDir) {
          // We need to go deeper! ☺
          f.subfiles(function(err, leafs) {
            for (var i = 0; i < leafs.length; i++) { leafs[i] = item + '/' + leafs[i]; }
            paths = paths.concat(leafs);
            cb2();
          }, depth - 1);
        } else {
          cb2();
        }
      });
    }, function(err) {
      // We are finished now.  All files are processed!
      cb(err, paths);   // Return from continuation.
      folder.close();
    });
  });
};

// Exports.

exports.fileFromPath = fileFromPath;
exports.type = type;
exports.file = file;
exports.profile = profile;

<commit_msg>Fix to issue #158: this.driver is not defined for the path '/'.<commit_after>/* File system primitives.
 * Copyright © 2011 Jan Keromnes, Thaddee Tyl. All rights reserved.
 * The following code is covered by the GPLv2 license. */

var nodefs = require ('fs'),
    nodepath = require ('path'),
    util = require('util'),
    CodeMirrorServer = require('operational-transformation').CodeMirrorServer,
    async = require('async');

var driver = require('./driver'),  // Driver.
    type = require('./type');      // Type system.

// Gather information for the profiler.
//
// Numbers are to computer science what a telescope is to an astrophysicist.

var bench = {
  openFiles: 0,
  totalOpenFilesEver: 0,
  size: 0,
  nbops: {},        // Number of operations per second (for each file).
  nbop: {},         // Number of operations (for each file).
  maxops: ["", 0],
  maxop: ["", 0],
  count: {},        // Number of users (for each file).
  latestFile: "",   // Latest file modified.
};

function profile (param) {
  var data = [
    {doc:'Number of open files', data:bench.openFiles, unit:'files'},
    { doc:'Number of opened files ever',
      data:bench.totalOpenFilesEver,
      unit:'files' },
    {doc:'Core Size (warning -- overstating)', data:bench.size, unit:'bytes'},
    {doc:'Max frenzy for a single file', data:bench.maxops, unit:'op/s'},
    {doc:'Max activity for a single file', data:bench.maxop, unit:'operations'},
    {doc:'Last modified file', data:bench.latestFile},
  ];
  if (param && param.path) {
    data.push({
      doc: 'Frenzy at ' + param.path,
      data: bench.nbops[param.path] || 0,
      unit: 'operations/sec',
    });
    data.push({
      doc: 'Activity at ' + param.path,
      data: bench.nbop[param.path] || 0,
      unit: 'operations',
    });
    data.push({
      doc: 'Number of users at ' + param.path,
      data: bench.count[param.path] || 0,
      unit: 'users'
    });
  }
  return data;
};

// Directory primitives.

// `path` is a String identifying a unique virtual path to the file.
//
// This is the constructor for the File object.
//
//     newFile ( '/path/to/myfile', function(err, file) {
//       …
//     });
//
// - `f.path` is the path (as a String).
// - `f.meta` contains meta information, like the `type`.
// - `f.isOfType` is a method that takes a mime type (as a String).
//   Open the file before using it. Close it when you stop accessing it.
// - `f.open` will count one more user editing that file.
// - `f.close` will count one less user. (That doesn't really matter
//   for folders.)
// - `f.rm` will remove the file for good (if nobody is using it).
// - `f.driver` contains additional functionality associated to files of this
//   type.
// - `f.content`, the content as a string for text files,
//   or an object with a property for each file, that links to the corresponding
//   <File> object, for directories.
//
function File (path) {
  this.path = path;
  this.count = 0;   // Number of users modifying the content.
  this.content = null;
  this.type = null;
  this.meta = {};   // Default: empty (may be overriden by what is on disk).

  this.writo = null;    // Regular write timeout.
  this.nbops = 0;       // Number of operations since last period.
}

var fileFromPath = {};  // From (fake) paths to already loaded files.

function file (vpath, cb) {
  var path = driver.normalize(vpath);
  if (fileFromPath[path] !== undefined) {
    cb(null, fileFromPath[path]);
    return;
  }

  var that = fileFromPath[path] = new File(path);
  type.guessType(that.path, function (err, td) {
    if (err) {
      //console.error("While guessing type of", that.path, err.stack);
      delete fileFromPath[path];
      cb(err);
      return;
    }
    if (td === undefined) {
      that.type = type.fromName['text'];
    } else {
      that.type = td;    // `td`: type descriptor (Number).
    }
    that.driver = type.driver(that.type);

    driver.loadMeta(that.path, function (err, meta) {
      if (err && err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
        console.error('error', err.code, 'with metadata of', that.path);
        // The metadata will be written to disk because it doesn't have a type.
        that.meta = {};
      } else {
        that.meta = meta || {};
      }

      if (that.meta.type === undefined) {
        that.meta.type = type.nameFromType[that.type];
        that.writeMeta();
      }
      if (that.meta['Last-Modified'] === undefined) {
        that.touch();
        that.writeMeta();
      }
      cb(null, that);
    });
  });
}

// Checks whether a `file` is of type `typename` (or falls back into it).
//
// - `file`: a File.
// - `mimeType`: a string, case-perfect match of a defined Type.
//
// Warning: this is not *cycle-safe* just yet. This is only an issue if you
// have mistakenly created a loop in the type system.
// It can really screw everything up though.
File.prototype.isOfType = function (mimeType) {
  if (this.type === undefined) {
    console.error('fs:isoftype: file %s has no type.', this.path);
  }
  return type.isCompatible(this.type, type.fromName[mimeType]);
};

// We try to write the file to disk every half minute.
File.writePeriod = 30000;

// The following function is meant to be bound to a file.
// It writes the file to disk if there were modifications.
function writeAtPeriod() {
  if (!bench.nbop[this.path])  bench.nbop[this.path] = 0;
  bench.nbop[this.path] += this.nbops;
  bench.nbops[this.path] = this.nbops / File.writePeriod * 1000;
  if (bench.maxops[1] <= this.nbops) {
    bench.maxops = [this.path, bench.nbops[this.path]];
  }
  if (bench.maxop[1] <= bench.nbop[this.path]) {
    bench.maxop = [this.path, bench.nbop[this.path]];
  }
  if (this.nbops > 0) {
    this.write();
  }
  this.nbops = 0;
}

// When you open a file, its content becomes synchronous, immediately available.
// Use it when you need to use readSync and writeSync.
File.prototype.open = function (cb) {
  //console.log('opening file', this.path);
  // If this file had no user, populate the content.
  if (this.count <= 0) {
    var that = this;
    this.driver.read(this.path, function(err, data) {
      if (err !== null) {
        console.error('fs:open:', err.message);
      } else {
        that.content = data;
        // Strings are UCS-2 (or UTF-16): characters are 2 bytes.
        if (data.length)  bench.size += that.content.length * 2;

        // Counts.
        that.count++;
        bench.openFiles++;
        bench.totalOpenFilesEver++;
        bench.count[that.path] = 1;

        if (that.driver.write) {
          that.writo = setInterval(writeAtPeriod.bind(that), File.writePeriod);
        }
      }
      cb(err, data);
    });
  } else {
    // Counts.
    this.count++;
    bench.openFiles++;
    bench.totalOpenFilesEver++;
    bench.count[this.path]++;
    cb(null);
  }
};

File.prototype.close = function () {
  //console.log('closing file', this.path);
  if (this.count <= 0) {
    console.error('fs:file: count is negative (%s). Keeping it at 0.',
        this.count);
  } else {
    this.count--;
    bench.openFiles--;
    bench.count[this.path]--;
  }

  if (this.count === 0) {
    var self = this;
    if (this.driver.write) {
      clearInterval(this.writo);
      this.write(function (err) {
        if (err) console.error('fs:write:', err.message);
        self.content = null;    // Let it be garbage-collected.
      });
    } else this.content = null;
    if (this.path !== '/') delete fileFromPath[this.path];
  }
};

File.prototype.write = function (cb) {
  if (this.content !== null && this.driver.write) {
    this.driver.write(this.path, this.content, this.meta, cb);
  }
};

File.prototype.writeMeta = function (cb) {
  driver.dumpMeta(this.path, this.meta, cb);
};

File.prototype.touch = function () {
  this.meta['Last-Modified'] = Date.now();
};

File.prototype.ot = function (io, cb) {
  var channel = io.of(this.path),
      file = this;
  this.open(function (err) {
    if (err) {
      cb(err); file.close(); return;
    } else if (!channel.codeMirrorServer) {
      channel.codeMirrorServer = new CodeMirrorServer(
          file.content,
          channel,
          [],
          function (socket, cb) { cb(true); }
      );

      channel.on('connection', function (socket) {
        // Call this function after the server send the user information to
        // the new client, such that the user
        // doesn't receive his own information.
        process.nextTick(function () {
          channel.codeMirrorServer.setName(socket, '' + (+new Date()));
        });

        socket.on('disconnect', function () { file.close(); });

        socket.on('operation', function () {
          file.nbops++;
          file.content = channel.codeMirrorServer.str;
          file.touch();
          bench.latestFile = file.path;
        });
      });

      cb(null);
    } else {
      cb(null);
    }
  });
};

File.prototype.rm = function (cb) {
  if (this.driver.rm) {
    // We have removed the file, but we need the parent folder to acknowledge it
    var parentPath = nodepath.dirname(this.path);
    if (fileFromPath[parentPath] !== undefined) {
      // We only do this if it is loaded in memory.
      var subfile = this;
      file(parentPath, function(err, parent) {
        if (parent.count > 0) {
          // The content is loaded.
          var subfileIndex = parent.content.indexOf(
            nodepath.basename(subfile.path));
          parent.content.splice(subfileIndex, 1);
        }
      });
    }

    this.driver.rm(this.path, cb);
  } else {
    console.error("Fs:File:rm: Cannot rm file %s of driver %s.",
        this.path, util.inspect(this.driver));
  }
};

// The following two functions are directory-only.

File.prototype.mkdir = function (name, cb) {
  if (this.isOfType('dir')) {
    // We don't want name to have slashes (avoid attacks).
    if (name.indexOf('/') !== -1) {
      console.error("fs:file:mkdir: cannot make folder %s which has a /.", name);
    } else {
      var self = this;
      this.driver.mkdir(this.path + '/' + name + '/', function (err) {
        if (!err) { self.touch(); }
        cb(err);
      });
    }
  } else {
    console.error("fs:file:mkdir: tried to make folder %s from non-folder %s.",
        name, this.path);
  }
};

File.prototype.mkfile = function (name, cb) {
  if (this.driver.mkfile) {
    // We don't want name to have slashes (avoid attacks).
    if (name.indexOf('/') !== -1) {
      console.error("fs:file:mkdir: cannot make folder %s which has a /.", name);
    } else {
      var self = this;
      this.driver.mkfile(this.path + '/' + name, function (err) {
        if (!err) { self.touch(); }
        cb(err);
      });
    }
  } else {
    console.error("fs:file:mkfile: tried to make file %s from non-folder %s.",
        name, this.path);
  }
};

// We may want to have all the files (as actual file objects) of a folder.
File.prototype.files = function (cb) {
  if (!this.isOfType('dir')) {
    cb(new Error("You can only get the files of a directory."));
    return;
  }

  var folder = this;

  folder.open(function(err) {
    if (err) { cb(err); return; }

    // Now we can use the content.
    async.map(folder.content, function(item, cb2) {
      file(folder.path + '/' + item, function(err, f) {
        if (err) { cb2(err); return; }
        cb2(null, f);
      });
    }, function(err, files) {
      // We are finished now.  All files are processed!
      cb(err, files);   // Return from continuation.
      folder.close();
    });
  });
};

// `Subfiles` gives all the leafs of the tree recursively, as relative paths.
//
// The callback `cb` is of the form `function(err, leafs) { … }`.
File.prototype.subfiles = function (cb, depth) {
  depth = depth !== undefined? depth: Infinity;

  // This function is meant to return [] if this is not a directory.
  if (!this.isOfType('dir')) { cb(null, []); return; }

  var folder = this,
      paths = [];

  folder.open(function(err) {
    async.forEach(folder.content, function(item, cb2) {
      file(folder.path + '/' + item, function(err, f) {
        if (err) { cb2(err); return; }
        var isDir = f.isOfType('dir');
        paths.push(item + (isDir? '/': ''));

        if (depth > 0 && isDir) {
          // We need to go deeper! ☺
          f.subfiles(function(err, leafs) {
            for (var i = 0; i < leafs.length; i++) { leafs[i] = item + '/' + leafs[i]; }
            paths = paths.concat(leafs);
            cb2();
          }, depth - 1);
        } else {
          cb2();
        }
      });
    }, function(err) {
      // We are finished now.  All files are processed!
      cb(err, paths);   // Return from continuation.
      folder.close();
    });
  });
};

// Exports.

exports.fileFromPath = fileFromPath;
exports.type = type;
exports.file = file;
exports.profile = profile;

<|endoftext|>


<commit_before>import { expect } from 'chai';
import reducer from '../../reducers/notifications';
import {
  NOTIFICATIONS_REQUEST, NOTIFICATIONS_SUCCESS, NOTIFICATIONS_FAILURE,
  MARK_NOTIFICATION_SUCCESS, MARK_REPO_NOTIFICATION_SUCCESS
} from '../../actions';

describe('reducers/notifications.js', () => {
  const initialState = {
    response: [],
    isFetching: false,
    failed: false
  };

  it('should return the initial state', () => {

    expect(reducer(undefined, {})).to.eql(initialState);

  });

  it('should handle NOTIFICATIONS_REQUEST', () => {

    const action = {
      type: NOTIFICATIONS_REQUEST,
      query: 'hello'
    };

    expect(reducer(undefined, action)).to.eql({
      ...initialState,
      isFetching: true,
      failed: false
    });

  });

  it('should handle NOTIFICATIONS_SUCCESS', () => {

    const notifications = [
      {
        id: 1,
        repository: 'ekonstantinidis/gitify',
        text: 'New Release'
      },
      {
        id: 2,
        repository: 'ekonstantinidis/gitify',
        text: 'It\'s Great'
      }
    ];

    expect(reducer(undefined, {})).to.eql(initialState);

    const action = {
      type: NOTIFICATIONS_SUCCESS,
      payload: notifications
    };

    const currentState = {
      ...initialState,
      isFetching: true,
      failed: false
    };

    expect(reducer(currentState, action)).to.eql({
      ...initialState,
      isFetching: false,
      response: notifications
    });

  });

  it('should handle NOTIFICATIONS_FAILURE', () => {

    const response = {
      error: 404,
      message: 'Oops! Something went wrong.'
    };

    const currentState = {
      ...initialState,
      isFetching: true,
      failed: false
    };

    expect(reducer(currentState, {})).to.eql(currentState);

    const action = {
      type: NOTIFICATIONS_FAILURE,
      payload: response
    };

    expect(reducer(currentState, action)).to.eql({
      ...initialState,
      isFetching: false,
      failed: true,
      response: response
    });

  });
});
<commit_msg>Complete tests for notifications reducer<commit_after>import { expect } from 'chai';
import reducer from '../../reducers/notifications';
import {
  NOTIFICATIONS_REQUEST, NOTIFICATIONS_SUCCESS, NOTIFICATIONS_FAILURE,
  MARK_NOTIFICATION_SUCCESS, MARK_REPO_NOTIFICATION_SUCCESS
} from '../../actions';

describe('reducers/notifications.js', () => {
  const initialState = {
    response: [],
    isFetching: false,
    failed: false
  };

  const notifications = [
    {
      id: 1,
      repository: {
        full_name: 'ekonstantinidis/gitify'
      },
      text: 'New Release'
    },
    {
      id: 2,
      repository: {
        full_name: 'ekonstantinidis/gitify'
      },
      text: 'It\'s Great'
    }
  ];

  it('should return the initial state', () => {

    expect(reducer(undefined, {})).to.eql(initialState);

  });

  it('should handle NOTIFICATIONS_REQUEST', () => {

    const action = {
      type: NOTIFICATIONS_REQUEST,
      query: 'hello'
    };

    expect(reducer(undefined, action)).to.eql({
      ...initialState,
      isFetching: true,
      failed: false
    });

  });

  it('should handle NOTIFICATIONS_SUCCESS', () => {

    expect(reducer(undefined, {})).to.eql(initialState);

    const action = {
      type: NOTIFICATIONS_SUCCESS,
      payload: notifications
    };

    const currentState = {
      ...initialState,
      isFetching: true,
      failed: false
    };

    expect(reducer(currentState, action)).to.eql({
      ...initialState,
      isFetching: false,
      response: notifications
    });

  });

  it('should handle NOTIFICATIONS_FAILURE', () => {

    const response = {
      error: 404,
      message: 'Oops! Something went wrong.'
    };

    const currentState = {
      ...initialState,
      isFetching: true,
      failed: false
    };

    expect(reducer(currentState, {})).to.eql(currentState);

    const action = {
      type: NOTIFICATIONS_FAILURE,
      payload: response
    };

    expect(reducer(currentState, action)).to.eql({
      ...initialState,
      isFetching: false,
      failed: true,
      response: response
    });

  });

  it('should handle MARK_NOTIFICATION_SUCCESS', () => {

    const currentState = {
      ...initialState,
      response: notifications
    };

    expect(reducer(currentState, {}).response.length).to.equal(2);

    const action = {
      type: MARK_NOTIFICATION_SUCCESS,
      meta: {
        id: 1
      }
    };

    expect(reducer(currentState, action).response.length).to.equal(1);

  });

  it('should handle MARK_REPO_NOTIFICATION_SUCCESS', () => {

    const currentState = {
      ...initialState,
      response: notifications
    };

    expect(reducer(currentState, {}).response.length).to.equal(2);

    const action = {
      type: MARK_REPO_NOTIFICATION_SUCCESS,
      meta: {
        repoFullName: 'ekonstantinidis/gitify'
      }
    };

    expect(reducer(currentState, action).response.length).to.equal(0);

  });
});
<|endoftext|>


<commit_before>import ControlledModalWrapper from 'components/Modals/ControlledModalWrapper';
import mapActions from 'actions/MapActions';
import text from 'js/languages';
import esriRequest from 'esri/request';
import geojsonUtil from 'utils/arcgis-to-geojson';
import symbols from 'utils/symbols';
import Polygon from 'esri/geometry/Polygon';
import Graphic from 'esri/graphic';
import React, {Component, PropTypes} from 'react';

export default class SubscribeModal extends Component {

  static contextTypes = {
    language: PropTypes.string.isRequired,
    map: PropTypes.object.isRequired
  };

  constructor(props) {
    super(props);
    this.state = {
      currentStep: 1,
      activeLanguage: 'English', //TODO: Get from context!
      email: '',
      aoiName: '',
      viirsAlerts: false,
      treeCoverAlerts: true,
      warnings: false
    };
  }

  updateEmail = evt => {
    this.setState({
      email: evt.target.value
    });
  }

  updateAreaName = evt => {
    this.setState({
      aoiName: evt.target.value
    });
  }

  optionMapper = (item) => {
    return <option key={item} value={item}>{item}</option>;
  };

  close = () => {
    mapActions.toggleSubscribeModal({ visible: false });
  };

  updateVIIRS = () => {
    this.setState({
      viirsAlerts: !this.state.viirsAlerts
    });
  }

  updateLoss = () => {
    this.setState({
      treeCoverAlerts: !this.state.treeCoverAlerts
    });
  }

  changeLanguage = evt => {
    this.setState({
      activeLanguage: evt.target.value
    });
  }

  next = () => {
    this.setState({
      currentStep: this.state.currentStep + 1
    });
  }

  back = () => {
    this.setState({
      currentStep: this.state.currentStep - 1
    });
  }

  save = () => {
    const { email, aoiName, viirsAlerts, treeCoverAlerts } = this.state;
    const selectedFeature = this.context.map.infoWindow.getSelectedFeature();

    console.log(this.state);

    if (email && aoiName && selectedFeature && (viirsAlerts || treeCoverAlerts)) {
      const datasets = [];
      if (viirsAlerts) {
        datasets.push('viirs-active-fires');
      }
      if (treeCoverAlerts) {
        datasets.push('umd-loss-gain');
      }
      const jsonData = {
        datasets: datasets,
        language: this.state.activeLanguage === 'English' ? 'en' : 'sp', //TODO: Switch statement over all of our possibilities
        name: aoiName,
        params: {
          geostore: selectedFeature.attributes.geostoreId,
          iso: {
            country: null,
            region: null
          },
          use: null,
          useid: null,
          wdpaid: null
        },
        resource: {
          content: this.state.email,
          type: 'EMAIL'
        }
      };

      console.log('jsonData', jsonData);
      $.ajax({
        url: 'https://production-api.globalforestwatch.org/v1/subscriptions',
        dataType: 'json',
        method: 'POST',
        data: jsonData,
        xhrFields: {
          withCredentials: true
        },
        success: (response) => {
          console.log('resss', response);
          this.setState({
            currentStep: 0,
            warnings: false,
            success: true
          });
        },
        error: (error) => {
          console.log('errr', error);
        }
      });
    } else {
      this.setState({
        warnings: true
      });
    }
  }

  render () {
    // const {language} = this.context;
    const langs = ['English', 'Spanish']; //TODO: Get from resources or config!

    return (
      <ControlledModalWrapper onClose={this.close}>
        <div className={`subscribe-step ${this.state.currentStep === 0 ? '' : 'hidden'}`}>

Subscription saved!

              This subscription has been added to your profile. Please
              check your email and click on the link to confirm your
              subscription. Visit your saved subscriptions to manage them.

        <div className={`subscribe-step ${this.state.currentStep === 1 ? '' : 'hidden'}`}>

Forest change alerts

Select the forest change alerts you would like to receive

            VIIRS active fire alerts<input className="dataset-checkbox" type="checkbox" checked={this.state.viirsAlerts} onChange={this.updateVIIRS} name="datasets" id="viirs-active-fires" />
            Tree cover loss data<input className="dataset-checkbox" type="checkbox" checked={this.state.treeCoverAlerts} onChange={this.updateLoss} name="datasets" id="umd-loss-gain" />

        <div className={`subscribe-step ${this.state.currentStep === 2 ? '' : 'hidden'}`}>

Subscribe to alerts

Enter your email below to receive an email notification when there are new annual tree cover loss data available for this area.

            <input className="alert-input" placeholder='Enter email' onChange={this.updateEmail} />

        <div className={`subscribe-step ${this.state.currentStep === 3 ? '' : 'hidden'}`}>

Name your subscription

Name

            <input className="subscription-name" placeholder='Area name' onChange={this.updateAreaName} />

Receive Alert Emails In...

            <select className='language-selector' onChange={this.changeLanguage} value={this.state.activeLanguage}>
              {langs.map(this.optionMapper)}
            </select>

          <div className={`subscribe-warnings ${this.state.warnings ? '' : 'hidden'}`}>You must have an alert subscription, valid email, and area name!

          {this.state.currentStep === 0 ? <button className='fa-button gold' onClick={this.next}>OK!</button> : null }
          {this.state.currentStep > 1 ? <button className='fa-button gold' onClick={this.back}>Back</button> : null }
          {this.state.currentStep === 1 || this.state.currentStep === 2 ? <button className='fa-button gold' onClick={this.next}>Next</button> : null }
          {this.state.currentStep === 3 ? <button className='fa-button gold' onClick={this.save}>Save</button> : null }

      </ControlledModalWrapper>
    );
  }

}
<commit_msg>Proper reset, new call after subscription request<commit_after>import ControlledModalWrapper from 'components/Modals/ControlledModalWrapper';
import mapActions from 'actions/MapActions';
import text from 'js/languages';
import esriRequest from 'esri/request';
import geojsonUtil from 'utils/arcgis-to-geojson';
import symbols from 'utils/symbols';
import Polygon from 'esri/geometry/Polygon';
import Graphic from 'esri/graphic';
import React, {Component, PropTypes} from 'react';

const initialState = {
  currentStep: 1,
  activeLanguage: 'English', //TODO: Get from context!
  email: '',
  aoiName: '',
  viirsAlerts: false,
  treeCoverAlerts: true,
  warnings: false
};

export default class SubscribeModal extends Component {

  static contextTypes = {
    language: PropTypes.string.isRequired,
    map: PropTypes.object.isRequired
  };

  constructor(props) {
    super(props);
    this.state = initialState;
  }

  updateEmail = evt => {
    this.setState({
      email: evt.target.value
    });
  }

  updateAreaName = evt => {
    this.setState({
      aoiName: evt.target.value
    });
  }

  optionMapper = (item) => {
    return <option key={item} value={item}>{item}</option>;
  };

  close = () => {
    mapActions.toggleSubscribeModal({ visible: false });
  };

  updateVIIRS = () => {
    this.setState({
      viirsAlerts: !this.state.viirsAlerts
    });
  }

  updateLoss = () => {
    this.setState({
      treeCoverAlerts: !this.state.treeCoverAlerts
    });
  }

  changeLanguage = evt => {
    this.setState({
      activeLanguage: evt.target.value
    });
  }

  next = () => {
    this.setState({
      currentStep: this.state.currentStep + 1
    });
  }

  back = () => {
    this.setState({
      currentStep: this.state.currentStep - 1
    });
  }

  refreshSubscriptions = () => {
    $.ajax({
      url: 'https://production-api.globalforestwatch.org/v1/subscriptions',
      dataType: 'json',
      xhrFields: {
        withCredentials: true
      },
      success: (response) => {
        console.log('resp', response);
        this.setState(initialState);
        mapActions.toggleSubscribeModal({ visible: false });
        mapActions.setUserSubscriptions(response.data);
        mapActions.toggleSubscriptionsModal({ visible: true });
      },
      error: (error) => {
        console.log('err', error);
        this.setState({
          userSubscriptions: []
        });
      }
    });
  }

  save = () => {
    const { email, aoiName, viirsAlerts, treeCoverAlerts } = this.state;
    const selectedFeature = this.context.map.infoWindow.getSelectedFeature();

    if (email && aoiName && selectedFeature && (viirsAlerts || treeCoverAlerts)) {
      const datasets = [];
      if (viirsAlerts) {
        datasets.push('viirs-active-fires');
      }
      if (treeCoverAlerts) {
        datasets.push('umd-loss-gain');
      }
      const jsonData = {
        datasets: datasets,
        language: this.state.activeLanguage === 'English' ? 'en' : 'sp', //TODO: Switch statement over all of our possibilities
        name: aoiName,
        params: {
          geostore: selectedFeature.attributes.geostoreId,
          iso: {
            country: null,
            region: null
          },
          use: null,
          useid: null,
          wdpaid: null
        },
        resource: {
          content: this.state.email,
          type: 'EMAIL'
        }
      };

      $.ajax({
        url: 'https://production-api.globalforestwatch.org/v1/subscriptions',
        dataType: 'json',
        method: 'POST',
        data: jsonData,
        xhrFields: {
          withCredentials: true
        },
        success: (response) => {
          console.log('response', response);
          this.setState({
            currentStep: 0,
            warnings: false,
            success: true
          });
        },
        error: (error) => {
          console.log('errr', error);
        }
      });
    } else {
      this.setState({
        warnings: true
      });
    }
  }

  render () {
    // const {language} = this.context;
    const langs = ['English', 'Spanish']; //TODO: Get from resources or config!

    return (
      <ControlledModalWrapper onClose={this.close}>
        <div className={`subscribe-step ${this.state.currentStep === 0 ? '' : 'hidden'}`}>

Subscription saved!

              This subscription has been added to your profile. Please
              check your email and click on the link to confirm your
              subscription. Visit your saved subscriptions to manage them.

        <div className={`subscribe-step ${this.state.currentStep === 1 ? '' : 'hidden'}`}>

Forest change alerts

Select the forest change alerts you would like to receive

            VIIRS active fire alerts<input className="dataset-checkbox" type="checkbox" checked={this.state.viirsAlerts} onChange={this.updateVIIRS} name="datasets" id="viirs-active-fires" />
            Tree cover loss data<input className="dataset-checkbox" type="checkbox" checked={this.state.treeCoverAlerts} onChange={this.updateLoss} name="datasets" id="umd-loss-gain" />

        <div className={`subscribe-step ${this.state.currentStep === 2 ? '' : 'hidden'}`}>

Subscribe to alerts

Enter your email below to receive an email notification when there are new annual tree cover loss data available for this area.

            <input className="alert-input" placeholder='Enter email' onChange={this.updateEmail} />

        <div className={`subscribe-step ${this.state.currentStep === 3 ? '' : 'hidden'}`}>

Name your subscription

Name

            <input className="subscription-name" placeholder='Area name' onChange={this.updateAreaName} />

Receive Alert Emails In...

            <select className='language-selector' onChange={this.changeLanguage} value={this.state.activeLanguage}>
              {langs.map(this.optionMapper)}
            </select>

          <div className={`subscribe-warnings ${this.state.warnings ? '' : 'hidden'}`}>You must have an alert subscription, valid email, and area name!

          {this.state.currentStep === 0 ? <button className='fa-button gold' onClick={this.refreshSubscriptions}>OK!</button> : null }
          {this.state.currentStep > 1 ? <button className='fa-button gold' onClick={this.back}>Back</button> : null }
          {this.state.currentStep === 1 || this.state.currentStep === 2 ? <button className='fa-button gold' onClick={this.next}>Next</button> : null }
          {this.state.currentStep === 3 ? <button className='fa-button gold' onClick={this.save}>Save</button> : null }

      </ControlledModalWrapper>
    );
  }

}
<|endoftext|>


<commit_before>var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.green;
var notice = chalk.yellow;
var whoops = chalk.bold.red; // Can't name error as exec uses error in callback.
var underline = chalk.underline;

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) == 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✔] Initialized new Git repository.'));
		}
	});
};

exports.clone = function(repository) {
	// Nothing to clone.
	if (!repository) {
		console.log(notice('[~] You must enter a repository URL.'));
	} else {
		exec('git clone ' + repository, function(error, stdout, stderr) {
			if (stderr.substring(0, 7) == 'Cloning') {
				if (stderr.split('\n')[1].split(' ')[0] == 'fatal:') {
					console.log(whoops('[✖] Could not clone repository.'));
				} else {
					console.log(success('[✔] Cloned into ' + stderr.split('\n')[0].split(' ')[2]));
				}
			} else {
				if (stderr.substring(0, 23) == 'fatal: destination path') {
					console.log(notice('[~] Directory ' + stderr.split(' ')[3] + ' is not empty.'));
				} else {
					console.log(whoops('[✖] Could not clone repository.'));
				}
			}
		});
	}
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✔] Added everything!'));
};

exports.addSingle = function(target) {
	//TODO: Fix the Error handling! Currently just ignores warnings
	exec('git add ' + target, function(error, stdout, stderr) {
		if (!stderr.substring(0, 7) === 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target == 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
}

exports.addOptions = function(options, target) {
	// TODO: Fix the Error Handling! Currently just ignores warnings
	exec('git add -' + options + ' ' + target, function(error, stdout, stderr) {
		if (!stderr.substring(0, 7) === 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target == 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
}

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		exports.addAll();

		exec('git commit -m "' + message + '"', function(error, stdout, stderr) {
			if (stdout.substring(0, 1) == '[') {
				console.log(success('[✔] Commited!'));

				console.log();
				console.log('"' + underline(message) + '"');
			} else if (stdout.substring(0, 2) == 'On') {
				console.log(notice('[~] Everything already committed.'));
			} else {
				console.log(whoops('[✖] Could not commit changes.') + chalk.red(' Try again if there was a large amount of changes to add.'));
			}
		});
	}
};

exports.push = function() {
	exec('git push', function(error, stdout, stderr) {
		if (stderr.substring(0, 10) == 'Everything') {
			console.log(notice('[~] All commits already pushed.'));
		} else if (stderr.substring(0, 2) == 'To') {
			console.log(success('[✔] Pushed!'));
		} else {
			// TODO: add handling for non-fast-forwards (when you need to pull first, merge, and then push).
			console.log(whoops('[✖] Could not push commits.') + chalk.red(' (may have to pull first, merge any conflicts, and then attempt to push again using the ') + chalk.red.underline('standard git command') + chalk.red('.)'));
		}
	});
};

exports.pull = function() {
	exec('git pull', function(error, stdout, stderr) {
		if (stdout.substring(0, 7) == 'Already') {
			console.log(notice('[~] Everything is already up-to-date.'));
		} else if (stdout.substring(0, 8) == 'Updating') {
			console.log(success('[✔] Pulled!'));
		} else {
			// TODO: add handling for merge conflicts.
			console.log(whoops('[✖] Could not pull commits.') + chalk.red(' (may have to pull using the ') + chalk.red.underline('standard git command') + chalk.red(' to handle merge conflicts.)'));
		}
	});
};

exports.fetch = function() {
	exec('git fetch', function(error, stdout, stderr) {
		if (stdout === '' && stderr === '') {
			console.log(success('[✔] Fetched!'));
		} else {
			console.log(whoops('[✖] Could not fetch commits.'));
		}
	});
};

exports.status = function() {
	exec('git status', function(error, stdout, stderr) {
		var status = stdout.split('\n');

		// Branch.
		console.log(chalk.dim('branch  ') + chalk.gray.dim(' | ') + success(status[0].split(' ')[2]));

		// Position in branch.
		var position;
		switch (status[1].split(' ')[3]) {
			case 'behind':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits behind (fetch or pull)');
				break;

			case 'working': // Quick hack to get it working with freshly initialized git repositories.
			case 'up-to-date':
				position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				break;

			case 'ahead':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits ahead (push commits)');
				break;

			default:
				// TODO: add proper handling for freshly initialized git repositories.
				if (typeof status[1].split(' ')[3] == 'undefined') { // Quick hack to get it working with freshly initialized git repositories.
					position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				} else {
					position = 'position' + chalk.gray.dim(' | ') + whoops('diverged');
				}
		}
		console.log(position);

		console.log();

		// Staging and commits.
		var staging;
		if (status[3] == 'Changes not staged for commit:') {
			staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
		} else {
			if (status[4].split(' ')[0] == 'Untracked') {
				staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
			} else {
				staging = chalk.dim('staging ') + chalk.gray.dim(' | ') + success('all changes staged');
			}
		}

		console.log(staging);

		var commits;
		if (status[3] == 'Changes to be committed:') {
			commits = 'commits ' + chalk.gray.dim(' | ') + notice('not all changes committed (commit all changes)');
		} else {
			commits = chalk.dim('commits ') + chalk.gray.dim(' | ') + success('all changes committed');
		}

		console.log(commits);
	});
};

// https://gist.github.com/textarcana/1306223
exports.log = function() {
	exec('git log --pretty=format:\'{%n  "commit": "%H",%n  "author": "%an <%ae>",%n  "date": "%ad",%n  "message": "%f"%n},\' $@ | perl -pe \'BEGIN{print "["}; END{print "]\n"}\' | perl -pe \'s/},]/}]/\'', function(error, stdout, stderr) {
		var log = JSON.parse(stdout);
		log.reverse(); // Show newest at the bottom.

		for (var i = 0; i < log.length; i++) {
			console.log(); // New line between each commit.

			console.log(chalk.yellow('[' + log[i].commit + ']'));

			var author = {
				name: log[i].author.split('<')[0].trim(),
				email: '<' + log[i].author.split('<')[1]
			};

			console.log('|- ' + chalk.gray(author.name) + " " + chalk.gray.dim(author.email));
			console.log('|- ' + chalk.gray.dim(log[i].date));
			console.log('|- ' + chalk.green(log[i].message.split('-').join(' ')));
		}
	});
};
<commit_msg>Conform with coding standards.<commit_after>var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.green;
var notice = chalk.yellow;
var whoops = chalk.bold.red; // Can't name error as exec uses error in callback.
var underline = chalk.underline;

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) === 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✔] Initialized new Git repository.'));
		}
	});
};

exports.clone = function(repository) {
	// Nothing to clone.
	if (!repository) {
		console.log(notice('[~] You must enter a repository URL.'));
	} else {
		exec('git clone ' + repository, function(error, stdout, stderr) {
			if (stderr.substring(0, 7) === 'Cloning') {
				if (stderr.split('\n')[1].split(' ')[0] === 'fatal:') {
					console.log(whoops('[✖] Could not clone repository.'));
				} else {
					console.log(success('[✔] Cloned into ' + stderr.split('\n')[0].split(' ')[2]));
				}
			} else {
				if (stderr.substring(0, 23) === 'fatal: destination path') {
					console.log(notice('[~] Directory ' + stderr.split(' ')[3] + ' is not empty.'));
				} else {
					console.log(whoops('[✖] Could not clone repository.'));
				}
			}
		});
	}
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✔] Added everything!'));
};

exports.addSingle = function(target) {
	//TODO: Fix the Error handling! Currently just ignores warnings
	exec('git add ' + target, function(error, stdout, stderr) {
		if (!stderr.substring(0, 7) === 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target === 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
}

exports.addOptions = function(options, target) {
	// TODO: Fix the Error Handling! Currently just ignores warnings
	exec('git add -' + options + ' ' + target, function(error, stdout, stderr) {
		if (!stderr.substring(0, 7) === 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target === 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
}

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		exports.addAll();

		exec('git commit -m "' + message + '"', function(error, stdout, stderr) {
			if (stdout.substring(0, 1) === '[') {
				console.log(success('[✔] Commited!'));

				console.log();
				console.log('"' + underline(message) + '"');
			} else if (stdout.substring(0, 2) === 'On') {
				console.log(notice('[~] Everything already committed.'));
			} else {
				console.log(whoops('[✖] Could not commit changes.') + chalk.red(' Try again if there was a large amount of changes to add.'));
			}
		});
	}
};

exports.push = function() {
	exec('git push', function(error, stdout, stderr) {
		if (stderr.substring(0, 10) === 'Everything') {
			console.log(notice('[~] All commits already pushed.'));
		} else if (stderr.substring(0, 2) === 'To') {
			console.log(success('[✔] Pushed!'));
		} else {
			// TODO: add handling for non-fast-forwards (when you need to pull first, merge, and then push).
			console.log(whoops('[✖] Could not push commits.') + chalk.red(' (may have to pull first, merge any conflicts, and then attempt to push again using the ') + chalk.red.underline('standard git command') + chalk.red('.)'));
		}
	});
};

exports.pull = function() {
	exec('git pull', function(error, stdout, stderr) {
		if (stdout.substring(0, 7) === 'Already') {
			console.log(notice('[~] Everything is already up-to-date.'));
		} else if (stdout.substring(0, 8) === 'Updating') {
			console.log(success('[✔] Pulled!'));
		} else {
			// TODO: add handling for merge conflicts.
			console.log(whoops('[✖] Could not pull commits.') + chalk.red(' (may have to pull using the ') + chalk.red.underline('standard git command') + chalk.red(' to handle merge conflicts.)'));
		}
	});
};

exports.fetch = function() {
	exec('git fetch', function(error, stdout, stderr) {
		if (stdout === '' && stderr === '') {
			console.log(success('[✔] Fetched!'));
		} else {
			console.log(whoops('[✖] Could not fetch commits.'));
		}
	});
};

exports.status = function() {
	exec('git status', function(error, stdout, stderr) {
		var status = stdout.split('\n');

		// Branch.
		console.log(chalk.dim('branch  ') + chalk.gray.dim(' | ') + success(status[0].split(' ')[2]));

		// Position in branch.
		var position;
		switch (status[1].split(' ')[3]) {
			case 'behind':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits behind (fetch or pull)');
				break;

			case 'working': // Quick hack to get it working with freshly initialized git repositories.
			case 'up-to-date':
				position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				break;

			case 'ahead':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits ahead (push commits)');
				break;

			default:
				// TODO: add proper handling for freshly initialized git repositories.
				if (typeof status[1].split(' ')[3] === 'undefined') { // Quick hack to get it working with freshly initialized git repositories.
					position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				} else {
					position = 'position' + chalk.gray.dim(' | ') + whoops('diverged');
				}
		}
		console.log(position);

		console.log();

		// Staging and commits.
		var staging;
		if (status[3] === 'Changes not staged for commit:') {
			staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
		} else {
			if (status[4].split(' ')[0] === 'Untracked') {
				staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
			} else {
				staging = chalk.dim('staging ') + chalk.gray.dim(' | ') + success('all changes staged');
			}
		}

		console.log(staging);

		var commits;
		if (status[3] === 'Changes to be committed:') {
			commits = 'commits ' + chalk.gray.dim(' | ') + notice('not all changes committed (commit all changes)');
		} else {
			commits = chalk.dim('commits ') + chalk.gray.dim(' | ') + success('all changes committed');
		}

		console.log(commits);
	});
};

// https://gist.github.com/textarcana/1306223
exports.log = function() {
	exec('git log --pretty=format:\'{%n  "commit": "%H",%n  "author": "%an <%ae>",%n  "date": "%ad",%n  "message": "%f"%n},\' $@ | perl -pe \'BEGIN{print "["}; END{print "]\n"}\' | perl -pe \'s/},]/}]/\'', function(error, stdout, stderr) {
		var log = JSON.parse(stdout);
		log.reverse(); // Show newest at the bottom.

		for (var i = 0; i < log.length; i++) {
			console.log(); // New line between each commit.

			console.log(chalk.yellow('[' + log[i].commit + ']'));

			var author = {
				name: log[i].author.split('<')[0].trim(),
				email: '<' + log[i].author.split('<')[1]
			};

			console.log('|- ' + chalk.gray(author.name) + " " + chalk.gray.dim(author.email));
			console.log('|- ' + chalk.gray.dim(log[i].date));
			console.log('|- ' + chalk.green(log[i].message.split('-').join(' ')));
		}
	});
};
<|endoftext|>


<commit_before>import React from 'react';

import TimeAgo from './TimeAgo';
import DescriptionList from './DescriptionList';
import Service from '../structs/Service';
import TaskStatsTable from './TaskStatsTable';

class ServiceDetailDebugTab extends React.Component {
  getValueText(value) {
    if (value == null || value === '') {
      return (

Unspecified

      );
    }

    return (
      {value}
    );
  }

  getLastTaskFailureInfo() {
    let lastTaskFailure = this.props.service.getLastTaskFailure();
    if (lastTaskFailure == null) {
      return (

This app does not have failed tasks

      );
    }

    const {version, timestamp, taskId, state, message, host} = lastTaskFailure;
    let taskFailureValueMapping = {
      'Task ID': this.getValueText(taskId),
      'State': this.getValueText(state),
      'Message': this.getValueText(message),
      'Host': this.getValueText(host),
      'Timestamp': {timestamp} (<TimeAgo time={timestamp} />),
      'Version': {version} (<TimeAgo time={version} />)
    };

    return <DescriptionList hash={taskFailureValueMapping} />;
  }

  getLastVersionChange() {
    let versionInfo = this.props.service.getVersionInfo();
    if (versionInfo == null) {
      return (

This app does not have version change information

      );
    }

    const {lastScalingAt, lastConfigChangeAt} = versionInfo;
    let lastScaling = 'No operation since last config change';
    if (lastScalingAt !== lastConfigChangeAt) {
      lastScaling = (

          {lastScalingAt} (<TimeAgo time={lastScalingAt} />)

      );
    }

    let LastVersionChangeValueMapping = {
      'Scale or Restart': lastScaling,
      'Configuration': (

          {lastConfigChangeAt} (<TimeAgo time={lastConfigChangeAt} />)

      )
    };

    return <DescriptionList hash={LastVersionChangeValueMapping} />;
  }

  getTaskStats() {
    let taskStats = this.props.service.getTaskStats();

    if (taskStats.getList().getItems().length === 0) {
      return (

This app does not have task statistics

      );
    }

    return <TaskStatsTable taskStats={taskStats} />;
  }

  render() {
    return (

          Last Changes

        {this.getLastVersionChange()}

          Last Task Failure

        {this.getLastTaskFailureInfo()}

          Task Statistics

        {this.getTaskStats()}

    );
  }
}

ServiceDetailDebugTab.contextTypes = {
  router: React.PropTypes.func
};

ServiceDetailDebugTab.propTypes = {
  service: React.PropTypes.instanceOf(Service)
};

module.exports = ServiceDetailDebugTab;
<commit_msg>Use dates not strings in TimeAgo<commit_after>import React from 'react';

import TimeAgo from './TimeAgo';
import DescriptionList from './DescriptionList';
import Service from '../structs/Service';
import TaskStatsTable from './TaskStatsTable';

class ServiceDetailDebugTab extends React.Component {
  getValueText(value) {
    if (value == null || value === '') {
      return (

Unspecified

      );
    }

    return (
      {value}
    );
  }

  getLastTaskFailureInfo() {
    let lastTaskFailure = this.props.service.getLastTaskFailure();
    if (lastTaskFailure == null) {
      return (

This app does not have failed tasks

      );
    }

    const {version, timestamp, taskId, state, message, host} = lastTaskFailure;
    let taskFailureValueMapping = {
      'Task ID': this.getValueText(taskId),
      'State': this.getValueText(state),
      'Message': this.getValueText(message),
      'Host': this.getValueText(host),
      'Timestamp':
        {timestamp} (<TimeAgo time={new Date(timestamp)} />)
      ,
      'Version': {version} (<TimeAgo time={new Date(version)} />)
    };

    return <DescriptionList hash={taskFailureValueMapping} />;
  }

  getLastVersionChange() {
    let versionInfo = this.props.service.getVersionInfo();
    if (versionInfo == null) {
      return (

This app does not have version change information

      );
    }

    const {lastScalingAt, lastConfigChangeAt} = versionInfo;
    let lastScaling = 'No operation since last config change';
    if (lastScalingAt !== lastConfigChangeAt) {
      lastScaling = (

          {lastScalingAt} (<TimeAgo time={new Date(lastScalingAt)} />)

      );
    }

    let LastVersionChangeValueMapping = {
      'Scale or Restart': lastScaling,
      'Configuration': (

          {lastConfigChangeAt} (<TimeAgo time={new Date(lastConfigChangeAt)} />)

      )
    };

    return <DescriptionList hash={LastVersionChangeValueMapping} />;
  }

  getTaskStats() {
    let taskStats = this.props.service.getTaskStats();

    if (taskStats.getList().getItems().length === 0) {
      return (

This app does not have task statistics

      );
    }

    return <TaskStatsTable taskStats={taskStats} />;
  }

  render() {
    return (

          Last Changes

        {this.getLastVersionChange()}

          Last Task Failure

        {this.getLastTaskFailureInfo()}

          Task Statistics

        {this.getTaskStats()}

    );
  }
}

ServiceDetailDebugTab.contextTypes = {
  router: React.PropTypes.func
};

ServiceDetailDebugTab.propTypes = {
  service: React.PropTypes.instanceOf(Service)
};

module.exports = ServiceDetailDebugTab;
<|endoftext|>


<commit_before>
/**
 * socket.io
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

(function (exports) {

  /**
   * IO namespace.
   *
   * @namespace
   */

  var io = exports;

  /**
   * Socket.IO version
   *
   * @api public
   */

  io.version = '0.8.5';

  /**
   * Protocol implemented.
   *
   * @api public
   */

  io.protocol = 1;

  /**
   * Available transports, these will be populated with the available transports
   *
   * @api public
   */

  io.transports = [];

  /**
   * Keep track of jsonp callbacks.
   *
   * @api private
   */

  io.j = [];

  /**
   * Keep track of our io.Sockets
   *
   * @api private
   */
  io.sockets = {};

  // if node

  /**
   * Expose constructors if in Node
   */

  if ('object' === typeof module && 'function' === typeof require) {

    /**
     * Expose utils
     *
     * @api private
     */

    io.util = require('./util').util;

    /**
     * Expose JSON.
     *
     * @api private
     */

    io.JSON = require('./json').JSON;

    /**
     * Expose parser.
     *
     * @api private
     */

    io.parser = require('./parser').parser;

    /**
     * Expose EventEmitter
     *
     * @api private
     */

    io.EventEmitter = require('./events').EventEmitter;

    /**
     * Expose SocketNamespace
     *
     * @api private
     */

     io.SocketNamespace = require('./namespace').SocketNamespace;

    /**
     * Expose Transport
     *
     * @api public
     */

    io.Transport = require('./transport').Transport;

    /**
     * Default enabled transports
     *
     * @api public
     */

    io.transports = ['websocket', 'xhr-polling'];

    /**
     * Expose all transports
     *
     * @api public
     */

    io.Transport.XHR = require('./transports/xhr').XHR;

    io.transports.forEach(function (t) {
      io.Transport[t] = require('./transports/' + t)[t];
    });

    /**
     * Expose Socket
     *
     * @api public
     */

    io.Socket = require('./socket').Socket;

    /**
     * Location of `dist/` directory.
     *
     * @api private
     */

    io.dist = __dirname + '/../dist';

    /**
     * Expose our build system which can generate
     * socket.io files on the fly with different transports
     *
     * @api private
     */

    io.builder = require('../bin/builder');

  }
  // end node

  /**
   * Manages connections to hosts.
   *
   * @param {String} uri
   * @Param {Boolean} force creation of new socket (defaults to false)
   * @api public
   */

  io.connect = function (host, details) {
    var uri = io.util.parseUri(host)
      , uuri
      , socket;

    if ('undefined' != typeof document) {
      uri.protocol = uri.protocol || document.location.protocol.slice(0, -1);
      uri.host = uri.host || document.domain;
      uri.port = uri.port || document.location.port;
    }

    uuri = io.util.uniqueUri(uri);

    var options = {
        host: uri.host
      , secure: 'https' == uri.protocol
      , port: uri.port || ('https' == uri.protocol ? 443 : 80)
      , query: uri.query || ''
    };

    io.util.merge(options, details);

    if (options['force new connection'] || !io.sockets[uuri]) {
      socket = new io.Socket(options);
    }

    if (!options['force new connection'] && socket) {
      io.sockets[uuri] = socket;
    }

    socket = socket || io.sockets[uuri];

    // if path is different from '' or /
    return socket.of(uri.path.length > 1 ? uri.path : '');
  };

})('object' === typeof module ? module.exports : (window.io = {}));
<commit_msg>Fixed; look up location in `global` object.<commit_after>
/**
 * socket.io
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

(function (exports, global) {

  /**
   * IO namespace.
   *
   * @namespace
   */

  var io = exports;

  /**
   * Socket.IO version
   *
   * @api public
   */

  io.version = '0.8.5';

  /**
   * Protocol implemented.
   *
   * @api public
   */

  io.protocol = 1;

  /**
   * Available transports, these will be populated with the available transports
   *
   * @api public
   */

  io.transports = [];

  /**
   * Keep track of jsonp callbacks.
   *
   * @api private
   */

  io.j = [];

  /**
   * Keep track of our io.Sockets
   *
   * @api private
   */
  io.sockets = {};

  // if node

  /**
   * Expose constructors if in Node
   */

  if ('object' === typeof module && 'function' === typeof require) {

    /**
     * Expose utils
     *
     * @api private
     */

    io.util = require('./util').util;

    /**
     * Expose JSON.
     *
     * @api private
     */

    io.JSON = require('./json').JSON;

    /**
     * Expose parser.
     *
     * @api private
     */

    io.parser = require('./parser').parser;

    /**
     * Expose EventEmitter
     *
     * @api private
     */

    io.EventEmitter = require('./events').EventEmitter;

    /**
     * Expose SocketNamespace
     *
     * @api private
     */

     io.SocketNamespace = require('./namespace').SocketNamespace;

    /**
     * Expose Transport
     *
     * @api public
     */

    io.Transport = require('./transport').Transport;

    /**
     * Default enabled transports
     *
     * @api public
     */

    io.transports = ['websocket', 'xhr-polling'];

    /**
     * Expose all transports
     *
     * @api public
     */

    io.Transport.XHR = require('./transports/xhr').XHR;

    io.transports.forEach(function (t) {
      io.Transport[t] = require('./transports/' + t)[t];
    });

    /**
     * Expose Socket
     *
     * @api public
     */

    io.Socket = require('./socket').Socket;

    /**
     * Location of `dist/` directory.
     *
     * @api private
     */

    io.dist = __dirname + '/../dist';

    /**
     * Expose our build system which can generate
     * socket.io files on the fly with different transports
     *
     * @api private
     */

    io.builder = require('../bin/builder');

  }
  // end node

  /**
   * Manages connections to hosts.
   *
   * @param {String} uri
   * @Param {Boolean} force creation of new socket (defaults to false)
   * @api public
   */

  io.connect = function (host, details) {
    var uri = io.util.parseUri(host)
      , uuri
      , socket;

    if (global && global.location) {
      uri.protocol = uri.protocol || global.location.protocol.slice(0, -1);
      uri.host = uri.host || global.domain;
      uri.port = uri.port || global.location.port;
    }

    uuri = io.util.uniqueUri(uri);

    var options = {
        host: uri.host
      , secure: 'https' == uri.protocol
      , port: uri.port || ('https' == uri.protocol ? 443 : 80)
      , query: uri.query || ''
    };

    io.util.merge(options, details);

    if (options['force new connection'] || !io.sockets[uuri]) {
      socket = new io.Socket(options);
    }

    if (!options['force new connection'] && socket) {
      io.sockets[uuri] = socket;
    }

    socket = socket || io.sockets[uuri];

    // if path is different from '' or /
    return socket.of(uri.path.length > 1 ? uri.path : '');
  };

})('object' === typeof module ? module.exports : (this.io = {}), this);
<|endoftext|>


<commit_before>global.isArray = Array.isArray;
global.isBuffer = !! global.Buffer ? Buffer.isBuffer : () => false;
const toString = Object.prototype.toString;

require('./Is/functions');

if (! isFunction(global.isObject)) {
    global.isObject = function (arg) {
        return !! arg && 'object' === typeof arg;
    };
}

for (const name of [ 'Arguments', 'Boolean', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet' ]) {
    if (isFunction(global['is' + name])) {
        continue;
    }

    global['is' + name] = function (obj) {
        return toString.call(obj) === '[object ' + name + ']';
    };
}

const primitives = [ Number, String, Boolean ];

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isNumeric = function isNumeric(value) {
    if (! isScalar(value)) {
        return false;
    }

    if (isNumber(value)) {
        return true;
    }

    return !! String(value).match(/^((\d+|\.\d+|\d+\.\d+)(e[+-]?\d+)?|0x[0-9a-f_]+)$/i);
};

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isScalar = function isScalar(value) {
    if (undefined === value || null === value) {
        return false;
    }

    const proto = Object.getPrototypeOf(value);
    for (const type of primitives) {
        if (proto === type.prototype) {
            return true;
        }
    }

    return false;
};

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isObjectLiteral = function isObjectLiteral(value) {
    if (null === value || undefined === value) {
        return false;
    }

    return Object.getPrototypeOf(value) === Object.getPrototypeOf({});
};

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isPromise = function isPromise(value) {
    return isFunction(value.then);
};

/**
 * @param {*} stream
 *
 * @returns {boolean}
 */
global.isStream = function isStream(stream) {
    return 'object' === typeof stream && isFunction(stream.pipe);
};
<commit_msg>[Contracts] add http server contracts and move events on contracts<commit_after>global.isArray = Array.isArray;
global.isBuffer = !! global.Buffer ? Buffer.isBuffer : () => false;
const toString = Object.prototype.toString;

require('./Is/functions');

if (! isFunction(global.isObject)) {
    global.isObject = function (arg) {
        return !! arg && 'object' === typeof arg;
    };
}

for (const name of [ 'Arguments', 'Boolean', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet' ]) {
    if (isFunction(global['is' + name])) {
        continue;
    }

    global['is' + name] = function (obj) {
        return toString.call(obj) === '[object ' + name + ']';
    };
}

const primitives = [ Number, String, Boolean ];

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isNumeric = function isNumeric(value) {
    if (! isScalar(value)) {
        return false;
    }

    if (isNumber(value)) {
        return true;
    }

    return !! String(value).match(/^((\d+|\.\d+|\d+\.\d+)(e[+-]?\d+)?|0x[0-9a-f_]+)$/i);
};

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isScalar = function isScalar(value) {
    if (undefined === value || null === value) {
        return false;
    }

    const proto = Object.getPrototypeOf(value);
    for (const type of primitives) {
        if (proto === type.prototype) {
            return true;
        }
    }

    return false;
};

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isObjectLiteral = function isObjectLiteral(value) {
    if (null === value || undefined === value) {
        return false;
    }

    return Object.getPrototypeOf(value) === Object.getPrototypeOf({});
};

/**
 * @param {*} value
 *
 * @returns {boolean}
 */
global.isPromise = function isPromise(value) {
    return 'object' === typeof value && isFunction(value.then);
};

/**
 * @param {*} stream
 *
 * @returns {boolean}
 */
global.isStream = function isStream(stream) {
    return 'object' === typeof stream && isFunction(stream.pipe);
};
<|endoftext|>


<commit_before>var typeOf = require('./of');
var typify = require('./typify');
var isBuffer = require('./is.buffer');
var isArrayLike = require('./is.array-like');

function is(expected, value) {
	return new RegExp('(' + typify(expected, true) + ')').test(typeOf(value));
}

is.not = function isnt(expected, value) {
	return !is(expected, value);
};

is.not.buffer = function isntBuffer(value) {
	return !isBuffer(value);
};

is.not.arrayLike = function isntArrayLike(value) {
	return !isArrayLike(value);
};

is.int = function isInt(value) {
	return parseFloat(value, 10) === parseInt(value, 10);
};

is.not.int = function isntInt(value) {
	return !is.int(value);
};

is.uint = function isUint(value) {
	return is.int(value) && value >= 0;
};

is.not.uint = function isntUint(value) {
	return !is.uint(value);
};

is.buffer = isBuffer;
is.arrayLike = isArrayLike;
is.a = is.an = is;
is.not.a = is.not.an = is.not;
module.exports = is;
<commit_msg>chore(is): add numeric method<commit_after>var typeOf = require('./of');
var typify = require('./typify');
var isBuffer = require('./is.buffer');
var isArrayLike = require('./is.array-like');

function is(expected, value) {
	return new RegExp('(' + typify(expected, true) + ')').test(typeOf(value));
}

is.not = function isnt(expected, value) {
	return !is(expected, value);
};

is.not.buffer = function isntBuffer(value) {
	return !isBuffer(value);
};

is.not.arrayLike = function isntArrayLike(value) {
	return !isArrayLike(value);
};

is.numeric = function isNumeric(value) {
	return !isNaN(parseFloat(value)) && isFinite(value);
};

is.not.numeric = function isntNumeric(value) {
	return !is.numeric(value);
};

is.int = function isInt(value) {
	return parseFloat(value, 10) === parseInt(value, 10);
};

is.not.int = function isntInt(value) {
	return !is.int(value);
};

is.uint = function isUint(value) {
	return is.int(value) && value >= 0;
};

is.not.uint = function isntUint(value) {
	return !is.uint(value);
};

is.buffer = isBuffer;
is.arrayLike = isArrayLike;
is.a = is.an = is;
is.not.a = is.not.an = is.not;
module.exports = is;
<|endoftext|>


<commit_before>String.prototype.lpad = function(char, count) {
    var ch = char || "0";
    var cnt = count || 2;
    var s = this;
    while (s.length < cnt) { s = ch+s; }
    return s;
}

String.prototype.rpad = function(char, count) {
    var ch = char || "0";
    var cnt = count || 2;
    var s = this;
    while (s.length < cnt) { s += ch; }
    return s;
}

String.prototype.trim = function() {
    return this.match(/^\s*(.*?)\s*$/)[1];
}

Date.prototype._dayNames = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
Date.prototype._dayNamesShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
Date.prototype._monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
Date.prototype._monthNamesShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

Date.prototype.format = function(str) {
	var suffixes = {
		1:"st",
		2:"nd",
		3:"rd",
		21:"st",
		22:"nd",
		23:"rd",
		31:"st"
	};
    var result = "";
    for (var i=0;i<str.length;i++) {
		var ch = str.charAt(i);
		switch (ch) {
			case "d": result += this.getDate().toString().lpad(); break;
			case "j": result += this.getDate(); break;
			case "w": result += this.getDay(); break;
			case "N": result += this.getDay() || 7; break;
			case "S":
				var d = this.getDate();
				return suffixes[d] || "th";
			break;
			case "D": result += this._dayNamesShort[(this.getDay() || 7)-1]; break;
			case "l": result += this._dayNames[(this.getDay() || 7)-1]; break;
			case "z":
				var t = this.getTime();
				var d = new Date(t);
				d.setDate(1);
				d.setMonth(0);
				var diff = t - d.getTime();
				result += diff / (1000 * 60 * 60 * 24);
			break;

			case "W":
				var d = new Date(this.getFullYear(), this.getMonth(), this.getDate());
				var day = d.getDay() || 7;
				d.setDate(d.getDate() + (4-day));
				var year = d.getFullYear();
				var day = Math.floor((d.getTime() - new Date(year, 0, 1, -6)) / (1000 * 60 * 60 * 24));
				result += (1 + Math.floor(day / 7)).toString().lpad();
			break;

			case "m": result += (this.getMonth()+1).toString().lpad(); break;
			case "n": result += (this.getMonth()+1); break;
			case "M": result += this._monthNamesShort[this.getMonth()]; break;
			case "F": result += this._monthNames[this.getMonth()]; break;
			case "t":
				var t = this.getTime();
				var m = this.getMonth();
				var d = new Date(t);
				var day = 0;
				do {
					day = d.getDate();
					t += 1000 * 60 * 60 * 24;
					d = new Date(t);
				} while (m == d.getMonth());
				result += day;
			break;

			case "L":
				var d = new Date(this.getTime());
				d.setDate(1);
				d.setMonth(1);
				d.setDate(29);
				result += (d.getMonth() == 1 ? "1" : "0");
			break;
			case "Y": result += this.getFullYear().toString().lpad(); break;
			case "y": result += this.getFullYear().toString().lpad().substring(2); break;

			case "a": result += (this.getHours() < 12 ? "am" : "pm"); break;
			case "A": result += (this.getHours() < 12 ? "AM" : "PM"); break;
			case "G": result += this.getHours(); break;
			case "H": result += this.getHours().toString().lpad(); break;
			case "g": result += (this.getHours() % 12)+1; break;
			case "h": result += ((this.getHours() % 12)+1).toString().lpad(); break;
			case "i": result += this.getMinutes().toString().lpad(); break;
			case "s": result += this.getSeconds().toString().lpad(); break;

			case "Z": result += -60*this.getTimezoneOffset(); break;

			case "O":
			case "P":
				var base = this.getTimezoneOffset()/-60;
				var o = Math.abs(base).toString().lpad();
				if (ch == "P") { o += ":"; }
				o += "00";
				result += (base >= 0 ? "+" : "-")+o;
			break;

			case "U": result += this.getTime()/1000; break;
			case "u": result += "0"; break;
			case "c": result += arguments.callee.call(this, "Y-m-d")+"T"+arguments.callee.call(this, "H:i:sP"); break;
			case "r": result += arguments.callee.call(this, "D, j M Y H:i:s O"); break;

			default: result += ch; break;
		}
    }
    return result;
}
<commit_msg>lpad/rpad fix<commit_after>String.prototype.lpad = function(char, count) {
	var ch = char || "0";
	var cnt = count || 2;

	var s = "";
	while (s.length < (count - this.length)) { s += char; }
	s = s.substring(0, count-this.length);
	return s+this;
}

String.prototype.rpad = function(char, count) {
	var ch = char || "0";
	var cnt = count || 2;

	var s = "";
	while (s.length < (count - this.length)) { s += char; }
	s = s.substring(0, count-this.length);
	return this+s;
}

String.prototype.trim = function() {
	return this.match(/^\s*(.*?)\s*$/)[1];
}

Date.prototype._dayNames = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
Date.prototype._dayNamesShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
Date.prototype._monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
Date.prototype._monthNamesShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

Date.prototype.format = function(str) {
	var suffixes = {
		1:"st",
		2:"nd",
		3:"rd",
		21:"st",
		22:"nd",
		23:"rd",
		31:"st"
	};
	var result = "";
	for (var i=0;i<str.length;i++) {
		var ch = str.charAt(i);
		switch (ch) {
			case "d": result += this.getDate().toString().lpad(); break;
			case "j": result += this.getDate(); break;
			case "w": result += this.getDay(); break;
			case "N": result += this.getDay() || 7; break;
			case "S":
				var d = this.getDate();
				return suffixes[d] || "th";
			break;
			case "D": result += this._dayNamesShort[(this.getDay() || 7)-1]; break;
			case "l": result += this._dayNames[(this.getDay() || 7)-1]; break;
			case "z":
				var t = this.getTime();
				var d = new Date(t);
				d.setDate(1);
				d.setMonth(0);
				var diff = t - d.getTime();
				result += diff / (1000 * 60 * 60 * 24);
			break;

			case "W":
				var d = new Date(this.getFullYear(), this.getMonth(), this.getDate());
				var day = d.getDay() || 7;
				d.setDate(d.getDate() + (4-day));
				var year = d.getFullYear();
				var day = Math.floor((d.getTime() - new Date(year, 0, 1, -6)) / (1000 * 60 * 60 * 24));
				result += (1 + Math.floor(day / 7)).toString().lpad();
			break;

			case "m": result += (this.getMonth()+1).toString().lpad(); break;
			case "n": result += (this.getMonth()+1); break;
			case "M": result += this._monthNamesShort[this.getMonth()]; break;
			case "F": result += this._monthNames[this.getMonth()]; break;
			case "t":
				var t = this.getTime();
				var m = this.getMonth();
				var d = new Date(t);
				var day = 0;
				do {
					day = d.getDate();
					t += 1000 * 60 * 60 * 24;
					d = new Date(t);
				} while (m == d.getMonth());
				result += day;
			break;

			case "L":
				var d = new Date(this.getTime());
				d.setDate(1);
				d.setMonth(1);
				d.setDate(29);
				result += (d.getMonth() == 1 ? "1" : "0");
			break;
			case "Y": result += this.getFullYear().toString().lpad(); break;
			case "y": result += this.getFullYear().toString().lpad().substring(2); break;

			case "a": result += (this.getHours() < 12 ? "am" : "pm"); break;
			case "A": result += (this.getHours() < 12 ? "AM" : "PM"); break;
			case "G": result += this.getHours(); break;
			case "H": result += this.getHours().toString().lpad(); break;
			case "g": result += (this.getHours() % 12)+1; break;
			case "h": result += ((this.getHours() % 12)+1).toString().lpad(); break;
			case "i": result += this.getMinutes().toString().lpad(); break;
			case "s": result += this.getSeconds().toString().lpad(); break;

			case "Z": result += -60*this.getTimezoneOffset(); break;

			case "O":
			case "P":
				var base = this.getTimezoneOffset()/-60;
				var o = Math.abs(base).toString().lpad();
				if (ch == "P") { o += ":"; }
				o += "00";
				result += (base >= 0 ? "+" : "-")+o;
			break;

			case "U": result += this.getTime()/1000; break;
			case "u": result += "0"; break;
			case "c": result += arguments.callee.call(this, "Y-m-d")+"T"+arguments.callee.call(this, "H:i:sP"); break;
			case "r": result += arguments.callee.call(this, "D, j M Y H:i:s O"); break;

			default: result += ch; break;
		}
	}
	return result;
}
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var debug = require('debug')('wp-connect:me');

/**
 * Create a Me instance
 *
 * @param {Me} wpconn
 * @api public
 */

function Me(wpconn){
  if (!(this instanceof Me)) return new Me(wpconn);
  this.wpconn = wpconn;
}

/**
 * Require user information
 *
 * @param {Object} params(optional)
 * @param {Function} fn
 * @api public
 */

Me.prototype.info = function(params, fn){
  this.wpconn.req.get('me.get', null, params, fn);
};

/**
 * User likes
 *
 * @param {Object} params(optional)
 * @param {Function} fn
 * @api public
 */

Me.prototype.likes = function(params, fn){
  this.wpconn.req.get('me.likes', null, params, fn);
};

/**
 * Expose `Me` module
 */

module.exports = Me;
<commit_msg>me: add `user groups` method<commit_after>
/**
 * Module dependencies.
 */

var debug = require('debug')('wp-connect:me');

/**
 * Create a Me instance
 *
 * @param {Me} wpconn
 * @api public
 */

function Me(wpconn){
  if (!(this instanceof Me)) return new Me(wpconn);
  this.wpconn = wpconn;
}

/**
 * Require user information
 *
 * @param {Object} params (optional)
 * @param {Function} fn
 * @api public
 */

Me.prototype.info = function(params, fn){
  this.wpconn.req.get('me.get', null, params, fn);
};

/**
 * User likes
 *
 * @param {Object} params (optional)
 * @param {Function} fn
 * @api public
 */

Me.prototype.likes = function(params, fn){
  this.wpconn.req.get('me.likes', null, params, fn);
};

/**
 * User groups
 * A list of the current user's group
 *
 * @param {Object} params (optional)
 * @param {Function} fn
 * @api public
 */

Me.prototype.groups = function(params, fn){
  this.wpconn.req.get('me.groups', null, params, fn);
};

/**
 * Expose `Me` module
 */

module.exports = Me;
<|endoftext|>