<commit_before>require('array.prototype.find');
var q = require('q');
var util = require('util');

var yaml = require("js-yaml");
var url = require("url");

var Kirra = require("./kirra-client.js");
var ebuiUtil = require("./util.js");

var assert = ebuiUtil.assert;
var merge = ebuiUtil.merge;

var MessageProcessor = function (emailGateway, messageStore, kirraBaseUrl, kirraApiUrl) {
    var self = this;

    assert(emailGateway, "emailGateway missing");
    assert(messageStore, "messageStore missing");
    assert(kirraBaseUrl, "kirraBaseUrl missing");
    assert(kirraApiUrl, "kirraApiUrl missing");

    self.messageStore = messageStore;
    self.emailGateway = emailGateway;

    self.parseMessage = function (message) {
        var text = message.text;
        var comment = '';
        var processingRules = [];
        var isProcessing = false;
        if (text) {
		    text.split("\n").forEach(function (current) {
		        if (isProcessing) {
                    if (current.indexOf('--') === 0) {
                        isProcessing = false;
                    } else {
	                    processingRules.push(current);
                    }
		        } else {
		            if (current.indexOf('--') === 0) {
		                isProcessing = true;
		            } else {
		                comment += current + '\n';
		            }
		        }
		    });
        }
        var values = yaml.safeLoad(processingRules.join('\n'));
        message.comment = comment;
        message.values = merge(merge({}, values), message.values);
        // (entity)(-objectId)?.(application)@<domain>
        //  Examples: issue.my-application@foo.bar.com and issue-43234cc221ad.my-application@foo.bar.com
        var elements = /^([a-z_A-Z]+)(?:-([^.]+))?\.([^@^.]+)@.*$/.exec(message.account);
        if (elements !== null) {
            message.entity = elements[1].replace("_", ".");
            message.objectId = elements[2];
            message.application = elements[3];
        }
        return message;

    };

    self.resolveLooseReference = function(kirraApp, entityName, value, context) {
        return kirraApp.getExactEntity(entityName).then(function (entity) {
            var filter = {};
            filter[entity.properties[Object.keys(entity.properties)[0]].name] = value;
            return kirraApp.getInstances(entityName, filter).then(function(instances) {
                return { matching: instances.contents, context: context };
            });
        });
    };

    self.processPendingMessage = function (message) {
        self.parseMessage(message);
        if (!message.application) {
            message.status = 'Invalid';
            emailGateway.replyToSender(message, "Unfortunately, your message could not be processed.");
            return messageStore.saveMessage(message).then(function() { return message; });
        }
        var kirraApp = new Kirra(kirraApiUrl, message.application);
        message.status = 'Processing';
        return messageStore.saveMessage(message).then(function () {
            return kirraApp.getApplication();
        }).then(function () {
            return kirraApp.getEntity(message.entity);
        }).then(function (entity) {
            var deferred = q.defer();
            var promise = deferred.promise;
            // it is possible the entity was loosely named, force a precise entity name
            message.entity = entity.fullName;
            // it is possible the fields were loosely named, replace with precisely named fields
            var properName = undefined;
            if (message.values) {
                var values = {};
                var links = {};
                var invocations = [];
                var linkResolvers = [], argumentResolvers = [];
                message_values: for (var key in message.values) {
                    entity_properties: for (var property in entity.properties) {
                        if (entity.properties[property].name.toUpperCase() === key.toUpperCase() || entity.properties[property].label.toUpperCase() === key.toUpperCase()) {
                            values[entity.properties[property].name] = message.values[key];
                            continue message_values;
                        }
                    }
                    entity_relationships: for (var r in entity.relationships) {
                        if (entity.relationships[r].name.toUpperCase() === key.toUpperCase() || entity.relationships[r].label.toUpperCase() === key.toUpperCase()) {
                            linkResolvers.push(self.resolveLooseReference(
                                    kirraApp,
                                    entity.relationships[r].typeRef.fullName,
                                    message.values[key],
                                    entity.relationships[r]
                                ));
                            promise = promise.then(function () {
                                return linkResolvers.shift().then(function(result) {
                                    links[result.context.name] = [{ uri: result.matching[0].uri }];
                                });
                            });
                            continue message_values;
                        }
                    }
                    entity_actions: for (var o in entity.operations) {
                        var operation = entity.operations[o];
                        if (operation.name.toUpperCase() === key.toUpperCase() || operation.label.toUpperCase() === key.toUpperCase()) {
                            var operationArguments = message.values[key];
                            invocations.push({ operation: operation, arguments: operationArguments });
                            for (var a in operationArguments) {
                                var parameter = operation.parameters.find(function (p) { return p.name === a });
                                if (parameter && parameter.typeRef.kind === 'Entity') {
                                    argumentResolvers.push(self.resolveLooseReference(
                                        kirraApp,
                                        parameter.typeRef.fullName,
                                        operationArguments[a],
                                        // context needs two coordinates - the invocation, and the argument name
                                        { invocationIndex: invocations.length - 1, argumentName: a }
                                    ));
                                    promise = promise.then(function () {
                                        return argumentResolvers.shift().then(function(result) {
                                            invocations[result.context.invocationIndex].arguments[result.context.argumentName] = { uri: result.matching[0].uri };
                                        });
                                    });
                                }
                            }
                            continue message_values;
                        }
                    }
                }
                message.values = values;
                message.links = links;
                message.invocations = invocations;
            }
            deferred.resolve(message);
            return promise.then(function () {
                return messageStore.saveMessage(message);
            });
        }).then(function(message) {
            if (message.objectId) {
                return self.processUpdateMessage(kirraApp, message);
            } else {
                return self.processCreationMessage(kirraApp, message);
            }
        }).then(function(message) {
            message.invocationsAttempted = [];
            message.invocationsCompleted = [];
            var invocationConsumer;

            invocationConsumer = function(message) {
                if (message.invocations.length === 0) {
                    return message;
                }
                var nextToInvoke = message.invocations.shift();
                message.invocationsAttempted.push(nextToInvoke);
                return self.messageStore.saveMessage(message).then(function(message) {
                    return kirraApp.invokeOperation(message.objectId, nextToInvoke.operation, nextToInvoke.arguments);
                }).then(function() {
                    var justInvoked = message.invocationsAttempted.shift();
                    message.invocationsCompleted.push(justInvoked);
                    return self.messageStore.saveMessage(message);
                }).then(invocationConsumer);
            };
            return invocationConsumer(message);
        }, self.onError(message, "Invalid application")).then(
            function() { return message; }
        );
    };

    self.makeEmailForInstance = function(message) {
        return message.entity.replace('.', '_') + '-' + message.objectId + '.' + message.application + '@inbox.cloudfier.com';
    };

    self.processCreationMessage = function(kirraApp, message) {
        var createdInstance;
        return kirraApp.createInstance(message).then(function (instance) {
            createdInstance = instance;
            message.objectId = instance.objectId;
            message.values = instance.values;
            message.links = instance.links;
            message.status = "Created";
	        self.sendMessageWithLink(message, instance, "Message successfully processed. Object was created.");
            return self.messageStore.saveMessage(message).then(function(savedMessage) { return savedMessage; });
        }, self.onError(message, "Error processing your message, object not created."));
    };

    self.processUpdateMessage = function(kirraApp, message) {
        return kirraApp.updateInstance(message).then(function (instance) {
	        self.sendMessageWithLink(message, instance, "Message successfully processed. Object was updated.");
	        message.status = "Updated";
            message.values = instance.values;
            message.links = instance.links;
	        return self.messageStore.saveMessage(message).then(function(updatedMessage) { return updatedMessage; });
        }, self.onError(message, "Error processing your message, object not updated."));
    };

    self.replyToSender = function(message, body, senderEmail) {
        emailGateway.replyToSender(message, body, senderEmail);
    };

    self.sendMessageWithLink = function(message, instance, userMessage) {
        self.replyToSender(message, userMessage + "\n" + yaml.safeDump(instance.values, { skipInvalid: true }) +
            "Use the URL below to access this object:\n\n" +
            kirraBaseUrl + '/kirra-api/kirra_qooxdoo/build/?app-path=/services/api-v2/' +
            message.application + '#' + encodeURIComponent('/entities/' + message.entity + '/instances/' + message.objectId), self.makeEmailForInstance(message));
    };

    self.onError = function(message, errorMessage) {
	    return function (e) {
	        console.error(e);
		    message.status = "Failure";
		    message.error = e;
		    messageStore.saveMessage(message);
	        self.replyToSender(message, errorMessage + " Reason: " + e.message);
	        return message;
	    };
    };

    return self;
};

var exports = module.exports = MessageProcessor;
<commit_msg>can handle two actions in the same message<commit_after>require('array.prototype.find');
var q = require('q');
var util = require('util');

var yaml = require("js-yaml");
var url = require("url");

var Kirra = require("./kirra-client.js");
var ebuiUtil = require("./util.js");

var assert = ebuiUtil.assert;
var merge = ebuiUtil.merge;

