<commit_before>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// @brief Foxx application module
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Michael Hackstein
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                           imports
// -----------------------------------------------------------------------------

var fs = require("fs");
var internal = require("internal");
var db = internal.db;
var joi = require("joi");
var _= require("underscore");
var utils = require("org/arangodb/foxx/manager-utils");
var console = require("console");
var arangodb = require("org/arangodb");
var ArangoError = arangodb.ArangoError;
var errors = arangodb.errors;
var throwFileNotFound = arangodb.throwFileNotFound;

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

function applyDefaultConfig(config, parse) {
  var res = {};
  if (config !== undefined) {
    Object.keys(config).forEach(function (key) {
      if (config[key].default !== undefined) {
        res[key] = config[key].default;
        if (!parse && config[key].type === 'json') {
          res[key] = JSON.stringify(res[key]);
        }
      }
    });
  }
  return res;
}

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                        AppContext
// -----------------------------------------------------------------------------

function AppContext(app) {
  var prefix = fs.safeJoin(app._root, app._path);

  this._prefix = prefix;
  this.comments = [];
  this.name = app._name;
  this.version = app._version;
  this.mount = app._mount;
  this.collectionPrefix = app._collectionPrefix;
  this.options = app._options;
  this.configuration = app._configuration;
  this.dependencies = app._dependencies;
  this.basePath = prefix;
  this.baseUrl = '/_db/' + encodeURIComponent(db._name()) + app._mount;
  this.isDevelopment = app._isDevelopment;
  this.isProduction = ! app._isDevelopment;
  this.manifest = app._manifest;
}

AppContext.prototype.foxxFilename = function (path) {
  return fs.safeJoin(this._prefix, path);
};

AppContext.prototype.collectionName = function (name) {
  var replaced = this.collectionPrefix.replace(/[:\.]+/g, '_') +
                 name.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);

  if (replaced.length === 0) {
    throw new Error("Cannot derive collection name from '" + name + "'");
  }

  return replaced;
};

AppContext.prototype.collection = function (name) {
  return db._collection(this.collectionName(name));
};

AppContext.prototype.path = function (name) {
  return fs.join(this._prefix, name);
};

AppContext.prototype.comment = function (str) {
  this.comments.push(str);
};

AppContext.prototype.clearComments = function () {
  this.comments = [];
};

// -----------------------------------------------------------------------------
// --SECTION--                                                         ArangoApp
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief Checks if the mountpoint is reserved for system apps
////////////////////////////////////////////////////////////////////////////////