var MessageProcessor = function (emailGateway, messageStore, kirraBaseUrl, kirraApiUrl) {
    var self = this;

    assert(emailGateway, "emailGateway missing");
    assert(messageStore, "messageStore missing");
    assert(kirraBaseUrl, "kirraBaseUrl missing");
    assert(kirraApiUrl, "kirraApiUrl missing");

    self.messageStore = messageStore;
    self.emailGateway = emailGateway;

    self.parseMessage = function (message) {
        var text = message.text;
        var comment = '';
        var processingRules = [];
        var isProcessing = false;
        if (text) {
		    text.split("\n").forEach(function (current) {
		        if (isProcessing) {
                    if (current.indexOf('--') === 0) {
                        isProcessing = false;
                    } else {
	                    processingRules.push(current);
                    }
		        } else {
		            if (current.indexOf('--') === 0) {
		                isProcessing = true;
		            } else {
		                comment += current + '\n';
		            }
		        }
		    });
        }
        var values = yaml.safeLoad(processingRules.join('\n'));
        message.comment = comment;
        message.values = merge(merge({}, values), message.values);
        // (entity)(-objectId)?.(application)@<domain>
        //  Examples: issue.my-application@foo.bar.com and issue-43234cc221ad.my-application@foo.bar.com
        var elements = /^([a-z_A-Z]+)(?:-([^.]+))?\.([^@^.]+)@.*$/.exec(message.account);
        if (elements !== null) {
            message.entity = elements[1].replace("_", ".");
            message.objectId = elements[2];
            message.application = elements[3];
        }
        return message;

    };

    self.resolveLooseReference = function(kirraApp, entityName, value, context) {
        return kirraApp.getExactEntity(entityName).then(function (entity) {
            var filter = {};
            filter[entity.properties[Object.keys(entity.properties)[0]].name] = value;
            return kirraApp.getInstances(entityName, filter).then(function(instances) {
                return { matching: instances.contents, context: context };
            });
        });
    };

    self.processPendingMessage = function (message) {
        self.parseMessage(message);
        if (!message.application) {
            message.status = 'Invalid';
            emailGateway.replyToSender(message, "Unfortunately, your message could not be processed.");
            return messageStore.saveMessage(message).then(function() { return message; });
        }
        var kirraApp = new Kirra(kirraApiUrl, message.application);
        message.status = 'Processing';
        return messageStore.saveMessage(message).then(function () {
            return kirraApp.getApplication();
        }).then(function () {
            return kirraApp.getEntity(message.entity);
        }).then(function (entity) {
            var deferred = q.defer();
            var promise = deferred.promise;
            // it is possible the entity was loosely named, force a precise entity name
            message.entity = entity.fullName;
            // it is possible the fields were loosely named, replace with precisely named fields
            var properName = undefined;
            if (message.values) {
                var values = {};
                var links = {};
                var invocations = [];
                var linkResolvers = [], argumentResolvers = [];
                message_values: for (var key in message.values) {
                    entity_properties: for (var property in entity.properties) {
                        if (entity.properties[property].name.toUpperCase() === key.toUpperCase() || entity.properties[property].label.toUpperCase() === key.toUpperCase()) {
                            values[entity.properties[property].name] = message.values[key];
                            continue message_values;
                        }
                    }
                    entity_relationships: for (var r in entity.relationships) {
                        if (entity.relationships[r].name.toUpperCase() === key.toUpperCase() || entity.relationships[r].label.toUpperCase() === key.toUpperCase()) {
                            linkResolvers.push(self.resolveLooseReference(
                                    kirraApp,
                                    entity.relationships[r].typeRef.fullName,
                                    message.values[key],
                                    entity.relationships[r]
                                ));
                            promise = promise.then(function () {
                                return linkResolvers.shift().then(function(result) {
                                    links[result.context.name] = [{ uri: result.matching[0].uri }];
                                });
                            });
                            continue message_values;
                        }
                    }
                    entity_actions: for (var o in entity.operations) {
                        var operation = entity.operations[o];
                        if (operation.name.toUpperCase() === key.toUpperCase() || operation.label.toUpperCase() === key.toUpperCase()) {
                            var operationArguments = message.values[key];
                            invocations.push({ operation: operation, arguments: operationArguments });
                            for (var a in operationArguments) {
                                var parameter = operation.parameters.find(function (p) { return p.name === a });
                                if (parameter && parameter.typeRef.kind === 'Entity') {
                                    argumentResolvers.push(self.resolveLooseReference(
                                        kirraApp,
                                        parameter.typeRef.fullName,
                                        operationArguments[a],
                                        // context needs two coordinates - the invocation, and the argument name
                                        { invocationIndex: invocations.length - 1, argumentName: a }
                                    ));
                                    promise = promise.then(function () {
                                        return argumentResolvers.shift().then(function(result) {
                                            invocations[result.context.invocationIndex].arguments[result.context.argumentName] = { uri: result.matching[0].uri };
                                        });
                                    });
                                }
                            }
                            continue message_values;
                        }
                    }
                }
                message.values = values;
                message.links = links;
                message.invocations = invocations;
            }
            deferred.resolve(message);
            return promise.then(function () {
                return messageStore.saveMessage(message);
            });
        }).then(function(message) {
            return (message.objectId ?
                self.processUpdateMessage(kirraApp, message) :
                self.processCreationMessage(kirraApp, message)
            ).then(self.invokePendingActions(kirraApp, message));
        }, self.onError(message, "Invalid application")).then(
            function() { return message; }
        );
    };

    self.makeEmailForInstance = function(message) {
        return message.entity.replace('.', '_') + '-' + message.objectId + '.' + message.application + '@inbox.cloudfier.com';
    };

    self.invokePendingActions = function(kirraApp, message) {
        message.invocationsAttempted = [];
        message.invocationsCompleted = [];
        var invocationConsumer;

        invocationConsumer = function(message) {
            if (message.invocations.length === 0) {
                return message;
            }
            var nextToInvoke = message.invocations.shift();
            message.invocationsAttempted.push(nextToInvoke);
            return self.messageStore.saveMessage(message).then(function(message) {
                return kirraApp.invokeOperation(message.objectId, nextToInvoke.operation, nextToInvoke.arguments);
            }).then(function() {
                var justInvoked = message.invocationsAttempted.shift();
                message.invocationsCompleted.push(justInvoked);
                return self.messageStore.saveMessage(message);
            }).then(invocationConsumer);
        };
        return invocationConsumer(message);
    };

    self.processCreationMessage = function(kirraApp, message) {
        var createdInstance;
        return kirraApp.createInstance(message).then(function (instance) {
            createdInstance = instance;
            message.objectId = instance.objectId;
            message.values = instance.values;
            message.links = instance.links;
            message.status = "Created";
	        self.sendMessageWithLink(message, instance, "Message successfully processed. Object was created.");
            return self.messageStore.saveMessage(message).then(function(savedMessage) { return savedMessage; });
        }, self.onError(message, "Error processing your message, object not created."));
    };

    self.processUpdateMessage = function(kirraApp, message) {
        return kirraApp.updateInstance(message).then(function (instance) {
	        self.sendMessageWithLink(message, instance, "Message successfully processed. Object was updated.");
	        message.status = "Updated";
            message.values = instance.values;
            message.links = instance.links;
	        return self.messageStore.saveMessage(message).then(function(updatedMessage) { return updatedMessage; });
        }, self.onError(message, "Error processing your message, object not updated."));
    };

    self.replyToSender = function(message, body, senderEmail) {
        emailGateway.replyToSender(message, body, senderEmail);
    };

    self.sendMessageWithLink = function(message, instance, userMessage) {
        self.replyToSender(message, userMessage + "\n" + yaml.safeDump(instance.values, { skipInvalid: true }) +
            "Use the URL below to access this object:\n\n" +
            kirraBaseUrl + '/kirra-api/kirra_qooxdoo/build/?app-path=/services/api-v2/' +
            message.application + '#' + encodeURIComponent('/entities/' + message.entity + '/instances/' + message.objectId), self.makeEmailForInstance(message));
    };

    self.onError = function(message, errorMessage) {
	    return function (e) {
	        console.error(e);
		    message.status = "Failure";
		    message.error = e;
		    messageStore.saveMessage(message);
	        self.replyToSender(message, errorMessage + " Reason: " + e.message);
	        return message;
	    };
    };

    return self;
};

var exports = module.exports = MessageProcessor;
<|endoftext|>


<commit_before>// Backup or restore the database to/from .data/backups/ or specified path
//

var mongodbBackup = require('mongodb-backup');
var mongodbRestore = require('mongodb-restore');
var moment = require('moment');
var path = require('path');
var fs = require('fs');
var local = require('../config/local');

// Dir name format
var FORMAT = 'YYYY-MM-DDTHH-mm-ss';

var findLatest = function (callback) {
  // Find name of the latest backup.
  //
  // Parameters:
  //   callback
  //     function (err, latestName)

  fs.readdir(local.mongo.backupDir, function (err, items) {
    if (err) {
      return callback(err);
    }

    var moms = items.map(function (item) {
      return moment(item, FORMAT);
    });

    var latest = moment.max(moms);

    return callback(null, latest.format(FORMAT));
  });
};

exports.list = function (callback) {
  // List available backups.
  //
  // Parameters:
  //   callback
  //     function (err, namelist)

  fs.readdir(local.mongo.backupDir, callback);
};

exports.backupTo = function (dirPath, callback) {

  mongodbBackup({
    uri: local.mongo.url,
    root: dirPath,
    parser: 'bson',
    callback: function (err) {
      if (err) {
        return callback(err);
      }  // else

      return callback(null, dirPath);
    },
  });
};

exports.backup = function (callback) {
  // Parameters:
  //   callback
  //     function (err, backupName)
  //       Parameters:
  //         err
  //         backupName
  //           name of the backup directory (not path)

  // Root dir name is derived from current time
  var dirname = moment().format(FORMAT);
  var root = path.resolve(local.mongo.backupDir, dirname);

  exports.backupTo(root, function (err) {
    return callback(err, dirname);
  });
};

exports.restoreFrom = function (dirPath, callback) {
  var root = path.resolve(dirPath, 'tresdb');

  fs.exists(root, function (rootDirExists) {
    var err2;

    if (!rootDirExists) {
      err2 = new Error('No backups found with the path "' + root + '"');
      err2.name = 'InvalidBackupName';

      return callback(err2);
    }  // else

    mongodbRestore({
      uri: local.mongo.url,
      root: root,
      parser: 'bson',
      dropCollections: true,
      callback: function (err3) {
        if (err3) {
          return callback(err3);
        }  // else

        return callback(null, root);
      },
    });
  });
};

exports.restore = function (name, callback) {
  // Parameters
  //   name
  //     optional, name of the dir under local.mongo.backupDir.
  //     If omitted, defaults to latest backup.
  //   callback
  //     function (err, restoredName)
  var cb, p, root;

  // p = null means that use the latest
  if (typeof name === 'function') {
    cb = name;
    p = null;
  } else {
    if (typeof callback === 'function') {
      cb = callback;
    } else {
      cb = function () {};
    }

    if (typeof name === 'string' && name.length > 0) {
      p = name;
    } else {
      p = null;
    }
  }

  if (p === null) {

    findLatest(function (err, latestDirName) {
      if (err) {
        return cb(err);
      }

      root = path.resolve(local.mongo.backupDir, latestDirName);

      return exports.restoreFrom(root, cb);
    });

  } else {

    root = path.resolve(local.mongo.backupDir, p);

    return exports.restoreFrom(root, cb);
  }
};
<commit_msg>Use fs-extra<commit_after>// Backup or restore the database to/from .data/backups/ or specified path
//

var mongodbBackup = require('mongodb-backup');
var mongodbRestore = require('mongodb-restore');
var moment = require('moment');
var path = require('path');
var local = require('../config/local');
var fse = require('fs-extra');

// Dir name format
var FORMAT = 'YYYY-MM-DDTHH-mm-ss';

var findLatest = function (callback) {
  // Find name of the latest backup.
  //
  // Parameters:
  //   callback
  //     function (err, latestName)

  fse.readdir(local.mongo.backupDir, function (err, items) {
    if (err) {
      return callback(err);
    }

    var moms = items.map(function (item) {
      return moment(item, FORMAT);
    });

    var latest = moment.max(moms);

    return callback(null, latest.format(FORMAT));
  });
};

exports.list = function (callback) {
  // List available backups.
  //
  // Parameters:
  //   callback
  //     function (err, namelist)

  fse.readdir(local.mongo.backupDir, callback);
};