function isSystemMount(mount) {
return (/^\/_/).test(mount);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the root path for application. Knows about system apps
////////////////////////////////////////////////////////////////////////////////

function computeRootAppPath(mount, isValidation) {
if (isValidation) {
  return "";
}
if (isSystemMount(mount)) {
  return module.systemAppPath();
}
return module.appPath();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoApp constructor
////////////////////////////////////////////////////////////////////////////////

function ArangoApp(config) {
  if (config.error) {
    this._error = config.error;
    this._isBroken = true;
  }
  this._manifest = config.manifest || {
    name: "unknown",
    version: "error"
  };
  if (!this._manifest.configuration) {
    this._manifest.configuration = {};
  }
  if (!this._manifest.dependencies) {
    this._manifest.dependencies = {};
  }
  this._name = this._manifest.name;
  this._version = this._manifest.version;
  this._root = computeRootAppPath(config.mount, config.id === "__internal");
  this._path = config.path;
  this._options = config.options;
  this._mount = config.mount;
  this._isSystem = config.isSystem || false;
  this._isDevelopment = config.isDevelopment || false;
  this._exports = {};
  this._collectionPrefix = this._mount.substr(1).replace(/-/g, "_").replace(/\//g, "_") + "_";

  // Apply the default configuration and ignore all missing options
  var cfg = config.options.configuration;
  this._options.configuration = applyDefaultConfig(this._manifest.configuration);
  this._configuration = applyDefaultConfig(this._manifest.configuration, true);
  this.configure(cfg);

  var deps = config.options.dependencies;
  this._options.dependencies = {};
  this._dependencies = {};
  this.updateDeps(deps);

  this._context = new AppContext(this);
  this._context.appPackage = module.createAppPackage(this);
  this._context.appModule = this._context.appPackage.createAppModule(this);

  if (! this._manifest.hasOwnProperty("defaultDocument")) {
    this._manifest.defaultDocument = "index.html";
  }
  if (this._manifest.hasOwnProperty("thumbnail")) {
    var thumbfile = fs.join(this._root, this._path, this._manifest.thumbnail);
    try {
      this._thumbnail = fs.read64(thumbfile);
    } catch (err) {
      console.warnLines(
        "Cannot read thumbnail '%s' : %s", thumbfile, err);
    }
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief prints a package
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype._PRINT = function (context) {
  context.output += '[app "' + this._name + '" (' + this._version + ')]';
};

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief creates a Json representation of itself to be persisted
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.toJSON = function () {
  var json = {
    manifest: this._manifest,
    name: this._name,
    version: this._version,
    path: this._path,
    options: this._options,
    mount: this._mount,
    root: this._root,
    isSystem: this._isSystem,
    isDevelopment: this._isDevelopment
  };
  if (this.hasOwnProperty("_error")) {
    json.error = this._error;
  }
  if (this._manifest.hasOwnProperty("author")) {
    json.author = this._manifest.author;
  }
  if (this._manifest.hasOwnProperty("description")) {
    json.description = this._manifest.description;
  }
  if (this.hasOwnProperty("_thumbnail")) {
    json.thumbnail = this._thumbnail;
  }

  return json;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief creates a reduced Json representation of itself for output
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.simpleJSON = function () {
  var json = {
    name: this._name,
    version: this._version,
    mount: this._mount
  };
  return json;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief toggles development mode
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.development = function(activate) {
  this._isDevelopment = activate;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief set app dependencies
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.updateDeps = function (deps) {
  var expected = this._manifest.dependencies;
  var invalid = [];

  _.each(deps, function (mount, name) {
    if (!expected[name]) {
      invalid.push("Unexpected dependency " + name);
    }
    this._options.dependencies[name] = mount;
  }, this);

  _.each(this._options.dependencies, function (mount, name) {
    Object.defineProperty(this._dependencies, name, {
      configurable: true,
      enumerable: true,
      get: function () {
        return require("org/arangodb/foxx").requireApp(mount);
      }
    });
  }, this);

  return invalid;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief set app configuration
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.configure = function(config) {
  var expected = this._manifest.configuration;
  var invalid = [];
  this._options.configuration = this._options.configuration || {};

  _.each(config, function (rawValue, name) {
    if (!expected[name]) {
      invalid.push("Unexpected Option " + name);
    } else {
      var value = rawValue;
      var type = expected[name].type;
      var schema = utils.parameterTypes[type];
      var error;
      var result;
      if (expected[name].required !== false) {
        result = joi.any().required().validate(value);
        if (result.error) {
          error = result.error.message.replace(/^"value"/, '"' + name + '"');
        }
      }
      if (!error) {
        if (schema.isJoi) {
          result = schema.optional().allow(null).validate(value);
          if (result.error) {
            error = result.error.message.replace(/^"value"/, '"' + name + '"');
          }
          value = result.value;
        } else {
          try {
            value = schema(value);
          } catch (e) {
            error = '"' + name + '": ' + e.message;
          }
        }
      }
      if (error) {
        invalid.push(error);
      } else {
        this._options.configuration[name] = rawValue;
        this._configuration[name] = value;
      }
    }
  }, this);

  return invalid;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief get app configuration
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.getConfiguration = function (simple) {
  var config = {};
  var definitions = this._manifest.configuration;
  var options = this._options.configuration;
  _.each(definitions, function (dfn, name) {
    var value = options[name] === undefined ? dfn.default : options[name];
    config[name] = simple ? value : _.extend(_.clone(dfn), {
      title: utils.getReadableName(name),
      current: value
    });
  });
  return config;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief get app dependencies
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.getDependencies = function(simple) {
  var deps = {};
  var definitions = this._manifest.dependencies;
  var options = this._options.dependencies;
  _.each(definitions, function (dfn, name) {
    deps[name] = simple ? options[name] : {
      definition: dfn,
      title: utils.getReadableName(name),
      current: options[name]
    };
  });
  return deps;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief App needs to be configured
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.needsConfiguration = function() {
  var config = this.getConfiguration();
  var deps = this.getDependencies();
  return _.any(config, function (cfg) {
    return cfg.current === undefined;
  }) || _.any(deps, function (dep) {
    return dep.current === undefined;
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief loadAppScript
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.loadAppScript = function (filename, options) {
  options = options || {};

  var appContext = _.extend({}, options.appContext, this._context);
  var full = fs.join(this._root, this._path, filename);

  if (!fs.exists(full)) {
    throwFileNotFound(full);
  }

  var fileContent = fs.read(full);

  if (options.transform) {
    fileContent = options.transform(fileContent);
  } else if (/\.coffee$/.test(filename)) {
    var cs = require("coffee-script");
    fileContent = cs.compile(fileContent, {bare: true});
  }

  var context = {};

  if (options.context) {
    Object.keys(options.context).forEach(function (key) {
      context[key] = options.context[key];
    });
  }

  var localModule = appContext.appPackage.createAppModule(this, filename);

  context.__filename = full;
  context.__dirname = module.normalizeModuleName(full + "/..");
  context.console = require("org/arangodb/foxx/console")(this._mount);
  context.applicationContext = appContext;

  try {
    return localModule.run(fileContent, context);
  } catch(e) {
    if (e instanceof ArangoError) {
      throw e;
    }
    var err = new ArangoError({
      errorNum: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.code,
      errorMessage: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.message
      + "\nFile: " + filename
    });
    err.stack = e.stack;
    err.cause = e;
    throw err;
  }
};

exports.ArangoApp = ArangoApp;

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
// End:
<commit_msg>Fixed manifest default values.<commit_after>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// @brief Foxx application module
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Michael Hackstein
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                           imports
// -----------------------------------------------------------------------------

var fs = require("fs");
var internal = require("internal");
var db = internal.db;
var joi = require("joi");
var _= require("underscore");
var utils = require("org/arangodb/foxx/manager-utils");
var console = require("console");
var arangodb = require("org/arangodb");
var ArangoError = arangodb.ArangoError;
var errors = arangodb.errors;
var throwFileNotFound = arangodb.throwFileNotFound;

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

function applyDefaultConfig(config, parse) {
  var res = {};
  if (config !== undefined) {
    Object.keys(config).forEach(function (key) {
      if (config[key].default !== undefined) {
        res[key] = config[key].default;
        if (!parse && config[key].type === 'json') {
          res[key] = JSON.stringify(res[key]);
        }
      }
    });
  }
  return res;
}

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                        AppContext
// -----------------------------------------------------------------------------

function AppContext(app) {
  var prefix = fs.safeJoin(app._root, app._path);

  this._prefix = prefix;
  this.comments = [];
  this.name = app._name;
  this.version = app._version;
  this.mount = app._mount;
  this.collectionPrefix = app._collectionPrefix;
  this.options = app._options;
  this.configuration = app._configuration;
  this.dependencies = app._dependencies;
  this.basePath = prefix;
  this.baseUrl = '/_db/' + encodeURIComponent(db._name()) + app._mount;
  this.isDevelopment = app._isDevelopment;
  this.isProduction = ! app._isDevelopment;
  this.manifest = app._manifest;
}

AppContext.prototype.foxxFilename = function (path) {
  return fs.safeJoin(this._prefix, path);
};

AppContext.prototype.collectionName = function (name) {
  var replaced = this.collectionPrefix.replace(/[:\.]+/g, '_') +
                 name.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);

  if (replaced.length === 0) {
    throw new Error("Cannot derive collection name from '" + name + "'");
  }

  return replaced;
};

AppContext.prototype.collection = function (name) {
  return db._collection(this.collectionName(name));
};

AppContext.prototype.path = function (name) {
  return fs.join(this._prefix, name);
};

AppContext.prototype.comment = function (str) {
  this.comments.push(str);
};

AppContext.prototype.clearComments = function () {
  this.comments = [];
};

// -----------------------------------------------------------------------------
// --SECTION--                                                         ArangoApp
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief Checks if the mountpoint is reserved for system apps
////////////////////////////////////////////////////////////////////////////////

function isSystemMount(mount) {
return (/^\/_/).test(mount);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the root path for application. Knows about system apps
////////////////////////////////////////////////////////////////////////////////

function computeRootAppPath(mount, isValidation) {
if (isValidation) {
  return "";
}
if (isSystemMount(mount)) {
  return module.systemAppPath();
}
return module.appPath();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoApp constructor
////////////////////////////////////////////////////////////////////////////////

function ArangoApp(config) {
  if (config.error) {
    this._error = config.error;
    this._isBroken = true;
  }
  this._manifest = config.manifest || {
    name: "unknown",
    version: "error"
  };
  if (!this._manifest.configuration) {
    this._manifest.configuration = {};
  }
  if (!this._manifest.dependencies) {
    this._manifest.dependencies = {};
  }
  this._name = this._manifest.name;
  this._version = this._manifest.version;
  this._root = computeRootAppPath(config.mount, config.id === "__internal");
  this._path = config.path;
  this._options = config.options;
  this._mount = config.mount;
  this._isSystem = config.isSystem || false;
  this._isDevelopment = config.isDevelopment || false;
  this._exports = {};
  this._collectionPrefix = this._mount.substr(1).replace(/-/g, "_").replace(/\//g, "_") + "_";

  // Apply the default configuration and ignore all missing options
  var cfg = config.options.configuration;
  this._options.configuration = applyDefaultConfig(this._manifest.configuration);
  this._configuration = applyDefaultConfig(this._manifest.configuration, true);
  this.configure(cfg);

  var deps = config.options.dependencies;
  this._options.dependencies = {};
  this._dependencies = {};
  this.updateDeps(deps);

  this._context = new AppContext(this);
  this._context.appPackage = module.createAppPackage(this);
  this._context.appModule = this._context.appPackage.createAppModule(this);

  if (! this._manifest.hasOwnProperty("defaultDocument")) {
    this._manifest.defaultDocument = "index.html";
  }
  if (this._manifest.hasOwnProperty("thumbnail")) {
    var thumbfile = fs.join(this._root, this._path, this._manifest.thumbnail);
    try {
      this._thumbnail = fs.read64(thumbfile);
    } catch (err) {
      console.warnLines(
        "Cannot read thumbnail '%s' : %s", thumbfile, err);
    }
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief prints a package
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype._PRINT = function (context) {
  context.output += '[app "' + this._name + '" (' + this._version + ')]';
};

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief creates a Json representation of itself to be persisted
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.toJSON = function () {
  var json = {
    manifest: this._manifest,
    name: this._name,
    version: this._version,
    path: this._path,
    options: this._options,
    mount: this._mount,
    root: this._root,
    isSystem: this._isSystem,
    isDevelopment: this._isDevelopment
  };
  if (this.hasOwnProperty("_error")) {
    json.error = this._error;
  }
  if (this._manifest.hasOwnProperty("author")) {
    json.author = this._manifest.author;
  }
  if (this._manifest.hasOwnProperty("description")) {
    json.description = this._manifest.description;
  }
  if (this.hasOwnProperty("_thumbnail")) {
    json.thumbnail = this._thumbnail;
  }

  return json;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief creates a reduced Json representation of itself for output
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.simpleJSON = function () {
  var json = {
    name: this._name,
    version: this._version,
    mount: this._mount
  };
  return json;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief toggles development mode
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.development = function(activate) {
  this._isDevelopment = activate;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief set app dependencies
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.updateDeps = function (deps) {
  var expected = this._manifest.dependencies;
  var invalid = [];

  _.each(deps, function (mount, name) {
    if (!expected[name]) {
      invalid.push("Unexpected dependency " + name);
    }
    this._options.dependencies[name] = mount;
  }, this);

  _.each(this._options.dependencies, function (mount, name) {
    Object.defineProperty(this._dependencies, name, {
      configurable: true,
      enumerable: true,
      get: function () {
        return require("org/arangodb/foxx").requireApp(mount);
      }
    });
  }, this);

  return invalid;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief set app configuration
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.configure = function(config) {
  var expected = this._manifest.configuration;
  var invalid = [];
  this._options.configuration = this._options.configuration || {};

  _.each(config, function (rawValue, name) {
    if (!expected[name]) {
      invalid.push("Unexpected Option " + name);
    } else {
      var value = rawValue;
      var type = expected[name].type;
      var schema = utils.parameterTypes[type];
      var error;
      var result;
      if (expected[name].required !== false) {
        result = joi.any().required().validate(value);
        if (result.error) {
          error = result.error.message.replace(/^"value"/, '"' + name + '"');
        }
      }
      if (!error) {
        if (schema.isJoi) {
          schema = schema.optional().allow(null);
          if (expected[name].default !== undefined) {
            schema = schema.default(expected[name].default);
          }
          result = schema.validate(value);
          if (result.error) {
            error = result.error.message.replace(/^"value"/, '"' + name + '"');
          }
          value = result.value;
        } else {
          try {
            value = schema(value);
          } catch (e) {
            error = '"' + name + '": ' + e.message;
          }
        }
      }
      if (error) {
        invalid.push(error);
      } else {
        this._options.configuration[name] = rawValue;
        this._configuration[name] = value;
      }
    }
  }, this);

  return invalid;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief get app configuration
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.getConfiguration = function (simple) {
  var config = {};
  var definitions = this._manifest.configuration;
  var options = this._options.configuration;
  _.each(definitions, function (dfn, name) {
    var value = options[name] === undefined ? dfn.default : options[name];
    config[name] = simple ? value : _.extend(_.clone(dfn), {
      title: utils.getReadableName(name),
      current: value
    });
  });
  return config;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief get app dependencies
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.getDependencies = function(simple) {
  var deps = {};
  var definitions = this._manifest.dependencies;
  var options = this._options.dependencies;
  _.each(definitions, function (dfn, name) {
    deps[name] = simple ? options[name] : {
      definition: dfn,
      title: utils.getReadableName(name),
      current: options[name]
    };
  });
  return deps;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief App needs to be configured
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.needsConfiguration = function() {
  var config = this.getConfiguration();
  var deps = this.getDependencies();
  return _.any(config, function (cfg) {
    return cfg.current === undefined && cfg.required !== false;
  }) || _.any(deps, function (dep) {
    return dep.current === undefined;
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief loadAppScript
////////////////////////////////////////////////////////////////////////////////

ArangoApp.prototype.loadAppScript = function (filename, options) {
  options = options || {};

  var appContext = _.extend({}, options.appContext, this._context);
  var full = fs.join(this._root, this._path, filename);

  if (!fs.exists(full)) {
    throwFileNotFound(full);
  }

  var fileContent = fs.read(full);

  if (options.transform) {
    fileContent = options.transform(fileContent);
  } else if (/\.coffee$/.test(filename)) {
    var cs = require("coffee-script");
    fileContent = cs.compile(fileContent, {bare: true});
  }

  var context = {};

  if (options.context) {
    Object.keys(options.context).forEach(function (key) {
      context[key] = options.context[key];
    });
  }

  var localModule = appContext.appPackage.createAppModule(this, filename);

  context.__filename = full;
  context.__dirname = module.normalizeModuleName(full + "/..");
  context.console = require("org/arangodb/foxx/console")(this._mount);
  context.applicationContext = appContext;

  try {
    return localModule.run(fileContent, context);
  } catch(e) {
    if (e instanceof ArangoError) {
      throw e;
    }
    var err = new ArangoError({
      errorNum: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.code,
      errorMessage: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.message
      + "\nFile: " + filename
    });
    err.stack = e.stack;
    err.cause = e;
    throw err;
  }
};

exports.ArangoApp = ArangoApp;

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
// End:
<|endoftext|>


<commit_before>(function(a,b){if(typeof define==="function"&&define.amd){define(["moment"],b)}else{if(typeof exports==="object"){module.exports=b(require("moment"))}else{b(a.moment)}}}(this,function(u){if(u.tz!==undefined){return u}var q="0.1.0",n={},g={};function e(x){if(x>96){return x-87}else{if(x>64){return x-29}}return x-48}function j(D){var B=0,z=D.split("."),E=z[0],y=z[1]||"",F=1,C,A=0,x=1;if(D.charCodeAt(0)===45){B=1;x=-1}for(B;B<E.length;B++){C=e(E.charCodeAt(B));A=60*A+C}for(B=0;B<y.length;B++){F=F/60;C=e(y.charCodeAt(B));A+=C*F}return A*x}function p(y){for(var x=0;x<y.length;x++){y[x]=j(y[x])}}function t(z,y){for(var x=0;x<y;x++){z[x]=Math.round((z[x-1]||0)+(z[x]*60000))}z[y-1]=Infinity}function a(z,A){var x=[],y;for(y=0;y<A.length;y++){x[y]=z[A[y]]}return x}function b(x){var z=x.split("|"),y=z[2].split(" "),B=z[3].split(""),A=z[4].split(" ");p(y);p(B);p(A);t(A,B.length);return{name:z[0],abbrs:a(z[1].split(" "),B),offsets:a(y,B),untils:A}}function f(x){var y=b(x);this.name=y.name;this.abbrs=y.abbrs;this.untils=y.untils;this.offsets=y.offsets}f.prototype={_index:function(y){var z=+y,A=this.untils,x;for(x=0;x<A.length;x++){if(z<A[x]){return x}}},parse:function(z){var A=+z,y=this.offsets,B=this.untils,x;for(x=0;x<B.length;x++){if(A<B[x]-(y[x]*60000)){return y[x]}}},abbr:function(x){return this.abbrs[this._index(x)]},offset:function(x){return this.offsets[this._index(x)]}};function k(x){return(x||"").toLowerCase().replace(/\//g,"_")}function o(y){var z,x;if(typeof y==="string"){y=[y]}for(z=0;z<y.length;z++){x=new f(y[z]);n[k(x.name)]=x}}function m(x){x=k(x);var y=g[x];if(y&&n[y]){x=y}return n[x]||null}function w(){var y,x=[];for(y in n){if(n.hasOwnProperty(y)&&n[y]){x.push(n[y].name)}}return x.sort()}function i(x){var z,y;if(typeof x==="string"){x=[x]}for(z=0;z<x.length;z++){y=k(x[z]).split("|");g[y[0]]=y[1];g[y[1]]=y[0]}}function c(x){o(x.zones);i(x.links);s.dataVersion=x.version}function r(x){if(!r.didShowError){r.didShowError=true;if(typeof console!=="undefined"&&typeof console.error==="function"){console.error("moment.tz.zoneExists('"+x+"') has been deprecated in favor of !moment.tz.zone('"+x+"')")}}return !!m(x)}function h(x){return !!(x._a&&(x._tzm===undefined))}function s(){var A=Array.prototype.slice.call(arguments,0,-1),z=arguments[arguments.length-1],x=m(z),y=u.utc.apply(null,A);if(x&&h(y)){y.add("minutes",x.parse(y))}y.tz(z);return y}s.version=q;s.dataVersion="";s._zones=n;s._links=g;s.add=o;s.link=i;s.load=c;s.zone=m;s.zoneExists=r;s.names=w;s.Zone=f;s.unpack=b;s.unpackBase60=j;s.needsOffset=h;var l=u.fn;u.tz=s;u.updateOffset=function(x,y){var z;if(x._z){z=x._z.offset(x);if(Math.abs(z)<16){z=z/60}x.zone(z,y)}};l.tz=function(x){if(x){this._z=m(x);if(this._z){u.updateOffset(this)}return this}if(this._z){return this._z.name}};function d(x){return function(){if(this._z){return this._z.abbr(this)}return x.call(this)}}function v(x){return function(){this._z=null;return x.call(this)}}l.zoneName=d(l.zoneName);l.zoneAbbr=d(l.zoneAbbr);l.utc=v(l.utc);u.momentProperties._z=null;return u}));<commit_msg>using officially minified file for moment-timezone v0.1.0<commit_after>//! moment-timezone.js
//! version : 0.1.0
//! author : Tim Wood
//! license : MIT
//! github.com/moment/moment-timezone
!function(a,b){"use strict";"function"==typeof define&&define.amd?define(["moment"],b):"object"==typeof exports?module.exports=b(require("moment")):b(a.moment)}(this,function(a){"use strict";function b(a){return a>96?a-87:a>64?a-29:a-48}function c(a){var c,d=0,e=a.split("."),f=e[0],g=e[1]||"",h=1,i=0,j=1;for(45===a.charCodeAt(0)&&(d=1,j=-1),d;d<f.length;d++)c=b(f.charCodeAt(d)),i=60*i+c;for(d=0;d<g.length;d++)h/=60,c=b(g.charCodeAt(d)),i+=c*h;return i*j}function d(a){for(var b=0;b<a.length;b++)a[b]=c(a[b])}function e(a,b){for(var c=0;b>c;c++)a[c]=Math.round((a[c-1]||0)+6e4*a[c]);a[b-1]=1/0}function f(a,b){var c,d=[];for(c=0;c<b.length;c++)d[c]=a[b[c]];return d}function g(a){var b=a.split("|"),c=b[2].split(" "),g=b[3].split(""),h=b[4].split(" ");return d(c),d(g),d(h),e(h,g.length),{name:b[0],abbrs:f(b[1].split(" "),g),offsets:f(c,g),untils:h}}function h(a){var b=g(a);this.name=b.name,this.abbrs=b.abbrs,this.untils=b.untils,this.offsets=b.offsets}function i(a){return(a||"").toLowerCase().replace(/\//g,"_")}function j(a){var b,c;for("string"==typeof a&&(a=[a]),b=0;b<a.length;b++)c=new h(a[b]),u[i(c.name)]=c}function k(a){a=i(a);var b=v[a];return b&&u[b]&&(a=b),u[a]||null}function l(){var a,b=[];for(a in u)u.hasOwnProperty(a)&&u[a]&&b.push(u[a].name);return b.sort()}function m(a){var b,c;for("string"==typeof a&&(a=[a]),b=0;b<a.length;b++)c=i(a[b]).split("|"),v[c[0]]=c[1],v[c[1]]=c[0]}function n(a){j(a.zones),m(a.links),q.dataVersion=a.version}function o(a){return o.didShowError||(o.didShowError=!0,"undefined"!=typeof console&&"function"==typeof console.error&&console.error("moment.tz.zoneExists('"+a+"') has been deprecated in favor of !moment.tz.zone('"+a+"')")),!!k(a)}function p(a){return!(!a._a||void 0!==a._tzm)}function q(){var b=Array.prototype.slice.call(arguments,0,-1),c=arguments[arguments.length-1],d=k(c),e=a.utc.apply(null,b);return d&&p(e)&&e.add("minutes",d.parse(e)),e.tz(c),e}function r(a){return function(){return this._z?this._z.abbr(this):a.call(this)}}function s(a){return function(){return this._z=null,a.call(this)}}if(void 0!==a.tz)return a;var t="0.1.0",u={},v={};h.prototype={_index:function(a){var b,c=+a,d=this.untils;for(b=0;b<d.length;b++)if(c<d[b])return b},parse:function(a){var b,c=+a,d=this.offsets,e=this.untils;for(b=0;b<e.length;b++)if(c<e[b]-6e4*d[b])return d[b]},abbr:function(a){return this.abbrs[this._index(a)]},offset:function(a){return this.offsets[this._index(a)]}},q.version=t,q.dataVersion="",q._zones=u,q._links=v,q.add=j,q.link=m,q.load=n,q.zone=k,q.zoneExists=o,q.names=l,q.Zone=h,q.unpack=g,q.unpackBase60=c,q.needsOffset=p;var w=a.fn;return a.tz=q,a.updateOffset=function(a,b){var c;a._z&&(c=a._z.offset(a),Math.abs(c)<16&&(c/=60),a.zone(c,b))},w.tz=function(b){return b?(this._z=k(b),this._z&&a.updateOffset(this),this):this._z?this._z.name:void 0},w.zoneName=r(w.zoneName),w.zoneAbbr=r(w.zoneAbbr),w.utc=s(w.utc),a.momentProperties._z=null,a});<|endoftext|>


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

/**
 * This is the Webpack voo-doo that makes it so easy to add spec
 * files.  It will recursively traverse the current directory,
 * checking for any files that end in .spec.js, bundling them
 * and making them accessible via the special `specFileRequire`
 * function.  These test modules are explicitly required in below.
 *
 * For more information, read the documentation here:
 *   https://github.com/webpack/docs/wiki/context/
 *   71f80252750e1d8f4b6b40395855e0dd5cca6d12#requirecontext
 */

var specFileRequire = require.context(".", true, /\.spec\.js$/);

/**
 * This creates a DOM element with ID "fixtures".  It is visible,
 * but far off to the left of the viewable screen.  When testing
 * your views, they can be mounted here.
 */

var fixturesEl = document.createElement("div");
fixturesEl.setAttribute("id", "fixtures");
document.querySelector("body").appendChild(fixturesEl);
fixturesEl.style.position = "absolute";
fixturesEl.style.left = "5000px";

/**
 * This loads Chai (assertion library) and Sinon (mock/stub
 * library) into the global context, for both in-browser
 * and Karma tests.
 */

window.chai = require("chai");
window.expect = window.chai.expect;
window.sinon = require("sinon");
window.chai.use(require("sinon-chai"));

/**
 * Requires in all spec files.  See above comment.
 */

_.each(_.keys(specFileRequire), function (specFileName) {
  specFileRequire(specFileName);
});
<commit_msg>Update test-runner.js<commit_after>var _ = require("lodash");

/**
 * This is the Webpack voo-doo that makes it so easy to add spec
 * files.  It will recursively traverse the current directory,
 * checking for any files that end in .spec.js, bundling them
 * and making them accessible via the special `specFileRequire`
 * function.  These test modules are explicitly required in below.
 *
 * For more information, read the documentation here:
 *   https://github.com/webpack/docs/wiki/context/
 *   71f80252750e1d8f4b6b40395855e0dd5cca6d12#requirecontext
 */

var specFileRequire = require.context(".", true, /\.spec\.js$/);

/**
 * This creates a DOM element with ID "fixtures".  It is visible,
 * but far off to the left of the viewable screen.  When testing
 * your views, they can be mounted here.
 */

var fixturesEl = document.createElement("div");
fixturesEl.setAttribute("id", "fixtures");
document.querySelector("body").appendChild(fixturesEl);
fixturesEl.style.position = "absolute";
fixturesEl.style.left = "5000px";

/**
 * This loads Chai (assertion library) and Sinon (mock/stub
 * library) into the global context, for both in-browser
 * and Karma tests.
 */

window.chai = require("chai");
window.expect = window.chai.expect;
window.sinon = require("sinon");
window.chai.use(require("sinon-chai"));

/**
 * Requires in all spec files.  See above comment.
 */

_.each(specFileRequire.keys(), function (specFileName) {
  specFileRequire(specFileName);
});
<|endoftext|>


<commit_before>var Q = require('q');

var Twit = require('twit');

var models = require('../models');
var utils = require('../helpers/utils');
var config = require('../config');
var match = require('../helpers/match')
var tweetBuilder = require('./tweetBuilder');

var T = new Twit(config.twitter);

function removeHashTag(text) {
  return text.replace(/#\w+/i, '');
}

function removeUser(text) {
  return text.replace(/@\w/i, '')
}

function parseFieldsFromTweet(tweet, fields) {
  var parsed = {};
  var mapFields = {
    id: 'id',
    name: 'user.name',
    screen_name: 'user.screen_name',
    text: 'text',
    hashtags: 'entities.hashtags'
  }

  fields.forEach(function(k) {
    if (k in mapFields) {
      parsed[k] = utils.getField(tweet, mapFields[k], 'none '+k);
    }
  })

  return parsed;
}

function getLocation(id) {
  console.log(getLocation);
  return Q.promise(function (resolve, reject) {
    T.get('statuses/show/:id', {id: id}, function (err, data, response) {
      console.log(err, id);
      console.log(data);
    });
  });
}

function findScheduleAndPost(msg, screen_name) {

  match.parseQueryFromTweet(msg)
    .then(models.schedule.getOne)
    .then(function(data) {
      if(!data.schedule) {
        data.schedule = 'No schedule found';
      };
      var posts = tweetBuilder.createPosts(screen_name, data);
      posts.forEach(function(post) {
        postTweet(post);
      })
    });
}

function follow(id, cb) {
  T.post('friendships/create', {user_id: id, follow: true},
         function(err, data, response) {
            if (err) return cb('follow ' + err);
            cb(null);
          }
  )
}

function handleNewTweet(tweet) {

  var tweetFields = parseFieldsFromTweet(tweet,
                     ['id', 'name', 'screen_name', 'text', 'hashtags']);
  var msg = tweetFields.text;
  if (msg.indexOf('boterino123') < 0 && msg.indexOf(config.hashtag) < 0) {
    return;
  }
  console.log('------------------on tweet --------------------------');
  var msg = removeHashTag(msg);
  msg = removeUser(msg);

  var msgClean = utils.cleanSpaces(msg);
  console.log(tweetFields);
  console.log('msgClean', msgClean);
  if ( msgClean === 'help' || !msgClean.length ) {
    var post = tweetBuilder.createHelpMsg(tweetFields.screen_name);
    postTweet(post);
    return;
  }

  findScheduleAndPost(msg, tweetFields.screen_name);

}

function listenStream(hashtag) {
  T.stream('statuses/filter', { track: hashtag});
  T.stream('user').on('tweet',handleNewTweet);;

}

function postTweet(message) {
  T.post('statuses/update', {status: message},
    function(err, data, response) {
      if (err) return console.log(err);
      console.log('posted', message);
    }
  )
}

// var mongoose = require('mongoose');
// var config = require('../config');

// mongoose.connect(config.mongoConnection);

// findScheduleAndPost('larcomar Terminator ', 'ggwp')

module.exports.listenStream = listenStream;

follow(615385295803056100,function(err) {
  console.log('ggwp', err)
})<commit_msg>test follow<commit_after>var Q = require('q');

var Twit = require('twit');

var models = require('../models');
var utils = require('../helpers/utils');
var config = require('../config');
var match = require('../helpers/match')
var tweetBuilder = require('./tweetBuilder');

var T = new Twit(config.twitter);

function removeHashTag(text) {
  return text.replace(/#\w+/i, '');
}

function removeUser(text) {
  return text.replace(/@\w/i, '')
}

function parseFieldsFromTweet(tweet, fields) {
  var parsed = {};
  var mapFields = {
    user_id: 'user.id',
    id: 'id',
    name: 'user.name',
    screen_name: 'user.screen_name',
    text: 'text',
    hashtags: 'entities.hashtags'
  }

  fields.forEach(function(k) {
    if (k in mapFields) {
      parsed[k] = utils.getField(tweet, mapFields[k], 'none '+k);
    }
  })

  return parsed;
}

function getLocation(id) {
  console.log(getLocation);
  return Q.promise(function (resolve, reject) {
    T.get('statuses/show/:id', {id: id}, function (err, data, response) {
      console.log(err, id);
      console.log(data);
    });
  });
}

function findScheduleAndPost(msg, screen_name) {

  match.parseQueryFromTweet(msg)
    .then(models.schedule.getOne)
    .then(function(data) {
      if(!data.schedule) {
        data.schedule = 'No schedule found';
      };
      var posts = tweetBuilder.createPosts(screen_name, data);
      posts.forEach(function(post) {
        postTweet(post);
      })
    });
}

function follow(id, cb) {
  T.post('friendships/create', {user_id: id, follow: true},
         function(err, data, response) {
            if (err) return cb('follow ' + err);
            cb(null);
          }
  )
}

function handleNewTweet(tweet) {

  var tweetFields = parseFieldsFromTweet(tweet,
                     ['id','user_id', 'name', 'screen_name', 'text', 'hashtags']);
  var msg = tweetFields.text;
  if (msg.indexOf('boterino123') < 0 && msg.indexOf(config.hashtag) < 0) {
    return;
  }
  console.log('------------------on tweet --------------------------');
  var msg = removeHashTag(msg);
  msg = removeUser(msg);

  var msgClean = utils.cleanSpaces(msg);
  console.log(tweetFields);
  console.log('msgClean', msgClean);
  if ( msgClean === 'help' || !msgClean.length ) {
    var post = tweetBuilder.createHelpMsg(tweetFields.screen_name);
    postTweet(post);
    return;
  }

  findScheduleAndPost(msg, tweetFields.screen_name);

}

function listenStream(hashtag) {
  T.stream('statuses/filter', { track: hashtag});
  T.stream('user').on('tweet',handleNewTweet);;

}

function postTweet(message) {
  T.post('statuses/update', {status: message},
    function(err, data, response) {
      if (err) return console.log(err);
      console.log('posted', message);
    }
  )
}

// var mongoose = require('mongoose');
// var config = require('../config');

// mongoose.connect(config.mongoConnection);

// findScheduleAndPost('larcomar Terminator ', 'ggwp')

module.exports.listenStream = listenStream;

// follow(3252772133,function(err) {
//   console.log('ggwp', err)
// })<|endoftext|>


<commit_before>/**
 * module class
 */
function module(viewmodel, id, name, description, doelstellingen) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description: ko.observable(description),
        doelstellingen: ko.observableArray(doelstellingen),

        addDoelstelling: function() {
            this.doelstellingen.push(new doelstelling(this));
        },

        removeThis: function() {
            viewModel.removeModule(this);
        },

        removeDoelstelling: function(doelstelling) {
            this.doelstellingen.remove(doelstelling);
        }
    };

}

/**
 * doelstelling class
 */
function doelstelling(parent, id, name, description, crit) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description: ko.observable(description),
        criterias: ko.observableArray(crit),

        addCriteria: function() {
            this.criterias.push(new criteria(this));
        },

        removeThis: function() {
            parent.removeDoelstelling(this);
        },

        removeCriteria: function(criteria) {
            this.criterias.remove(criteria);
        }
    };
}

/**
 * criteria class
 */
function criteria(parent, id, name, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description : ko.observable(description),

        removeThis: function() {
            parent.removeCriteria(this);
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.modules = 0;
    gvm.doelstelling = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addmoduleBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Addmodule");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.modules = ko.observableArray([]);

    gvm.addModule = function() {
        gvm.modules.push(new module(this));
    };

    gvm.removeModule = function(module) {
        gvm.modules.remove(module);
    }

    gvm.updateModule = function(id, name, description) {
        var mod = new module(this, id, name, description);
        gvm.modules.push(mod);
        return mod;
    }

    gvm.clearStructure = function() {
        gvm.modules.destroyAll();
    }
}

function fetchCourseStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/coursestructure/" + courseid, function(data){
        $.each(data, function(i, item){
            var module = viewModel.updateModule(item.id, item.name, item.description);

            $.each(item.doelstellingen, function(i, doel){
               var doelst = new doelstelling(module, doel.id, doel.name, doel.description);
                module.doelstellingen.push(doelst);

               $.each(doel.criterias, function(i, crit){
                  doelst.criterias.push(new criteria(doelst, crit.id, crit.name, crit.description));
               });
            });
        })
    });
}

function initPage() {
    fetchCourseStructure();

    $(".addmoduleBtn").click(function() {
        console.log('clicked on add module');
        viewModel.addModule();
    });

    $(".savePageBtn").click(function(){
        if(validationCheck()) {
            saveCourseStructure();
            console.log("Saved");
        } else {
            window.scrollTo(0,0);
            console.log("Not saved");
        }
    });
}

function saveCourseStructure() {
    $.ajax({
        type: "POST",
        url: "/api/savemodules/" + courseid,
        data: ko.toJSON(viewModel.modules),
        success: function(){
            // TODO make multilangual and with modals
            alert("Saved coursestructure to server");

            fetchCourseStructure();
        }
    });
}

function validationCheck()
{
    var allmodulesValid = true;
    var alldoelstellingenValid = true;
    var allcriteriasValid = true;

    for(var indexmodules =0; indexmodules < viewModel.modules().length; indexmodules++)
    {
        if(!viewModel.modules()[indexmodules].name() && !viewModel.modules()[indexmodules].description())
        {
            if(allmodulesValid)
            {
                $(".validationSummary ul").append("
Code or name in modules is empty
");
                $(".validationSummary").removeClass("hide");
            }
            allmodulesValid = false;
        }
        for(var indexdoelstelling = 0; indexdoelstelling < viewModel.modules()[indexmodules].doelstellingen().length; indexdoelstelling++)
        {
            if(!viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].name() && !viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].description())
            {
                if(alldoelstellingenValid)
                {
                    $(".validationSummary ul").append("
Code or name in doelstellingen is empty
");
                    $(".validationSummary").removeClass("hide");
                }
                alldoelstellingenValid = false;
            }
            for(var indexcriterias = 0; indexcriterias < viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].criterias().length; indexcriterias++)
            {
                if(!viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].criterias()[indexcriterias].name() && !viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].criterias()[indexcriterias].description())
                {
                    if(allcriteriasValid)
                    {
                        $(".validationSummary ul").append("
Description or name in criterias is empty
");
                        $(".validationSummary").removeClass("hide");
                    }
                    allcriteriasValid = false;
                }
            }
        }
    }
    return allmodulesValid && alldoelstellingenValid && allcriteriasValid;
}
<commit_msg>remove module<commit_after>/**
 * module class
 */
function module(viewmodel, id, name, description, doelstellingen) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description: ko.observable(description),
        doelstellingen: ko.observableArray(doelstellingen),

        addDoelstelling: function() {
            this.doelstellingen.push(new doelstelling(this));
        },

        removeThis: function() {
            //viewModel.removeModule(this);
            this.module.remove(module);
        },

        removeDoelstelling: function(doelstelling) {
            this.doelstellingen.remove(doelstelling);
        }
    };

}

/**
 * doelstelling class
 */
function doelstelling(parent, id, name, description, crit) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description: ko.observable(description),
        criterias: ko.observableArray(crit),

        addCriteria: function() {
            this.criterias.push(new criteria(this));
        },

        removeThis: function() {
            parent.removeDoelstelling(this);
        },

        removeCriteria: function(criteria) {
            this.criterias.remove(criteria);
        }
    };
}

/**
 * criteria class
 */
function criteria(parent, id, name, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        description : ko.observable(description),

        removeThis: function() {
            parent.removeCriteria(this);
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.modules = 0;
    gvm.doelstelling = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addmoduleBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Addmodule");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.modules = ko.observableArray([]);

    gvm.addModule = function() {
        gvm.modules.push(new module(this));
    };

    gvm.removeModule = function(module) {
        gvm.modules.remove(module);
    }

    gvm.updateModule = function(id, name, description) {
        var mod = new module(this, id, name, description);
        gvm.modules.push(mod);
        return mod;
    }

    gvm.clearStructure = function() {
        gvm.modules.destroyAll();
    }
}

function fetchCourseStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/coursestructure/" + courseid, function(data){
        $.each(data, function(i, item){
            var module = viewModel.updateModule(item.id, item.name, item.description);

            $.each(item.doelstellingen, function(i, doel){
               var doelst = new doelstelling(module, doel.id, doel.name, doel.description);
                module.doelstellingen.push(doelst);

               $.each(doel.criterias, function(i, crit){
                  doelst.criterias.push(new criteria(doelst, crit.id, crit.name, crit.description));
               });
            });
        })
    });
}

function initPage() {
    fetchCourseStructure();

    $(".addmoduleBtn").click(function() {
        console.log('clicked on add module');
        viewModel.addModule();
    });

    $(".savePageBtn").click(function(){
        if(validationCheck()) {
            saveCourseStructure();
            console.log("Saved");
        } else {
            window.scrollTo(0,0);
            console.log("Not saved");
        }
    });
}

function saveCourseStructure() {
    $.ajax({
        type: "POST",
        url: "/api/savemodules/" + courseid,
        data: ko.toJSON(viewModel.modules),
        success: function(){
            // TODO make multilangual and with modals
            alert("Saved coursestructure to server");

            fetchCourseStructure();
        }
    });
}

function validationCheck()
{
    var allmodulesValid = true;
    var alldoelstellingenValid = true;
    var allcriteriasValid = true;

    for(var indexmodules =0; indexmodules < viewModel.modules().length; indexmodules++)
    {
        if(!viewModel.modules()[indexmodules].name() && !viewModel.modules()[indexmodules].description())
        {
            if(allmodulesValid)
            {
                $(".validationSummary ul").append("
Code or name in modules is empty
");
                $(".validationSummary").removeClass("hide");
            }
            allmodulesValid = false;
        }
        for(var indexdoelstelling = 0; indexdoelstelling < viewModel.modules()[indexmodules].doelstellingen().length; indexdoelstelling++)
        {
            if(!viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].name() && !viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].description())
            {
                if(alldoelstellingenValid)
                {
                    $(".validationSummary ul").append("
Code or name in doelstellingen is empty
");
                    $(".validationSummary").removeClass("hide");
                }
                alldoelstellingenValid = false;
            }
            for(var indexcriterias = 0; indexcriterias < viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].criterias().length; indexcriterias++)
            {
                if(!viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].criterias()[indexcriterias].name() && !viewModel.modules()[indexmodules].doelstellingen()[indexdoelstelling].criterias()[indexcriterias].description())
                {
                    if(allcriteriasValid)
                    {
                        $(".validationSummary ul").append("
Description or name in criterias is empty
");
                        $(".validationSummary").removeClass("hide");
                    }
                    allcriteriasValid = false;
                }
            }
        }
    }
    return allmodulesValid && alldoelstellingenValid && allcriteriasValid;
}
<|endoftext|>


<commit_before>
pc.script.create('worldmap', function (context) {
    var hexsize = 34;
    var numhexes = 5;

    var WorldMap = function (entity) {
        this.entity = entity;
    };

    WorldMap.prototype = {
        // Called once after all resources are loaded and before the first update
        initialize: function () {
            this.needtobuild = true;
        },

        buildmap: function() {
            var basehex = this.entity.findByName("basichex");
            var basetree = this.entity.findByName("basictree");

            var hexmap = chartreusewarden.generatemap(hexsize, numhexes);

            var hexes = _.values(hexmap.mapdata);
            var entity = this.entity;

            // place hexes
            _.each(hexes, function(hex) {
                var worldcoord = hex.worldcoord;

                // nudge meshes up and down a little bit to avoid z-fighting of the flat ground
                var perturbedworldcoord = new pc.Vec3(worldcoord.x, basehex.getPosition().y + Math.random() * 0.04 - 0.02, worldcoord.z);

                var freshhex = basehex.clone();
                this.entity.addChild(freshhex);
                freshhex.setPosition(perturbedworldcoord);

                // randomize rotation
                var rotationangle = Math.floor(Math.random() * 6) * 60;
                var newrotation = new pc.Quat();
                newrotation.setFromEulerAngles(0,rotationangle,0);
                freshhex.setLocalRotation(newrotation.mul(freshhex.getLocalRotation()));

                freshhex.rigidbody.syncEntityToBody();

            }, this);

            // some hexes are adjacent but not "connected" so we have to place to wall
            // on the non-connected edge.
            var wallplacements = [];
            _.each(hexes, function(hex) {
                var hexcoord = hex.hexcoord;
                var adjhexcoords = hexmap.getAdjacentHexes(hexcoord);

                // if an adjacent hex doesn't exist, we need a wall
                // if an adjacent hex exists but isn't connected to this hex we need a wall
                // if an adjacent hex exists and is connected we don't need a wall
                _.each(adjhexcoords, function(adjhexcoord) {
                    var adjhex = hexmap.getHex(adjhexcoord);
                    var needwall =  ((typeof adjhex === "undefined") || (_.contains(hex.connectedhexes, adjhex) === false));

                    if (needwall) {
                        var edgestring = hexmap.buildEdgeCoordinate(hexcoord, adjhexcoord);

                        // add to the list of walls if it isn't already there
                        if (_.contains(wallplacements, edgestring) === false) {
                            wallplacements.push(edgestring);
                        }
                    }
                }, this);

            }, this);

            // place a tree at each wall location
            _.each(wallplacements, function(walllocation) {
                var edgeendpoints = hexmap.parseEdgeCoordinateToWorldEndpoints(walllocation);
                var obstaclestep = edgeendpoints[1].clone().sub(edgeendpoints[0]).scale(0.33);
                var walllocation1 = edgeendpoints[0].clone().add(obstaclestep);
                var walllocation2 = walllocation1.clone().add(obstaclestep);

                var freshwall1 = basetree.clone();
                this.entity.addChild(freshwall1);
                freshwall1.setPosition(walllocation1);
                freshwall1.rigidbody.syncEntityToBody();

                var freshwall2 = basetree.clone();
                this.entity.addChild(freshwall2);
                freshwall2.setPosition(walllocation2);
                freshwall2.rigidbody.syncEntityToBody();
            }, this);

            // clear out exemplar objects
            basehex.destroy();
            basetree.destroy();
        },

        // Called every frame, dt is time in seconds since last update
        update: function (dt) {
            if (this.needtobuild) {
             this.buildmap();
             this.needtobuild = false;
            }
        }

    };

    return WorldMap;
});<commit_msg>Now places player at the start hex location.<commit_after>
pc.script.create('worldmap', function (context) {
    var hexsize = 34;
    var numhexes = 5;

    var WorldMap = function (entity) {
        this.entity = entity;
    };

    WorldMap.prototype = {
        // Called once after all resources are loaded and before the first update
        initialize: function () {
            this.needtobuild = true;
        },

        buildmap: function() {
            var basehex = this.entity.findByName("basichex");
            var basetree = this.entity.findByName("basictree");

            var hexmap = chartreusewarden.generatemap(hexsize, numhexes);

            var hexes = _.values(hexmap.mapdata);
            var entity = this.entity;

            // place hexes
            _.each(hexes, function(hex) {
                var worldcoord = hex.worldcoord;

                // nudge meshes up and down a little bit to avoid z-fighting of the flat ground
                var perturbedworldcoord = new pc.Vec3(worldcoord.x, basehex.getPosition().y + Math.random() * 0.04 - 0.02, worldcoord.z);

                var freshhex = basehex.clone();
                this.entity.addChild(freshhex);
                freshhex.setPosition(perturbedworldcoord);

                // randomize rotation
                var rotationangle = Math.floor(Math.random() * 6) * 60;
                var newrotation = new pc.Quat();
                newrotation.setFromEulerAngles(0,rotationangle,0);
                freshhex.setLocalRotation(newrotation.mul(freshhex.getLocalRotation()));

                freshhex.rigidbody.syncEntityToBody();

            }, this);

            // some hexes are adjacent but not "connected" so we have to place to wall
            // on the non-connected edge.
            var wallplacements = [];
            _.each(hexes, function(hex) {
                var hexcoord = hex.hexcoord;
                var adjhexcoords = hexmap.getAdjacentHexes(hexcoord);

                // if an adjacent hex doesn't exist, we need a wall
                // if an adjacent hex exists but isn't connected to this hex we need a wall
                // if an adjacent hex exists and is connected we don't need a wall
                _.each(adjhexcoords, function(adjhexcoord) {
                    var adjhex = hexmap.getHex(adjhexcoord);
                    var needwall =  ((typeof adjhex === "undefined") || (_.contains(hex.connectedhexes, adjhex) === false));

                    if (needwall) {
                        var edgestring = hexmap.buildEdgeCoordinate(hexcoord, adjhexcoord);

                        // add to the list of walls if it isn't already there
                        if (_.contains(wallplacements, edgestring) === false) {
                            wallplacements.push(edgestring);
                        }
                    }
                }, this);

            }, this);

            // place a tree at each wall location
            _.each(wallplacements, function(walllocation) {
                var edgeendpoints = hexmap.parseEdgeCoordinateToWorldEndpoints(walllocation);
                var obstaclestep = edgeendpoints[1].clone().sub(edgeendpoints[0]).scale(0.33);
                var walllocation1 = edgeendpoints[0].clone().add(obstaclestep);
                var walllocation2 = walllocation1.clone().add(obstaclestep);

                var freshwall1 = basetree.clone();
                this.entity.addChild(freshwall1);
                freshwall1.setPosition(walllocation1);
                freshwall1.rigidbody.syncEntityToBody();

                var freshwall2 = basetree.clone();
                this.entity.addChild(freshwall2);
                freshwall2.setPosition(walllocation2);
                freshwall2.rigidbody.syncEntityToBody();
            }, this);

            // clear out exemplar objects
            basehex.destroy();
            basetree.destroy();

            // position the player at the start hex
            var starthexes = hexmap.findHexesWithTag('start');
            var starthex = starthexes[0];

            var playerentity = this.entity.getRoot().findByName('Avatar');
            playerentity.setPosition(starthex.worldcoord.x, starthex.worldcoord.y + 10, starthex.worldcoord.z);
        },

        // Called every frame, dt is time in seconds since last update
        update: function (dt) {
            if (this.needtobuild) {
                this.buildmap();
                this.needtobuild = false;
            }
        }

    };

    return WorldMap;
});<|endoftext|>