exports.backupTo = function (dirPath, callback) {

  mongodbBackup({
    uri: local.mongo.url,
    root: dirPath,
    parser: 'bson',
    callback: function (err) {
      if (err) {
        return callback(err);
      }  // else

      return callback(null, dirPath);
    },
  });
};

exports.backup = function (callback) {
  // Parameters:
  //   callback
  //     function (err, backupName)
  //       Parameters:
  //         err
  //         backupName
  //           name of the backup directory (not path)

  // Root dir name is derived from current time
  var dirname = moment().format(FORMAT);
  var root = path.resolve(local.mongo.backupDir, dirname);

  exports.backupTo(root, function (err) {
    return callback(err, dirname);
  });
};

exports.restoreFrom = function (dirPath, callback) {
  var root = path.resolve(dirPath, 'tresdb');

  fse.exists(root, function (rootDirExists) {
    var err2;

    if (!rootDirExists) {
      err2 = new Error('No backups found with the path "' + root + '"');
      err2.name = 'InvalidBackupName';

      return callback(err2);
    }  // else

    mongodbRestore({
      uri: local.mongo.url,
      root: root,
      parser: 'bson',
      dropCollections: true,
      callback: function (err3) {
        if (err3) {
          return callback(err3);
        }  // else

        return callback(null, root);
      },
    });
  });
};

exports.restore = function (name, callback) {
  // Parameters
  //   name
  //     optional, name of the dir under local.mongo.backupDir.
  //     If omitted, defaults to latest backup.
  //   callback
  //     function (err, restoredName)
  var cb, p, root;

  // p = null means that use the latest
  if (typeof name === 'function') {
    cb = name;
    p = null;
  } else {
    if (typeof callback === 'function') {
      cb = callback;
    } else {
      cb = function () {};
    }

    if (typeof name === 'string' && name.length > 0) {
      p = name;
    } else {
      p = null;
    }
  }

  if (p === null) {

    findLatest(function (err, latestDirName) {
      if (err) {
        return cb(err);
      }

      root = path.resolve(local.mongo.backupDir, latestDirName);

      return exports.restoreFrom(root, cb);
    });

  } else {

    root = path.resolve(local.mongo.backupDir, p);

    return exports.restoreFrom(root, cb);
  }
};
<|endoftext|>


<commit_before>/*
  Adds migration capabilities. Migrations are defined like:

  Migrations.add({
    up: function() {}, //*required* code to run to migrate upwards
    version: 1, //*required* number to identify migration order
    down: function() {}, //*optional* code to run to migrate downwards
    name: 'Something' //*optional* display name for the migration
  });

  The ordering of migrations is determined by the version you set.

  To run the migrations, set the MIGRATE environment variable to either
  'latest' or the version number you want to migrate to. Optionally, append
  ',exit' if you want the migrations to exit the meteor process, e.g if you're
  migrating from a script (remember to pass the --once parameter).

  e.g:
  MIGRATE="latest" mrt # ensure we'll be at the latest version and run the app
  MIGRATE="latest,exit" mrt --once # ensure we'll be at the latest version and exit
  MIGRATE="2,exit" mrt --once # migrate to version 2 and exit

  Note: Migrations will lock ensuring only 1 app can be migrating at once. If
  a migration crashes, the control record in the migrations collection will
  remain locked and at the version it was at previously, however the db could
  be in an inconsistant state.
*/

// since we'll be at version 0 by default, we should have a migration set for
// it.
var DefaultMigration = {version: 0, up: function(){}};

Migrations = {
  _list: [DefaultMigration],
  options: {
    // false disables logging
    log: true,
    // null or a function
    logger: null,
    // enable/disable info log "already at latest."
    logIfLatest: true,
    // migrations collection name
    collectionName: "migrations"
  },
  config: function(opts) {
    this.options = _.extend({}, this.options, opts);
  },
}

/*
  Logger factory function. Takes a prefix string and options object
  and uses an injected `logger` if provided, else falls back to
  Meteor's `Log` package.
  Will send a log object to the injected logger, on the following form:
    message: String
    level: String (info, warn, error, debug)
    tag: 'Migrations'
*/
function createLogger(prefix) {
  check(prefix, String);

  // Return noop if logging is disabled.
  if(Migrations.options.log === false) {
    return function() {};
  }

  return function(level, message) {
    check(level, Match.OneOf('info', 'error', 'warn', 'debug'));
    check(message, String);

    var logger = Migrations.options && Migrations.options.logger;

    if(logger && _.isFunction(logger)) {

      logger({
        level: level,
        message: message,
        tag: prefix
      });

    } else {
      Log[level]({ message: prefix + ': ' + message });
    }
  }
}

var log;

Meteor.startup(function () {
  var options = Migrations.options;

  // collection holding the control record
  Migrations._collection = new Mongo.Collection(options.collectionName);

  log = createLogger('Migrations');

  ['info', 'warn', 'error', 'debug'].forEach(function(level) {
    log[level] = _.partial(log, level);
  });

  if (process.env.MIGRATE)
    Migrations.migrateTo(process.env.MIGRATE);
});

// Add a new migration:
// {up: function *required
//  version: Number *required
//  down: function *optional
//  name: String *optional
// }
Migrations.add = function(migration) {
  if (typeof migration.up !== 'function')
    throw new Meteor.Error('Migration must supply an up function.');

  if (typeof migration.version !== 'number')
    throw new Meteor.Error('Migration must supply a version number.');

  if (migration.version <= 0)
    throw new Meteor.Error('Migration version must be greater than 0');

  // Freeze the migration object to make it hereafter immutable
  Object.freeze(migration);

  this._list.push(migration);
  this._list = _.sortBy(this._list, function(m) {return m.version;});
}

// Attempts to run the migrations using command in the form of:
// e.g 'latest', 'latest,exit', 2
// use 'XX,rerun' to re-run the migration at that version
Migrations.migrateTo = function(command) {
  if (_.isUndefined(command) || command === '' || this._list.length === 0)
    throw new Error("Cannot migrate using invalid command: " + command);

  if (typeof command === 'number') {
    var version = command;
  } else {
    var version = command.split(',')[0];
    var subcommand = command.split(',')[1];
  }

  if (version === 'latest') {
    this._migrateTo(_.last(this._list).version);
  } else {
    this._migrateTo(parseInt(version), (subcommand === 'rerun'));
  }

  // remember to run meteor with --once otherwise it will restart
  if (subcommand === 'exit')
    process.exit(0);
}

// just returns the current version
Migrations.getVersion = function() {
  return this._getControl().version;
}

// migrates to the specific version passed in
Migrations._migrateTo = function(version, rerun) {
  var self = this;
  var control = this._getControl(); // Side effect: upserts control document.
  var currentVersion = control.version;

  if (lock() === false) {
    log.info('Not migrating, control is locked.');
    return;
  }

  if (rerun) {
    log.info('Rerunning version ' + version);
    migrate('up', version);
    log.info('Finished migrating.');
    unlock();
    return;
  }

  if (currentVersion === version) {
    if (Migrations.options.logIfLatest) {
      log.info('Not migrating, already at version ' + version);
    }
    unlock();
    return;
  }

  var startIdx = this._findIndexByVersion(currentVersion);
  var endIdx = this._findIndexByVersion(version);

  // log.info('startIdx:' + startIdx + ' endIdx:' + endIdx);
  log.info('Migrating from version ' + this._list[startIdx].version
    + ' -> ' + this._list[endIdx].version);

  // run the actual migration
  function migrate(direction, idx) {
    var migration = self._list[idx];

    if (typeof migration[direction] !== 'function') {
      unlock();
      throw new Meteor.Error('Cannot migrate ' + direction + ' on version '
        + migration.version);
    }

    function maybeName() {
      return migration.name ? ' (' + migration.name + ')' : '';
    }

    log.info('Running ' + direction + '() on version '
      + migration.version + maybeName());

    migration[direction](migration);
  }

  // Returns true if lock was acquired.
  function lock() {
    // This is atomic. The selector ensures only one caller at a time will see
    // the unlocked control, and locking occurs in the same update's modifier.
    // All other simultaneous callers will get false back from the update.
    return self._collection.update(
      {_id: 'control', locked: false}, {$set: {locked: true, lastLocked: new Date()}}
    ) === 1;
  }

  // Side effect: saves version.
  function unlock() {
    self._setControl({locked: false, version: currentVersion});
  }

  if (currentVersion < version) {
    for (var i = startIdx;i < endIdx;i++) {
      migrate('up', i + 1);
      currentVersion = self._list[i + 1].version;
    }
  } else {
    for (var i = startIdx;i > endIdx;i--) {
      migrate('down', i);
      currentVersion = self._list[i - 1].version;
    }
  }

  unlock();
  log.info('Finished migrating.');
}

// gets the current control record, optionally creating it if non-existant
Migrations._getControl = function() {
  var control = this._collection.findOne({_id: 'control'});

  return control || this._setControl({version: 0, locked: false});
}

// sets the control record
Migrations._setControl = function(control) {
  // be quite strict
  check(control.version, Number);
  check(control.locked, Boolean);

  this._collection.update({_id: 'control'},
    {$set: {version: control.version, locked: control.locked}}, {upsert: true});

  return control;
}

// returns the migration index in _list or throws if not found
Migrations._findIndexByVersion = function(version) {
  for (var i = 0;i < this._list.length;i++) {
    if (this._list[i].version === version)
      return i;
  }

  throw new Meteor.Error('Can\'t find migration version ' + version);
}

//reset (mainly intended for tests)
Migrations._reset = function() {
  this._list = [{version: 0, up: function(){}}];
  this._collection.remove({});
}
<commit_msg>Renames lastLocked to lockedAt<commit_after>/*
  Adds migration capabilities. Migrations are defined like:

  Migrations.add({
    up: function() {}, //*required* code to run to migrate upwards
    version: 1, //*required* number to identify migration order
    down: function() {}, //*optional* code to run to migrate downwards
    name: 'Something' //*optional* display name for the migration
  });

  The ordering of migrations is determined by the version you set.

  To run the migrations, set the MIGRATE environment variable to either
  'latest' or the version number you want to migrate to. Optionally, append
  ',exit' if you want the migrations to exit the meteor process, e.g if you're
  migrating from a script (remember to pass the --once parameter).

  e.g:
  MIGRATE="latest" mrt # ensure we'll be at the latest version and run the app
  MIGRATE="latest,exit" mrt --once # ensure we'll be at the latest version and exit
  MIGRATE="2,exit" mrt --once # migrate to version 2 and exit

  Note: Migrations will lock ensuring only 1 app can be migrating at once. If
  a migration crashes, the control record in the migrations collection will
  remain locked and at the version it was at previously, however the db could
  be in an inconsistant state.
*/

// since we'll be at version 0 by default, we should have a migration set for
// it.
var DefaultMigration = {version: 0, up: function(){}};

Migrations = {
  _list: [DefaultMigration],
  options: {
    // false disables logging
    log: true,
    // null or a function
    logger: null,
    // enable/disable info log "already at latest."
    logIfLatest: true,
    // migrations collection name
    collectionName: "migrations"
  },
  config: function(opts) {
    this.options = _.extend({}, this.options, opts);
  },
}

/*
  Logger factory function. Takes a prefix string and options object
  and uses an injected `logger` if provided, else falls back to
  Meteor's `Log` package.
  Will send a log object to the injected logger, on the following form:
    message: String
    level: String (info, warn, error, debug)
    tag: 'Migrations'
*/
function createLogger(prefix) {
  check(prefix, String);

  // Return noop if logging is disabled.
  if(Migrations.options.log === false) {
    return function() {};
  }

  return function(level, message) {
    check(level, Match.OneOf('info', 'error', 'warn', 'debug'));
    check(message, String);

    var logger = Migrations.options && Migrations.options.logger;

    if(logger && _.isFunction(logger)) {

      logger({
        level: level,
        message: message,
        tag: prefix
      });

    } else {
      Log[level]({ message: prefix + ': ' + message });
    }
  }
}

var log;

Meteor.startup(function () {
  var options = Migrations.options;

  // collection holding the control record
  Migrations._collection = new Mongo.Collection(options.collectionName);

  log = createLogger('Migrations');

  ['info', 'warn', 'error', 'debug'].forEach(function(level) {
    log[level] = _.partial(log, level);
  });

  if (process.env.MIGRATE)
    Migrations.migrateTo(process.env.MIGRATE);
});

// Add a new migration:
// {up: function *required
//  version: Number *required
//  down: function *optional
//  name: String *optional
// }
Migrations.add = function(migration) {
  if (typeof migration.up !== 'function')
    throw new Meteor.Error('Migration must supply an up function.');

  if (typeof migration.version !== 'number')
    throw new Meteor.Error('Migration must supply a version number.');

  if (migration.version <= 0)
    throw new Meteor.Error('Migration version must be greater than 0');

  // Freeze the migration object to make it hereafter immutable
  Object.freeze(migration);

  this._list.push(migration);
  this._list = _.sortBy(this._list, function(m) {return m.version;});
}

// Attempts to run the migrations using command in the form of:
// e.g 'latest', 'latest,exit', 2
// use 'XX,rerun' to re-run the migration at that version
Migrations.migrateTo = function(command) {
  if (_.isUndefined(command) || command === '' || this._list.length === 0)
    throw new Error("Cannot migrate using invalid command: " + command);

  if (typeof command === 'number') {
    var version = command;
  } else {
    var version = command.split(',')[0];
    var subcommand = command.split(',')[1];
  }

  if (version === 'latest') {
    this._migrateTo(_.last(this._list).version);
  } else {
    this._migrateTo(parseInt(version), (subcommand === 'rerun'));
  }

  // remember to run meteor with --once otherwise it will restart
  if (subcommand === 'exit')
    process.exit(0);
}

// just returns the current version
Migrations.getVersion = function() {
  return this._getControl().version;
}

// migrates to the specific version passed in
Migrations._migrateTo = function(version, rerun) {
  var self = this;
  var control = this._getControl(); // Side effect: upserts control document.
  var currentVersion = control.version;

  if (lock() === false) {
    log.info('Not migrating, control is locked.');
    return;
  }

  if (rerun) {
    log.info('Rerunning version ' + version);
    migrate('up', version);
    log.info('Finished migrating.');
    unlock();
    return;
  }

  if (currentVersion === version) {
    if (Migrations.options.logIfLatest) {
      log.info('Not migrating, already at version ' + version);
    }
    unlock();
    return;
  }

  var startIdx = this._findIndexByVersion(currentVersion);
  var endIdx = this._findIndexByVersion(version);

  // log.info('startIdx:' + startIdx + ' endIdx:' + endIdx);
  log.info('Migrating from version ' + this._list[startIdx].version
    + ' -> ' + this._list[endIdx].version);

  // run the actual migration
  function migrate(direction, idx) {
    var migration = self._list[idx];

    if (typeof migration[direction] !== 'function') {
      unlock();
      throw new Meteor.Error('Cannot migrate ' + direction + ' on version '
        + migration.version);
    }

    function maybeName() {
      return migration.name ? ' (' + migration.name + ')' : '';
    }

    log.info('Running ' + direction + '() on version '
      + migration.version + maybeName());

    migration[direction](migration);
  }

  // Returns true if lock was acquired.
  function lock() {
    // This is atomic. The selector ensures only one caller at a time will see
    // the unlocked control, and locking occurs in the same update's modifier.
    // All other simultaneous callers will get false back from the update.
    return self._collection.update(
      {_id: 'control', locked: false}, {$set: {locked: true, lockedAt: new Date()}}
    ) === 1;
  }

  // Side effect: saves version.
  function unlock() {
    self._setControl({locked: false, version: currentVersion});
  }

  if (currentVersion < version) {
    for (var i = startIdx;i < endIdx;i++) {
      migrate('up', i + 1);
      currentVersion = self._list[i + 1].version;
    }
  } else {
    for (var i = startIdx;i > endIdx;i--) {
      migrate('down', i);
      currentVersion = self._list[i - 1].version;
    }
  }

  unlock();
  log.info('Finished migrating.');
}

// gets the current control record, optionally creating it if non-existant
Migrations._getControl = function() {
  var control = this._collection.findOne({_id: 'control'});

  return control || this._setControl({version: 0, locked: false});
}

// sets the control record
Migrations._setControl = function(control) {
  // be quite strict
  check(control.version, Number);
  check(control.locked, Boolean);

  this._collection.update({_id: 'control'},
    {$set: {version: control.version, locked: control.locked}}, {upsert: true});

  return control;
}

// returns the migration index in _list or throws if not found
Migrations._findIndexByVersion = function(version) {
  for (var i = 0;i < this._list.length;i++) {
    if (this._list[i].version === version)
      return i;
  }

  throw new Meteor.Error('Can\'t find migration version ' + version);
}

//reset (mainly intended for tests)
Migrations._reset = function() {
  this._list = [{version: 0, up: function(){}}];
  this._collection.remove({});
}
<|endoftext|>


<commit_before>(function (ng, app) {

    var subnav = [
            { state: 'org-view', text: 'Organisation' }
    ];

    app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {

        $stateProvider.state('org-view', {
            url: '/organization',
            templateUrl: 'partials/org/org.html',
            controller: 'org.OrgViewCtrl',
            resolve: {
                orgRolesHttp: ['$http', function($http) {
                    return $http.get('api/organizationRole');
                }]
            }
        });

    }]);

    app.controller('org.OrgViewCtrl', ['$rootScope', '$scope', '$http', 'growl', 'orgRolesHttp', function ($rootScope, $scope, $http, growl, orgRolesHttp) {
        $rootScope.page.title = 'Organisation';
        $rootScope.page.subnav = subnav;

        var userId = $rootScope.user.id;

        //cache
        var orgs = [];

        //flatten map of all loaded orgUnits
        $scope.orgUnits = [];

        $scope.orgRoles = {};
        _.each(orgRolesHttp.data.Response, function(orgRole) {
            $scope.orgRoles[orgRole.Id] = orgRole;
        });

        console.log($scope.orgRoles);

        function flatten(orgUnit) {
            $scope.orgUnits[orgUnit.Id] = orgUnit;

            _.each(orgUnit.Children, flatten);
        }

        $http.get('api/organizationunit?userId=' + userId).success(function(result) {
            $scope.nodes = result.Response;

            _.each(result.Response, flatten);
        });

        $scope.chosenOrgUnit = null;

        $scope.chooseOrgUnit = function (node) {

            if (!node.Organization) {

                //try get from cache
                if (orgs[node.Organization_Id]) {

                    node.Organization = orgs[node.Organization_Id];

                } else {
                    //else get from server

                    $http.get('api/organization/' + node.Organization_Id).success(function (data) {
                        node.Organization = data.Response;

                        //save to cache
                        orgs[node.Organization_Id] = data.Response;
                    });
                }
            }

            if (!node.OrgRights) {
                $http.get('api/organizationRight?organizationUnitId=' + node.Id).success(function(data) {
                    node.OrgRights = data.Response;
                });
            }

            $scope.chosenOrgUnit = node;
        };

        $scope.userSelectOptions = {
            initSelection: function (element, callback) {
            },
            ajax: {
                data: function (term, page) {
                    return { query: term };
                },
                quietMillis: 500,
                transport: function (queryParams) {
                    //console.log(queryParams);
                    var res = $http.get('api/user?q=' + queryParams.data.query).then(queryParams.success);
                    res.abort = function () {
                        console.log('Aborting...');
                        return null;
                    };

                    return res;
                },
                results: function (data, page) {
                    console.log(data);
                    var results = [];

                    _.each(data.data.Response, function (user) {
                        results.push({
                            id: user.Id,
                            text: user.Name
                        });
                    });

                    return { results: results };
                }
            }

        };

        $scope.submitRight = function () {
            var data = {
                'Object_Id': $scope.chosenOrgUnit.Id,
                'Role_Id': $scope.newRole,
                'User_Id': $scope.selectedUser.id
            };

            console.log(data);
        };

    }]);

})(angular, app);<commit_msg>Added fetch calls<commit_after>(function (ng, app) {

    var subnav = [
            { state: 'org-view', text: 'Organisation' }
    ];

    app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {

        $stateProvider.state('org-view', {
            url: '/organization',
            templateUrl: 'partials/org/org.html',
            controller: 'org.OrgViewCtrl',
            resolve: {
                orgRolesHttp: ['$http', function($http) {
                    return $http.get('api/organizationRole');
                }]
            }
        });

    }]);

    app.controller('org.OrgViewCtrl', ['$rootScope', '$scope', '$http', 'growl', 'orgRolesHttp', 'Restangular', function ($rootScope, $scope, $http, growl, orgRolesHttp, Restangular) {
        $rootScope.page.title = 'Organisation';
        $rootScope.page.subnav = subnav;

        var userId = $rootScope.user.id;

        //cache
        var orgs = [];

        //flatten map of all loaded orgUnits
        $scope.orgUnits = [];

        $scope.orgRoles = {};
        _.each(orgRolesHttp.data.Response, function(orgRole) {
            $scope.orgRoles[orgRole.Id] = orgRole;
        });

        console.log($scope.orgRoles);

        function flatten(orgUnit) {
            $scope.orgUnits[orgUnit.Id] = orgUnit;

            _.each(orgUnit.Children, flatten);
        }

        $http.get('api/organizationunit?userId=' + userId).success(function(result) {
            $scope.nodes = result.Response;

            _.each(result.Response, flatten);
        });

        $scope.chosenOrgUnit = null;

        $scope.chooseOrgUnit = function (node) {

            if (!node.Organization) {

                //try get from cache
                if (orgs[node.Organization_Id]) {

                    node.Organization = orgs[node.Organization_Id];

                } else {
                    //else get from server

                    $http.get('api/organization/' + node.Organization_Id).success(function (data) {
                        node.Organization = data.Response;

                        //save to cache
                        orgs[node.Organization_Id] = data.Response;
                    });
                }
            }

            if (!node.OrgRights) {
                $http.get('api/organizationRight?organizationUnitId=' + node.Id).success(function(data) {
                    node.OrgRights = data.Response;
                });
            }

            $scope.chosenOrgUnit = node;
        };

        $scope.userSelectOptions = {
            initSelection: function (element, callback) {
            },
            ajax: {
                data: function (term, page) {
                    return { query: term };
                },
                quietMillis: 500,
                transport: function (queryParams) {
                    //console.log(queryParams);
                    var res = $http.get('api/user?q=' + queryParams.data.query).then(queryParams.success);
                    res.abort = function () {
                        console.log('Aborting...');
                        return null;
                    };

                    return res;
                },
                results: function (data, page) {
                    console.log(data);
                    var results = [];

                    _.each(data.data.Response, function (user) {
                        results.push({
                            id: user.Id,
                            text: user.Name
                        });
                    });

                    return { results: results };
                }
            }

        };

        $scope.submitRight = function () {
            var data = {
                'Object_Id': $scope.chosenOrgUnit.Id,
                'Role_Id': $scope.newRole,
                'User_Id': $scope.selectedUser.id
            };

            console.log(data);
        };

        Restangular.getList('OrganizationUnit/' + chooseOrgUnit.Id, 'taskrefs').then(function(refs) {
            $scope.chosenTaskRefs = refs;
        });

        Restangular.getList('OrganizationUnit/' + chooseOrgUnit.ParentId, 'taskrefs').then(function (refs) {
            $scope.availableTaskRefs = refs;
        });
    }]);

})(angular, app);<|endoftext|>


<commit_before>browser.on("init", function () {
    "use strict";

    const LOC_CACHE = new Map;
    const URI = Windows.Foundation.Uri;
    const RE_VALIDATE_URL = /^[-:.&#+(),?%=\/\w]+$/;

    // Attempt a function
    function attempt(func) {
        try {
            return func();
        }
        catch (e) {
            return e;
        }
    }

    // Check if a file exists at the specified URL
    function fileExists(url) {
        return new Promise(resolve =>
            Windows.Web.Http.HttpClient()
                .getAsync(new URI(url), Windows.Web.Http.HttpCompletionOption.responseHeadersRead)
                .done(e => resolve(e.isSuccessStatusCode), () => resolve(false))
        );
    }

    // Navigate to the specified absolute URL
    function navigate(webview, url, silent) {
        let resp = attempt(() => webview.navigate(url));
        let result = !(resp instanceof Error);

        if (!silent && !result) {
            console.error(`Unable to navigate to ${url}: ${resp.message}`);
        }
        return result;
    }

    // Show the favicon if available
    this.getFavicon = loc => {
        let host = new URI(loc).host;

        // Exit for cached ico location
        if (this.faviconLocs.has(host)) {
            loc = this.faviconLocs.get(host);
            if (loc) {
                this.favicon.src = loc;
            }
            else {
                this.hideFavicon();
            }
            return;
        }
        let protocol = loc.split(":")[0];

        // Hide favicon when the host cannot be resolved or the protocol is not http(s)
        if (!protocol.startsWith("http") || !host) {
            this.faviconLocs.set(host, "");
            this.hideFavicon();
            return;
        }

        loc = `${protocol}://${host}/favicon.ico`;

        // Check if there is a favicon in the root directory
        fileExists(loc).then(exists => {
            if (exists) {
                console.log(`Favicon found: ${loc}`);
                this.faviconLocs.set(host, loc);
                this.favicon.src = loc;
                return;
            }
            // Asynchronously check for a favicon in the web page markup
            console.log("Favicon not found in root. Checking the markup...");
            let asyncOp = this.webview.invokeScriptAsync("eval", `
                Object(Array.from(document.getElementsByTagName('link'))
                  .find(link => link.rel.includes('icon'))).href
            `);
            asyncOp.oncomplete = e => {
                loc = e.target.result || "";
                this.faviconLocs.set(host, loc);

                if (loc) {
                    console.log(`Found favicon in markup: ${loc}`);
                    this.favicon.src = loc;
                }
                else {
                    this.hideFavicon();
                }
            };
            asyncOp.onerror = e => {
                console.error(`Unable to find favicon in markup: ${e.message}`);
                this.faviconLocs.set(host, "");
            };
            asyncOp.start();
        });
    };

    // Hide the favicon
    this.hideFavicon = () => {
        this.favicon.src = "";
    };

    // Navigate to the specified location
    this.navigateTo = loc => {
        loc = LOC_CACHE.get(loc) || loc;

        // Check if the input value contains illegal characters
        let isUrl = RE_VALIDATE_URL.test(loc);
        if (isUrl && navigate(this.webview, loc, true)) {
            return;
        }
        let bingLoc = `https://www.bing.com/search?q=${encodeURIComponent(loc)}`;
        let locHTTP = `http://${loc}`;
        let locHTTPS = `https://${loc}`;

        console.log(`Unable to navigate to ${loc}\nAttemping to prepend http(s):// to URI...`);

        let uri = attempt(() => new URI(locHTTP));
        let isErr = uri instanceof Error;

        if (isErr || !isUrl || !uri.domain) {
            let message = isErr ? uri.message : "";
            console.log(`Prepend unsuccessful\nQuerying bing.com... "${loc}": ${message}`);

            LOC_CACHE.set(loc, bingLoc);
            navigate(this.webview, bingLoc);
        }
        else {
            // Check if the site supports https
            fileExists(locHTTPS).then(exists => {
                if (exists) {
                    LOC_CACHE.set(loc, locHTTPS);
                    navigate(this.webview, locHTTPS);
                }
            });

            // Get a head start on loading via http
            LOC_CACHE.set(loc, locHTTP);
            navigate(this.webview, locHTTP);
        }
    };

    // Show or hide the progress ring
    this.showProgressRing = shown => {
        this.progressRing.style.display = shown ? "inline-block" : "none";
    };

    // Update the address bar with the given text and remove focus
    this.updateAddressBar = text => {
        this.urlInput.value = text;
        this.urlInput.blur();
    };

    // Hide favicon when it fails to load
    this.favicon.addEventListener("error", () => {
        if (!this.favicon.src.startsWith("ms-appx://")) {
            this.hideFavicon();
        }
    });

    // Listen for the tweet button
    this.tweetIcon.addEventListener("click", () => {
        let domain = this.currentUrl ? new URI(this.currentUrl).domain : "microsoft.com";
        let path = "https://twitter.com/intent/tweet";
        let tags = ["UWPWebBrowser"].map(encodeURIComponent);
        let text = encodeURIComponent`I visited ${domain} in a browser built with HTML and JavaScript. Find out more here:`;
        let url = encodeURIComponent("https://github.com/MicrosoftEdge/UAPWebBrowser");
        this.navigateTo(`${path}?hashtags=${tags.join()}&text=${text}&url=${url}`);
    });

    // Listen for the loss of focus on the address bar to unselect the text
    this.urlInput.addEventListener("blur", () => getSelection().removeAllRanges());

    // Listen for focus on the address bar to auto-select the text
    // Use `setImmediate` to prevent the text from being immediately unselected
    this.urlInput.addEventListener("focus", e => setImmediate(() => e.target.select()));

    // Listen for the Enter key in the address bar to navigate to the specified URL
    this.urlInput.addEventListener("keypress", e => {
        if (e.keyCode === 13) {
            this.navigateTo(urlInput.value.trim());
        }
    });
});
<commit_msg>update regex for url validation<commit_after>browser.on("init", function () {
    "use strict";

    const LOC_CACHE = new Map;
    const URI = Windows.Foundation.Uri;
    const RE_VALIDATE_URL = /^[-:\.&#\+\(\)\[\]\$\'\*;@~!,\?%=\/\w]+$/;

    // Attempt a function
    function attempt(func) {
        try {
            return func();
        }
        catch (e) {
            return e;
        }
    }

    // Check if a file exists at the specified URL
    function fileExists(url) {
        return new Promise(resolve =>
            Windows.Web.Http.HttpClient()
                .getAsync(new URI(url), Windows.Web.Http.HttpCompletionOption.responseHeadersRead)
                .done(e => resolve(e.isSuccessStatusCode), () => resolve(false))
        );
    }

    // Navigate to the specified absolute URL
    function navigate(webview, url, silent) {
        let resp = attempt(() => webview.navigate(url));
        let result = !(resp instanceof Error);

        if (!silent && !result) {
            console.error(`Unable to navigate to ${url}: ${resp.message}`);
        }
        return result;
    }

    // Show the favicon if available
    this.getFavicon = loc => {
        let host = new URI(loc).host;

        // Exit for cached ico location
        if (this.faviconLocs.has(host)) {
            loc = this.faviconLocs.get(host);
            if (loc) {
                this.favicon.src = loc;
            }
            else {
                this.hideFavicon();
            }
            return;
        }
        let protocol = loc.split(":")[0];

        // Hide favicon when the host cannot be resolved or the protocol is not http(s)
        if (!protocol.startsWith("http") || !host) {
            this.faviconLocs.set(host, "");
            this.hideFavicon();
            return;
        }

        loc = `${protocol}://${host}/favicon.ico`;

        // Check if there is a favicon in the root directory
        fileExists(loc).then(exists => {
            if (exists) {
                console.log(`Favicon found: ${loc}`);
                this.faviconLocs.set(host, loc);
                this.favicon.src = loc;
                return;
            }
            // Asynchronously check for a favicon in the web page markup
            console.log("Favicon not found in root. Checking the markup...");
            let asyncOp = this.webview.invokeScriptAsync("eval", `
                Object(Array.from(document.getElementsByTagName('link'))
                  .find(link => link.rel.includes('icon'))).href
            `);
            asyncOp.oncomplete = e => {
                loc = e.target.result || "";
                this.faviconLocs.set(host, loc);

                if (loc) {
                    console.log(`Found favicon in markup: ${loc}`);
                    this.favicon.src = loc;
                }
                else {
                    this.hideFavicon();
                }
            };
            asyncOp.onerror = e => {
                console.error(`Unable to find favicon in markup: ${e.message}`);
                this.faviconLocs.set(host, "");
            };
            asyncOp.start();
        });
    };

    // Hide the favicon
    this.hideFavicon = () => {
        this.favicon.src = "";
    };

    // Navigate to the specified location
    this.navigateTo = loc => {
        loc = LOC_CACHE.get(loc) || loc;

        // Check if the input value contains illegal characters
        let isUrl = RE_VALIDATE_URL.test(loc);
        if (isUrl && navigate(this.webview, loc, true)) {
            return;
        }
        let bingLoc = `https://www.bing.com/search?q=${encodeURIComponent(loc)}`;
        let locHTTP = `http://${loc}`;
        let locHTTPS = `https://${loc}`;

        console.log(`Unable to navigate to ${loc}\nAttemping to prepend http(s):// to URI...`);

        let uri = attempt(() => new URI(locHTTP));
        let isErr = uri instanceof Error;

        if (isErr || !isUrl || !uri.domain) {
            let message = isErr ? uri.message : "";
            console.log(`Prepend unsuccessful\nQuerying bing.com... "${loc}": ${message}`);

            LOC_CACHE.set(loc, bingLoc);
            navigate(this.webview, bingLoc);
        }
        else {
            // Check if the site supports https
            fileExists(locHTTPS).then(exists => {
                if (exists) {
                    LOC_CACHE.set(loc, locHTTPS);
                    navigate(this.webview, locHTTPS);
                }
            });

            // Get a head start on loading via http
            LOC_CACHE.set(loc, locHTTP);
            navigate(this.webview, locHTTP);
        }
    };

    // Show or hide the progress ring
    this.showProgressRing = shown => {
        this.progressRing.style.display = shown ? "inline-block" : "none";
    };

    // Update the address bar with the given text and remove focus
    this.updateAddressBar = text => {
        this.urlInput.value = text;
        this.urlInput.blur();
    };

    // Hide favicon when it fails to load
    this.favicon.addEventListener("error", () => {
        if (!this.favicon.src.startsWith("ms-appx://")) {
            this.hideFavicon();
        }
    });

    // Listen for the tweet button
    this.tweetIcon.addEventListener("click", () => {
        let domain = this.currentUrl ? new URI(this.currentUrl).domain : "microsoft.com";
        let path = "https://twitter.com/intent/tweet";
        let tags = ["UWPWebBrowser"].map(encodeURIComponent);
        let text = encodeURIComponent`I visited ${domain} in a browser built with HTML and JavaScript. Find out more here:`;
        let url = encodeURIComponent("https://github.com/MicrosoftEdge/UAPWebBrowser");
        this.navigateTo(`${path}?hashtags=${tags.join()}&text=${text}&url=${url}`);
    });

    // Listen for the loss of focus on the address bar to unselect the text
    this.urlInput.addEventListener("blur", () => getSelection().removeAllRanges());

    // Listen for focus on the address bar to auto-select the text
    // Use `setImmediate` to prevent the text from being immediately unselected
    this.urlInput.addEventListener("focus", e => setImmediate(() => e.target.select()));

    // Listen for the Enter key in the address bar to navigate to the specified URL
    this.urlInput.addEventListener("keypress", e => {
        if (e.keyCode === 13) {
            this.navigateTo(urlInput.value.trim());
        }
    });
});
<|endoftext|>


<commit_before>import axios from 'axios';
import { push } from 'react-router-redux';
import { LOGGING_IN, LOGIN_SUCCESS, LOGIN_FAILURE } from './types';
import { apiURL } from './userSignUp';

const loggingIn = () => ({
  type: LOGGING_IN,
});

const loginSuccess = user => ({
  type: LOGIN_SUCCESS,
  user,
});

const loginFailure = error => ({
  type: LOGIN_FAILURE,
  error,
});

const loginUser = user => (dispatch) => {
  dispatch(loggingIn());
  return axios.post(`${apiURL}/users/login`, user)
    .then((response) => {
      localStorage.setItem('userToken', response.data.token);
      dispatch(loginSuccess(response.data.token));
      setTimeout(() => {
        dispatch(push('/'));
      }, 2000);
    })
    .catch((error) => {
      if (error.response) {
        let errorMessage = '';
        if (error.response.status === 401) {
          errorMessage = 'Incorrect email or password';
        } else if (error.response.status === 404) {
          errorMessage = 'User not found';
        } else {
          errorMessage = 'An error occured';
        }
        dispatch(loginFailure(errorMessage));
      } else {
        dispatch(loginFailure(error.message));
      }
    });
};

export default loginUser;

<commit_msg>Save user information in local storage<commit_after>import axios from 'axios';
import { push } from 'react-router-redux';
import { LOGGING_IN, LOGIN_SUCCESS, LOGIN_FAILURE } from './types';
import { apiURL } from './userSignUp';

const loggingIn = () => ({
  type: LOGGING_IN,
});

export const loginSuccess = user => ({
  type: LOGIN_SUCCESS,
  user,
});

const loginFailure = error => ({
  type: LOGIN_FAILURE,
  error,
});

const loginUser = user => (dispatch) => {
  dispatch(loggingIn());
  return axios.post(`${apiURL}/users/login`, user)
    .then((response) => {
      const userInfo = JSON.stringify(response.data.user);
      localStorage.setItem('userToken', response.data.token);
      localStorage.setItem('user', userInfo);
      dispatch(loginSuccess(response.data.user));
      setTimeout(() => {
        dispatch(push('/'));
      }, 2000);
    })
    .catch((error) => {
      if (error.response) {
        let errorMessage = '';
        if (error.response.status === 401) {
          errorMessage = 'Incorrect email or password';
        } else if (error.response.status === 404) {
          errorMessage = 'User not found';
        } else {
          errorMessage = 'An error occured';
        }
        dispatch(loginFailure(errorMessage));
      } else {
        dispatch(loginFailure(error.message));
      }
    });
};

export default loginUser;

<|endoftext|>


<commit_before>angular.module('app.auth', [])

.controller('AuthController', ['$scope', '$http', function($scope, $http){

  $scope.attemptedFirstName = '';
  $scope.attemptedLastName = '';
  $scope.attemptedUsername = '';
  $scope.attemptedPassword = '';

  $scope.showUnauthMsg = false;

  $scope.attemptLogin = function () {
    $scope.showUnauthMsg = false;
    $http.get('/api/login', {
      username: $scope.attemptedUsername,
      password: $scope.attemptedPassword
    })
    .then(
      //success callback
      function(res){
        console.log('sent login credentials');
        console.log('res.data', res.data);
        res.redirect('/#/dashboard?username=' + res.body.username);
      },
      //error callback
      function(res){
        console.log('res:', res);
        if(res.status === 401){
          console.log('unauthorized credentials');
          $scope.showUnauthMsg = true;
        }
      }
      );
  };

  $scope.attemptSignup = function () {
    $scope.showUnauthMsg = false;
    $http.post('/api/signup', {
      firstName: $scope.attemptedFirstName,
      lastName: $scope.attemptedLastName,
      username: $scope.attemptedUsername,
      password: $scope.attemptedPassword
    })
    .then(
      //success callback
      function(res){
        console.log('sent login credentials');
        console.log('res.data', res.data);
        res.redirect('/#/dashboard?username=' + res.body.username);
      },
      //error callback
      function(res){
        console.log('res:', res);
        if(res.status === 401){
          console.log('unauthorized credentials');
          $scope.showUnauthMsg = true;
        }
      }
      );
  };

}]);<commit_msg>sign up works<commit_after>angular.module('app.auth', [])

.controller('AuthController', ['$scope', '$http','$state', function($scope, $http, $state){

  $scope.attemptedFirstName = '';
  $scope.attemptedLastName = '';
  $scope.attemptedUsername = '';
  $scope.attemptedPassword = '';

  $scope.showUnauthMsg = false;

  $scope.attemptLogin = function () {
    $scope.showUnauthMsg = false;
    $http.get('/api/login', {
      username: $scope.attemptedUsername,
      password: $scope.attemptedPassword
    })
    .then(
      //success callback
      function(res){
        console.log('sent login credentials');
        console.log('res.data', res.data);
        $state.go('dashboard', {url: '/dashboard' + res.data.username});
      },
      //error callback
      function(res){
        console.log('res:', res);
        if(res.status === 401){
          console.log('unauthorized credentials');
          $scope.showUnauthMsg = true;
        }
      }
      );
  };

  $scope.attemptSignup = function () {
    $scope.showUnauthMsg = false;
    $http.post('/api/signup', {
      firstName: $scope.attemptedFirstName,
      lastName: $scope.attemptedLastName,
      username: $scope.attemptedUsername,
      password: $scope.attemptedPassword
    })
    .then(
      //success callback
      function(res){
        console.log('sent signup credentials');
        console.log('res.data', res.data);
        $state.go('dashboard', {url: '/dashboard' + res.data.username});
      },
      //error callback
      function(res){
        console.log('sent signup credentials');
        console.log('res.data', res.data);
        $state.go('dashboard', {url: '/dashboard' + res.data.username});
      }
      // function(res){
      //   console.log('res:', res);
      //   if(res.status === 401){
      //     console.log('invalid username');
      //     $scope.showUnauthMsg = true;
      //   }
      // }
      );
  };

}]);<|endoftext|>


<commit_before>var VXWORLD = (function() {
	var self = {};

	var sWidth, sHeight;

	var isShiftDown=false;
	var scene = new THREE.Scene();
	var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 5000 );
	var controls;
	var dirLight, hemiLight;
	var mixers = [];
	var renderer = new THREE.WebGLRenderer();

	var mouse = new THREE.Vector2();
	var raycaster = new THREE.Raycaster();

	var voxels = [];
	var objects = [];
	var rollOverMesh, rollOverMaterial;
	var cubeGeo, cubeMaterial;
	var plane;

	var sWidth = window.innerWidth;
	console.log(window.innerHeight);
	console.log(document.getElementById("headerElement").clientHeight);
	console.log(document.getElementById("footerElement").clientHeight);
	var sHeight = window.innerHeight - document.getElementById("headerElement").clientHeight - document.getElementById("footerElement").clientHeight;
	//document.getElementById("mainCanvas").domElement = renderer.domElement;
	document.getElementById("mainCanvasContainer").appendChild( renderer.domElement );

	rollOverGeo = new THREE.BoxGeometry( 1, 1, 1 );
	rollOverMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: 0.5, transparent: true } );
	rollOverMesh = new THREE.Mesh( rollOverGeo, rollOverMaterial );
	scene.add( rollOverMesh );

	cubeGeo = new THREE.BoxGeometry( 1, 1, 1 );
	cubeMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, morphTargets: true, vertexColors: THREE.FaceColors, shading: THREE.FlatShading } );

	var geometry = new THREE.BoxGeometry( 1, 1, 1 );
	var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, morphTargets: true, vertexColors: THREE.FaceColors, shading: THREE.FlatShading } );
	var cube = new THREE.Mesh( geometry, material );
	//scene.add( cube );

	// grid
	var size = 500, step = 10;
	var geometry = new THREE.Geometry();
	for ( var i = - size; i <= size; i += step ) {
		geometry.vertices.push( new THREE.Vector3( - size, 0, i ) );
		geometry.vertices.push( new THREE.Vector3(   size, 0, i ) );
		geometry.vertices.push( new THREE.Vector3( i, 0, - size ) );
		geometry.vertices.push( new THREE.Vector3( i, 0,   size ) );
	}
	var material = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2, transparent: true } );
	var line = new THREE.LineSegments( geometry, material );
	scene.add( line );

	// camera controls
	/*
	controls = new THREE.TrackballControls( camera );
	controls.rotateSpeed = 1.0;
	controls.zoomSpeed = 1.2;
	controls.panSpeed = 0.8;
	controls.noZoom = false;
	controls.noPan = false;
	controls.staticMoving = true;
	controls.dynamicDampingFactor = 0.3;
	*/
	camera.position.set( 5, 8, 13 );
	camera.lookAt( new THREE.Vector3() );
	//camera.position.z = 5;
	//cube.rotation.x += 0.4;

	scene.fog = new THREE.Fog( 0xffffff, 1, 5000 );
	scene.fog.color.setHSL( 0.6, 0, 1 );
	// LIGHTS
	hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
	hemiLight.color.setHSL( 0.6, 1, 0.6 );
	hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
	hemiLight.position.set( 0, 500, 0 );
	scene.add( hemiLight );

	dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
	dirLight.color.setHSL( 0.1, 1, 0.95 );
	dirLight.position.set( -1, 1.75, 1 );
	dirLight.position.multiplyScalar( 50 );
	scene.add( dirLight );
	dirLight.castShadow = true;
	dirLight.shadow.mapSize.width = 2048;
	dirLight.shadow.mapSize.height = 2048;

	var d = 50;
	dirLight.shadow.camera.left = -d;
	dirLight.shadow.camera.right = d;
	dirLight.shadow.camera.top = d;
	dirLight.shadow.camera.bottom = -d;
	dirLight.shadow.camera.far = 3500;
	dirLight.shadow.bias = -0.0001;

	// GROUND
	var groundGeo = new THREE.PlaneBufferGeometry( 10000, 10000 );
	var groundMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x050505 } );
	groundMat.color.setHSL( 0.095, 1, 0.75 );
	var ground = new THREE.Mesh( groundGeo, groundMat );
	ground.rotation.x = -Math.PI/2;
	ground.position.y = -33;
	scene.add( ground );
	ground.receiveShadow = true;

	// SKYDOME
	var vertexShader = document.getElementById( 'vertexShader' ).textContent;
	var fragmentShader = document.getElementById( 'fragmentShader' ).textContent;
	var uniforms = {
		topColor:    { value: new THREE.Color( 0x0077ff ) },
		bottomColor: { value: new THREE.Color( 0xffffff ) },
		offset:      { value: 33 },
		exponent:    { value: 0.6 }
	};
	uniforms.topColor.value.copy( hemiLight.color );
	scene.fog.color.copy( uniforms.bottomColor.value );
	var skyGeo = new THREE.SphereGeometry( 4000, 32, 15 );
	var skyMat = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide } );
	var sky = new THREE.Mesh( skyGeo, skyMat );
	scene.add( sky );

	var planegeometry = new THREE.PlaneBufferGeometry( 1000, 1000 );
	planegeometry.rotateX( - Math.PI / 2 );
	plane = new THREE.Mesh( planegeometry, new THREE.MeshBasicMaterial( { visible: false } ) );
	scene.add( plane );
	objects.push( plane );

	renderer.setClearColor( scene.fog.color );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( sWidth, sHeight );

	renderer.gammaInput = true;
	renderer.gammaOutput = true;
	renderer.shadowMap.enabled = true;
	renderer.shadowMap.renderReverseSided = false;

	var render = function () {

		requestAnimationFrame( render );

		//controls.update();

		//cube.rotation.y += 0.016;

		renderer.render(scene, camera);
	};

	renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
	renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
	renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
	renderer.domElement.addEventListener( 'keydown', onDocumentKeyDown, false );
	renderer.domElement.addEventListener( 'keyup', onDocumentKeyUp, false );

	window.addEventListener( 'resize', onWindowResize, false );

	function onDocumentMouseMove(event) {
		event.preventDefault();
		mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );
		raycaster.setFromCamera( mouse, camera );
		var intersects = raycaster.intersectObjects( objects );
		console.log(intersects);
		if ( intersects.length > 0 ) {

			var intersect = intersects[ 0 ];
			rollOverMesh.position.copy( intersect.point ).add( intersect.face.normal );
			rollOverMesh.position.divideScalar( 1 ).floor().multiplyScalar( 1 ).addScalar( 0.5 );
		}

	}

	function onDocumentMouseDown(event) {
		event.preventDefault();

		mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );
		raycaster.setFromCamera( mouse, camera );

		var intersects = raycaster.intersectObjects( objects );

		if ( intersects.length > 0 ) {
			var intersect = intersects[ 0 ];
			// delete cube
			if ( isShiftDown ) {
				if ( intersect.object != plane ) {
					scene.remove( intersect.object );
					objects.splice( objects.indexOf( intersect.object ), 1 );
				}
			// create cube
			} else {
				var voxel = new THREE.Mesh( cubeGeo, cubeMaterial );
				voxel.position.copy( intersect.point ).add( intersect.face.normal );
				voxel.position.divideScalar( 1 ).floor().multiplyScalar( 1 ).addScalar( 0.5 );
				scene.add( voxel );
				objects.push( voxel );
			}

		}

	}

	function onDocumentMouseUp(event) {

	}

	function onDocumentKeyDown( event ) {
		switch( event.keyCode ) {
			case 16: isShiftDown = true; break;
		}
	}

	function onDocumentKeyUp (event) {
		switch( event.keyCode ) {
			case 16: isShiftDown = false; break;
		}
	}

	function onWindowResize() {
		sWidth = window.innerWidth;
		sHeight = window.innerHeight - document.getElementById("headerElement").clientHeight - document.getElementById("footerElement").clientHeight;
		camera.aspect = sWidth / sHeight;
		camera.updateProjectionMatrix();
		renderer.setSize( sWidth, sHeight );
	}

	render();

	return self;
});

var VXVoxel = (function(){
	var self = this;

	return self;
});<commit_msg>Apparently there are changes<commit_after>var VXWORLD = (function() {
	var self = {};

	var sWidth, sHeight;

	var isShiftDown=false;
	var scene = new THREE.Scene();
	var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 5000 );
	var controls;
	var dirLight, hemiLight;
	var mixers = [];
	var renderer = new THREE.WebGLRenderer();

	var mouse = new THREE.Vector2();
	var raycaster = new THREE.Raycaster();

	var voxels = [];
	var objects = [];
	var rollOverMesh, rollOverMaterial;
	var cubeGeo, cubeMaterial;
	var plane;

	var sWidth = window.innerWidth;
	console.log(window.innerHeight);
	console.log(document.getElementById("headerElement").clientHeight);
	console.log(document.getElementById("footerElement").clientHeight);
	var sHeight = window.innerHeight - document.getElementById("headerElement").clientHeight - document.getElementById("footerElement").clientHeight;
	//document.getElementById("mainCanvas").domElement = renderer.domElement;
	document.getElementById("mainCanvasContainer").appendChild( renderer.domElement );

	rollOverGeo = new THREE.BoxGeometry( 1, 1, 1 );
	rollOverMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: 0.5, transparent: true } );
	rollOverMesh = new THREE.Mesh( rollOverGeo, rollOverMaterial );
	scene.add( rollOverMesh );

	cubeGeo = new THREE.BoxGeometry( 1, 1, 1 );
	cubeMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, morphTargets: true, vertexColors: THREE.FaceColors, shading: THREE.FlatShading } );

	var geometry = new THREE.BoxGeometry( 1, 1, 1 );
	var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, morphTargets: true, vertexColors: THREE.FaceColors, shading: THREE.FlatShading } );
	var cube = new THREE.Mesh( geometry, material );
	//scene.add( cube );

	// grid
	var size = 50, step = 1;
	var geometry = new THREE.Geometry();
	for ( var i = - size; i <= size; i += step ) {
		geometry.vertices.push( new THREE.Vector3( - size, 0, i ) );
		geometry.vertices.push( new THREE.Vector3(   size, 0, i ) );
		geometry.vertices.push( new THREE.Vector3( i, 0, - size ) );
		geometry.vertices.push( new THREE.Vector3( i, 0,   size ) );
	}
	var material = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2, transparent: true } );
	var line = new THREE.LineSegments( geometry, material );
	scene.add( line );

	// camera controls

	controls = new THREE.TrackballControls( camera );
	controls.rotateSpeed = 1.0;
	controls.zoomSpeed = 1.2;
	controls.panSpeed = 0.8;
	controls.noZoom = false;
	controls.noPan = false;
	controls.staticMoving = true;
	controls.dynamicDampingFactor = 0.3;

	camera.position.set( 5, 8, 13 );
	camera.lookAt( new THREE.Vector3() );
	//camera.position.z = 5;
	//cube.rotation.x += 0.4;

	scene.fog = new THREE.Fog( 0xffffff, 1, 5000 );
	scene.fog.color.setHSL( 0.6, 0, 1 );
	// LIGHTS
	hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
	hemiLight.color.setHSL( 0.6, 1, 0.6 );
	hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
	hemiLight.position.set( 0, 500, 0 );
	scene.add( hemiLight );

	dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
	dirLight.color.setHSL( 0.1, 1, 0.95 );
	dirLight.position.set( -1, 1.75, 1 );
	dirLight.position.multiplyScalar( 50 );
	scene.add( dirLight );
	dirLight.castShadow = true;
	dirLight.shadow.mapSize.width = 2048;
	dirLight.shadow.mapSize.height = 2048;

	var d = 50;
	dirLight.shadow.camera.left = -d;
	dirLight.shadow.camera.right = d;
	dirLight.shadow.camera.top = d;
	dirLight.shadow.camera.bottom = -d;
	dirLight.shadow.camera.far = 3500;
	dirLight.shadow.bias = -0.0001;

	// GROUND
	var groundGeo = new THREE.PlaneBufferGeometry( 10000, 10000 );
	var groundMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x050505 } );
	groundMat.color.setHSL( 0.095, 1, 0.75 );
	var ground = new THREE.Mesh( groundGeo, groundMat );
	ground.rotation.x = -Math.PI/2;
	ground.position.y = -33;
	scene.add( ground );
	ground.receiveShadow = true;

	// SKYDOME
	var vertexShader = document.getElementById( 'vertexShader' ).textContent;
	var fragmentShader = document.getElementById( 'fragmentShader' ).textContent;
	var uniforms = {
		topColor:    { value: new THREE.Color( 0x0077ff ) },
		bottomColor: { value: new THREE.Color( 0xffffff ) },
		offset:      { value: 33 },
		exponent:    { value: 0.6 }
	};
	uniforms.topColor.value.copy( hemiLight.color );
	scene.fog.color.copy( uniforms.bottomColor.value );
	var skyGeo = new THREE.SphereGeometry( 4000, 32, 15 );
	var skyMat = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide } );
	var sky = new THREE.Mesh( skyGeo, skyMat );
	scene.add( sky );

	var planegeometry = new THREE.PlaneBufferGeometry( 1000, 1000 );
	planegeometry.rotateX( - Math.PI / 2 );
	plane = new THREE.Mesh( planegeometry, new THREE.MeshBasicMaterial( { visible: false } ) );
	scene.add( plane );
	objects.push( plane );

	renderer.setClearColor( scene.fog.color );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( sWidth, sHeight );

	renderer.gammaInput = true;
	renderer.gammaOutput = true;
	renderer.shadowMap.enabled = true;
	renderer.shadowMap.renderReverseSided = false;

	var render = function () {

		requestAnimationFrame( render );

		controls.update();

		//cube.rotation.y += 0.016;

		renderer.render(scene, camera);
	};

	renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
	renderer.domElement.addEventListener( 'mouseup', onDocumentMouseDown, false );
	renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
	renderer.domElement.addEventListener( 'keydown', onDocumentKeyDown, false );
	renderer.domElement.addEventListener( 'keyup', onDocumentKeyUp, false );

	window.addEventListener( 'resize', onWindowResize, false );

	function onDocumentMouseMove(event) {
		event.preventDefault();
		mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );
		raycaster.setFromCamera( mouse, camera );
		var intersects = raycaster.intersectObjects( objects );
		console.log(intersects);
		if ( intersects.length > 0 ) {

			var intersect = intersects[ 0 ];
			rollOverMesh.position.copy( intersect.point ).add( intersect.face.normal );
			//rollOverMesh.position.addScalar( 0.5 );
			rollOverMesh.position.divideScalar( 1 ).floor().multiplyScalar( 1 );//.addScalar( 0.5 );
		}

	}

	function onDocumentMouseDown(event) {
		event.preventDefault();

		mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );
		raycaster.setFromCamera( mouse, camera );

		var intersects = raycaster.intersectObjects( objects );

		if ( intersects.length > 0 ) {
			var intersect = intersects[ 0 ];
			// delete cube
			if ( isShiftDown ) {
				if ( intersect.object != plane ) {
					scene.remove( intersect.object );
					objects.splice( objects.indexOf( intersect.object ), 1 );
				}
			// create cube
			} else {
				var voxel = new THREE.Mesh( cubeGeo, cubeMaterial );
				voxel.position.copy( intersect.point ).add( intersect.face.normal );
				voxel.position.divideScalar( 1 ).floor().multiplyScalar( 1 );//.addScalar( 0.5 );
				scene.add( voxel );
				objects.push( voxel );
			}

		}

	}

	function onDocumentMouseUp(event) {

	}

	function onDocumentKeyDown( event ) {
		switch( event.keyCode ) {
			case 16: isShiftDown = true; break;
		}
	}

	function onDocumentKeyUp (event) {
		switch( event.keyCode ) {
			case 16: isShiftDown = false; break;
		}
	}

	function onWindowResize() {
		sWidth = window.innerWidth;
		sHeight = window.innerHeight - document.getElementById("headerElement").clientHeight - document.getElementById("footerElement").clientHeight;
		camera.aspect = sWidth / sHeight;
		camera.updateProjectionMatrix();
		renderer.setSize( sWidth, sHeight );
	}

	render();

	return self;
});

var VXVoxel = (function(){
	var self = this;

	return self;
});<|endoftext|>


<commit_before>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import { formatThousands } from 'common/format';

import Module from 'Parser/Core/Module';

import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';

const debug = false;

class DistanceMoved extends Module {
  lastPositionUpdate = null;
  totalDistanceMoved = 0;

  // Events
  on_cast(event) {
    this.updatePlayerPosition(event);
  }

  on_damage(event) {
    this.updatePlayerPosition(event);
  }

  on_energize(event) {
    this.updatePlayerPosition(event);
  }

  on_heal(event) {
    this.updatePlayerPosition(event);
  }

  on_absorbed(event) {
    this.updatePlayerPosition(event);
  }

  // Data parsing
  calculateDistance(x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / 100;
  }

  updateTotalDistance(event) {
    if (!this.lastPositionUpdate) {
      return;
    }
    this.totalDistanceMoved += this.calculateDistance(this.lastPositionUpdate.x, this.lastPositionUpdate.y, event.x, event.y);
  }

  updatePlayerPosition(event) {
    if (!event.x || !event.y) {
      return;
    }
    this.updateTotalDistance(event);
    this.lastPositionUpdate = event;
  }

  statistic() {
    debug && console.log(`Total distance moved: ${this.totalDistanceMoved} yds`);
    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.FRENETIC_SPEED_TALENT.id} />}
        value={`≈${formatThousands(this.totalDistanceMoved)} yards`}
        label="Distance moved during fight"
        tooltip="Consider this when analyzing the fight, as some fights require more movement than others. Unnecessary movement can result in a DPS/HPS loss."
      />
    );
  }

  // Move to the very end of the optional statistics
  statisticOrder = STATISTIC_ORDER.OPTIONAL(99);
}

export default DistanceMoved;
<commit_msg>Show yards per minute in tooltip<commit_after>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import { formatThousands } from 'common/format';

import Module from 'Parser/Core/Module';

import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';

const debug = false;

class DistanceMoved extends Module {
  lastPositionUpdate = null;
  totalDistanceMoved = 0;

  // Events
  on_cast(event) {
    this.updatePlayerPosition(event);
  }

  on_damage(event) {
    this.updatePlayerPosition(event);
  }

  on_energize(event) {
    this.updatePlayerPosition(event);
  }

  on_heal(event) {
    this.updatePlayerPosition(event);
  }

  on_absorbed(event) {
    this.updatePlayerPosition(event);
  }

  // Data parsing
  calculateDistance(x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / 100;
  }

  updateTotalDistance(event) {
    if (!this.lastPositionUpdate) {
      return;
    }
    this.totalDistanceMoved += this.calculateDistance(this.lastPositionUpdate.x, this.lastPositionUpdate.y, event.x, event.y);
  }

  updatePlayerPosition(event) {
    if (!event.x || !event.y) {
      return;
    }
    this.updateTotalDistance(event);
    this.lastPositionUpdate = event;
  }

  statistic() {
    debug && console.log(`Total distance moved: ${this.totalDistanceMoved} yds`);
    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.FRENETIC_SPEED_TALENT.id} />}
        value={`≈${formatThousands(this.totalDistanceMoved)} yards`}
        label="Distance moved during fight"
        tooltip={`≈${formatThousands(this.totalDistanceMoved / (this.owner.fightDuration / 1000) * 60)} yards per minute. Consider this when analyzing the fight, as some fights require more movement than others. Unnecessary movement can result in a DPS/HPS loss.`}
      />
    );
  }

  // Move to the very end of the optional statistics
  statisticOrder = STATISTIC_ORDER.OPTIONAL(99);
}

export default DistanceMoved;
<|endoftext|>


<commit_before>$(function(){
  $.widget( "custom.catcomplete", $.ui.autocomplete, {
    _create: function() {
      this._super();
      this.widget().menu( "option", "items", "> :not(.ui-autocomplete-category)" );
    },
    _renderMenu: function( ul, items ) {
      var that = this,
      currentCategory = "";
      function sortBy(a, b) {
        if (a.category.toLowerCase()  b.category.toLowerCase()) {
          return 1;
        } else if (a.value.toLowerCase()  b.value.toLowerCase()) {
          return 1;
        } else {
          return 0;
        }
      }
      $.each( items.sort(sortBy), function( index, item ) {
        var li;
        if ( item.category != currentCategory ) {
          ul.append( "
" + item.category + "
" );
          currentCategory = item.category;
        }
        li = that._renderItemData( ul, item );
        if ( item.category ) {
          li.attr( "aria-label", item.category + " : " + item.label );
        }
      });
    }
  });
  $("#query").attr('placeholder', 'Search').catcomplete({
      response: function( e, ui ) {
        if ( ! ui.content.length ) {
            $('#search').addClass('not-found')
                .find('#try-web-search').attr(
                    'href', 'https://www.google.com/search?q=site%3Adocs.perl6.org+'
                    + encodeURIComponent( $("#query").val() )
                );
        }
        else {
            $('#search').removeClass('not-found')
        }
      },
      open: function() {
        var ui_el = $('.ui-autocomplete');
        if ( ui_el.offset().left < 0 ) {
            ui_el.css({left: 0})
        }
      },
      position: { my: "right top", at: "right bottom", of: "#search div" },
      source: [
ITEMS
      ],
      select: function (event, ui) { window.location.href = ui.item.url; },
      autoFocus: true
  });
});
<commit_msg>change default value for #query in the template<commit_after>$(function(){
  $.widget( "custom.catcomplete", $.ui.autocomplete, {
    _create: function() {
      this._super();
      this.widget().menu( "option", "items", "> :not(.ui-autocomplete-category)" );
    },
    _renderMenu: function( ul, items ) {
      var that = this,
      currentCategory = "";
      function sortBy(a, b) {
        if (a.category.toLowerCase()  b.category.toLowerCase()) {
          return 1;
        } else if (a.value.toLowerCase()  b.value.toLowerCase()) {
          return 1;
        } else {
          return 0;
        }
      }
      $.each( items.sort(sortBy), function( index, item ) {
        var li;
        if ( item.category != currentCategory ) {
          ul.append( "
" + item.category + "
" );
          currentCategory = item.category;
        }
        li = that._renderItemData( ul, item );
        if ( item.category ) {
          li.attr( "aria-label", item.category + " : " + item.label );
        }
      });
    }
  });
  $("#query").attr('placeholder', '🔍').catcomplete({
      response: function( e, ui ) {
        if ( ! ui.content.length ) {
            $('#search').addClass('not-found')
                .find('#try-web-search').attr(
                    'href', 'https://www.google.com/search?q=site%3Adocs.perl6.org+'
                    + encodeURIComponent( $("#query").val() )
                );
        }
        else {
            $('#search').removeClass('not-found')
        }
      },
      open: function() {
        var ui_el = $('.ui-autocomplete');
        if ( ui_el.offset().left < 0 ) {
            ui_el.css({left: 0})
        }
      },
      position: { my: "right top", at: "right bottom", of: "#search div" },
      source: [
ITEMS
      ],
      select: function (event, ui) { window.location.href = ui.item.url; },
      autoFocus: true
  });
});
<|endoftext|>