<commit_before>const _ = require("lodash");
const path = require("path");
const Provider = require("@truffle/provider");
const TruffleError = require("@truffle/error");
const Module = require("module");
const findUp = require("find-up");
const originalrequire = require("original-require");
const Configstore = require("configstore");

const DEFAULT_CONFIG_FILENAME = "truffle-config.js";
const BACKUP_CONFIG_FILENAME = "truffle.js"; // old config filename

class Config {
  constructor(truffle_directory, working_directory, network) {
    const default_tx_values = {
      gas: 6721975,
      gasPrice: 20000000000, // 20 gwei,
      from: null
    };

    // This is a list of multi-level keys with defaults
    // we need to _.merge. Using this list for safety
    // vs. just merging all objects.
    this._deepCopy = ["compilers"];

    this._values = {
      truffle_directory:
        truffle_directory || path.resolve(path.join(__dirname, "../")),
      working_directory: working_directory || process.cwd(),
      network,
      networks: {},
      verboseRpc: false,
      gas: null,
      gasPrice: null,
      from: null,
      confirmations: 0,
      timeoutBlocks: 0,
      production: false,
      skipDryRun: false,
      build: null,
      resolver: null,
      artifactor: null,
      ethpm: {
        ipfs_host: "ipfs.infura.io",
        ipfs_protocol: "https",
        registry: "0x8011df4830b4f696cd81393997e5371b93338878",
        install_provider_uri: "https://ropsten.infura.io/truffle"
      },
      compilers: {
        solc: {
          settings: {
            optimizer: {
              enabled: false,
              runs: 200
            }
          }
        },
        vyper: {}
      },
      logger: {
        log() {}
      }
    };

    const resolveDirectory = value =>
      path.resolve(this.working_directory, value);

    const props = {
      // These are already set.
      truffle_directory() {},
      working_directory() {},
      network() {},
      networks() {},
      verboseRpc() {},
      build() {},
      resolver() {},
      artifactor() {},
      ethpm() {},
      logger() {},
      compilers() {},

      build_directory: {
        default: () => path.join(this.working_directory, "build"),
        transform: resolveDirectory
      },
      contracts_directory: {
        default: () => path.join(this.working_directory, "contracts"),
        transform: resolveDirectory
      },
      contracts_build_directory: {
        default: () => path.join(this.build_directory, "contracts"),
        transform: resolveDirectory
      },
      migrations_directory: {
        default: () => path.join(this.working_directory, "migrations"),
        transform: resolveDirectory
      },
      migrations_file_extension_regexp() {
        return /^\.(js|es6?)$/;
      },
      test_directory: {
        default: () => path.join(this.working_directory, "test"),
        transform: resolveDirectory
      },
      test_file_extension_regexp() {
        return /.*\.(js|ts|es|es6|jsx|sol)$/;
      },
      example_project_directory: {
        default: () => path.join(this.truffle_directory, "example"),
        transform: resolveDirectory
      },
      network_id: {
        get() {
          try {
            return this.network_config.network_id;
          } catch (e) {
            return null;
          }
        },
        set() {
          throw new Error(
            "Do not set config.network_id. Instead, set config.networks and then config.networks[<network name>].network_id"
          );
        }
      },
      network_config: {
        get() {
          const network = this.network;

          if (network === null || network === undefined) {
            throw new Error(
              "Network not set. Cannot determine network to use."
            );
          }

          let conf = this.networks[network];

          if (conf === null || conf === undefined) {
            config = {};
          }

          conf = _.extend({}, default_tx_values, conf);

          return conf;
        },
        set() {
          throw new Error(
            "Don't set config.network_config. Instead, set config.networks with the desired values."
          );
        }
      },
      from: {
        get() {
          try {
            return this.network_config.from;
          } catch (e) {
            return default_tx_values.from;
          }
        },
        set() {
          throw new Error(
            "Don't set config.from directly. Instead, set config.networks and then config.networks[<network name>].from"
          );
        }
      },
      gas: {
        get() {
          try {
            return this.network_config.gas;
          } catch (e) {
            return default_tx_values.gas;
          }
        },
        set() {
          throw new Error(
            "Don't set config.gas directly. Instead, set config.networks and then config.networks[<network name>].gas"
          );
        }
      },
      gasPrice: {
        get() {
          try {
            return this.network_config.gasPrice;
          } catch (e) {
            return default_tx_values.gasPrice;
          }
        },
        set() {
          throw new Error(
            "Don't set config.gasPrice directly. Instead, set config.networks and then config.networks[<network name>].gasPrice"
          );
        }
      },
      provider: {
        get() {
          if (!this.network) {
            return null;
          }

          const options = this.network_config;
          options.verboseRpc = this.verboseRpc;

          return Provider.create(options);
        },
        set() {
          throw new Error(
            "Don't set config.provider directly. Instead, set config.networks and then set config.networks[<network name>].provider"
          );
        }
      },
      confirmations: {
        get() {
          try {
            return this.network_config.confirmations;
          } catch (e) {
            return 0;
          }
        },
        set() {
          throw new Error(
            "Don't set config.confirmations directly. Instead, set config.networks and then config.networks[<network name>].confirmations"
          );
        }
      },
      production: {
        get() {
          try {
            return this.network_config.production;
          } catch (e) {
            return false;
          }
        },
        set() {
          throw new Error(
            "Don't set config.production directly. Instead, set config.networks and then config.networks[<network name>].production"
          );
        }
      },
      timeoutBlocks: {
        get() {
          try {
            return this.network_config.timeoutBlocks;
          } catch (e) {
            return 0;
          }
        },
        set() {
          throw new Error(
            "Don't set config.timeoutBlocks directly. Instead, set config.networks and then config.networks[<network name>].timeoutBlocks"
          );
        }
      }
    };

    Object.keys(props).forEach(prop => {
      this.addProp(prop, props[prop]);
    });
  }

  addProp(propertyName, descriptor) {
    // possible property descriptors
    //
    // supports `default` and `transform` in addition to `get` and `set`
    //
    // default: specify function to retrieve default value (used by get)
    // transform: specify function to transform value when (used by set)
    Object.defineProperty(this, propertyName, {
      // retrieve config property value
      get:
        descriptor.get ||
        function() {
          // value is specified
          if (propertyName in this._values) {
            return this._values[propertyName];
          }

          // default getter is specified
          if (descriptor.default) {
            return descriptor.default();
          }

          // descriptor is a function
          return descriptor();
        },
      set:
        descriptor.set ||
        function(value) {
          this._values[propertyName] = descriptor.transform
            ? descriptor.transform(value)
            : value;
        },
      configurable: true,
      enumerable: true
    });
  }

  normalize(obj) {
    const clone = {};
    Object.keys(obj).forEach(key => {
      try {
        clone[key] = obj[key];
      } catch (e) {
        // Do nothing with values that throw.
      }
    });
    return clone;
  }

  with(obj) {
    const normalized = this.normalize(obj);
    const current = this.normalize(this);

    return _.extend(Object.create(Config.prototype), current, normalized);
  }

  merge(obj) {
    let clone = this.normalize(obj);

    // Only set keys for values that don't throw.
    const propertyNames = Object.keys(obj);

    propertyNames.forEach(key => {
      try {
        if (typeof clone[key] === "object" && this._deepCopy.includes(key)) {
          this[key] = _.merge(this[key], clone[key]);
        } else {
          this[key] = clone[key];
        }
      } catch (e) {
        // Do nothing.
      }
    });

    return this;
  }
}

Config.default = () => new Config();

Config.search = (options = {}, filename) => {
  const searchOptions = {
    cwd: options.working_directory || options.workingDirectory
  };

  if (!filename) {
    const isWin = /^win/.test(process.platform);
    const defaultConfig = findUp.sync(DEFAULT_CONFIG_FILENAME, searchOptions);
    const backupConfig = findUp.sync(BACKUP_CONFIG_FILENAME, searchOptions);
    if (defaultConfig && backupConfig) {
      console.warn(
        `Warning: Both ${DEFAULT_CONFIG_FILENAME} and ${BACKUP_CONFIG_FILENAME} were found. Using ${DEFAULT_CONFIG_FILENAME}.`
      );
      return defaultConfig;
    } else if (backupConfig && !defaultConfig) {
      if (isWin)
        console.warn(
          `Warning: Please rename ${BACKUP_CONFIG_FILENAME} to ${DEFAULT_CONFIG_FILENAME} to ensure Windows compatibility.`
        );
      return backupConfig;
    } else {
      return defaultConfig;
    }
  }

  return findUp.sync(filename, searchOptions);
};

Config.detect = (options = {}, filename) => {
  const configFile = Config.search(options, filename);

  if (!configFile) {
    throw new TruffleError("Could not find suitable configuration file.");
  }

  return Config.load(configFile, options);
};

Config.load = (file, options) => {
  const config = new Config();

  config.working_directory = path.dirname(path.resolve(file));

  // The require-nocache module used to do this for us, but
  // it doesn't bundle very well. So we've pulled it out ourselves.
  delete require.cache[Module._resolveFilename(file, module)];
  const static_config = originalrequire(file);

  config.merge(static_config);
  config.merge(options);

  return config;
};

Config.getUserConfig = () =>
  new Configstore("truffle", {}, { globalConfigPath: true });

Config.getTruffleDataDirectory = () => {
  const configStore = new Configstore(
    "truffle",
    {},
    { globalConfigPath: true }
  );
  return path.dirname(configStore.path);
};

module.exports = Config;
<commit_msg>Add default for compiler.solc.settings.remappings to truffle config<commit_after>const _ = require("lodash");
const path = require("path");
const Provider = require("@truffle/provider");
const TruffleError = require("@truffle/error");
const Module = require("module");
const findUp = require("find-up");
const originalrequire = require("original-require");
const Configstore = require("configstore");

const DEFAULT_CONFIG_FILENAME = "truffle-config.js";
const BACKUP_CONFIG_FILENAME = "truffle.js"; // old config filename

class Config {
  constructor(truffle_directory, working_directory, network) {
    const default_tx_values = {
      gas: 6721975,
      gasPrice: 20000000000, // 20 gwei,
      from: null
    };

    // This is a list of multi-level keys with defaults
    // we need to _.merge. Using this list for safety
    // vs. just merging all objects.
    this._deepCopy = ["compilers"];

    this._values = {
      truffle_directory:
        truffle_directory || path.resolve(path.join(__dirname, "../")),
      working_directory: working_directory || process.cwd(),
      network,
      networks: {},
      verboseRpc: false,
      gas: null,
      gasPrice: null,
      from: null,
      confirmations: 0,
      timeoutBlocks: 0,
      production: false,
      skipDryRun: false,
      build: null,
      resolver: null,
      artifactor: null,
      ethpm: {
        ipfs_host: "ipfs.infura.io",
        ipfs_protocol: "https",
        registry: "0x8011df4830b4f696cd81393997e5371b93338878",
        install_provider_uri: "https://ropsten.infura.io/truffle"
      },
      compilers: {
        solc: {
          settings: {
            optimizer: {
              enabled: false,
              runs: 200
            },
            remappings: []
          }
        },
        vyper: {}
      },
      logger: {
        log() {}
      }
    };

    const resolveDirectory = value =>
      path.resolve(this.working_directory, value);

    const props = {
      // These are already set.
      truffle_directory() {},
      working_directory() {},
      network() {},
      networks() {},
      verboseRpc() {},
      build() {},
      resolver() {},
      artifactor() {},
      ethpm() {},
      logger() {},
      compilers() {},

      build_directory: {
        default: () => path.join(this.working_directory, "build"),
        transform: resolveDirectory
      },
      contracts_directory: {
        default: () => path.join(this.working_directory, "contracts"),
        transform: resolveDirectory
      },
      contracts_build_directory: {
        default: () => path.join(this.build_directory, "contracts"),
        transform: resolveDirectory
      },
      migrations_directory: {
        default: () => path.join(this.working_directory, "migrations"),
        transform: resolveDirectory
      },
      migrations_file_extension_regexp() {
        return /^\.(js|es6?)$/;
      },
      test_directory: {
        default: () => path.join(this.working_directory, "test"),
        transform: resolveDirectory
      },
      test_file_extension_regexp() {
        return /.*\.(js|ts|es|es6|jsx|sol)$/;
      },
      example_project_directory: {
        default: () => path.join(this.truffle_directory, "example"),
        transform: resolveDirectory
      },
      network_id: {
        get() {
          try {
            return this.network_config.network_id;
          } catch (e) {
            return null;
          }
        },
        set() {
          throw new Error(
            "Do not set config.network_id. Instead, set config.networks and then config.networks[<network name>].network_id"
          );
        }
      },
      network_config: {
        get() {
          const network = this.network;

          if (network === null || network === undefined) {
            throw new Error(
              "Network not set. Cannot determine network to use."
            );
          }

          let conf = this.networks[network];

          if (conf === null || conf === undefined) {
            config = {};
          }

          conf = _.extend({}, default_tx_values, conf);

          return conf;
        },
        set() {
          throw new Error(
            "Don't set config.network_config. Instead, set config.networks with the desired values."
          );
        }
      },
      from: {
        get() {
          try {
            return this.network_config.from;
          } catch (e) {
            return default_tx_values.from;
          }
        },
        set() {
          throw new Error(
            "Don't set config.from directly. Instead, set config.networks and then config.networks[<network name>].from"
          );
        }
      },
      gas: {
        get() {
          try {
            return this.network_config.gas;
          } catch (e) {
            return default_tx_values.gas;
          }
        },
        set() {
          throw new Error(
            "Don't set config.gas directly. Instead, set config.networks and then config.networks[<network name>].gas"
          );
        }
      },
      gasPrice: {
        get() {
          try {
            return this.network_config.gasPrice;
          } catch (e) {
            return default_tx_values.gasPrice;
          }
        },
        set() {
          throw new Error(
            "Don't set config.gasPrice directly. Instead, set config.networks and then config.networks[<network name>].gasPrice"
          );
        }
      },
      provider: {
        get() {
          if (!this.network) {
            return null;
          }

          const options = this.network_config;
          options.verboseRpc = this.verboseRpc;

          return Provider.create(options);
        },
        set() {
          throw new Error(
            "Don't set config.provider directly. Instead, set config.networks and then set config.networks[<network name>].provider"
          );
        }
      },
      confirmations: {
        get() {
          try {
            return this.network_config.confirmations;
          } catch (e) {
            return 0;
          }
        },
        set() {
          throw new Error(
            "Don't set config.confirmations directly. Instead, set config.networks and then config.networks[<network name>].confirmations"
          );
        }
      },
      production: {
        get() {
          try {
            return this.network_config.production;
          } catch (e) {
            return false;
          }
        },
        set() {
          throw new Error(
            "Don't set config.production directly. Instead, set config.networks and then config.networks[<network name>].production"
          );
        }
      },
      timeoutBlocks: {
        get() {
          try {
            return this.network_config.timeoutBlocks;
          } catch (e) {
            return 0;
          }
        },
        set() {
          throw new Error(
            "Don't set config.timeoutBlocks directly. Instead, set config.networks and then config.networks[<network name>].timeoutBlocks"
          );
        }
      }
    };

    Object.keys(props).forEach(prop => {
      this.addProp(prop, props[prop]);
    });
  }

  addProp(propertyName, descriptor) {
    // possible property descriptors
    //
    // supports `default` and `transform` in addition to `get` and `set`
    //
    // default: specify function to retrieve default value (used by get)
    // transform: specify function to transform value when (used by set)
    Object.defineProperty(this, propertyName, {
      // retrieve config property value
      get:
        descriptor.get ||
        function() {
          // value is specified
          if (propertyName in this._values) {
            return this._values[propertyName];
          }

          // default getter is specified
          if (descriptor.default) {
            return descriptor.default();
          }

          // descriptor is a function
          return descriptor();
        },
      set:
        descriptor.set ||
        function(value) {
          this._values[propertyName] = descriptor.transform
            ? descriptor.transform(value)
            : value;
        },
      configurable: true,
      enumerable: true
    });
  }

  normalize(obj) {
    const clone = {};
    Object.keys(obj).forEach(key => {
      try {
        clone[key] = obj[key];
      } catch (e) {
        // Do nothing with values that throw.
      }
    });
    return clone;
  }

  with(obj) {
    const normalized = this.normalize(obj);
    const current = this.normalize(this);

    return _.extend(Object.create(Config.prototype), current, normalized);
  }

  merge(obj) {
    let clone = this.normalize(obj);

    // Only set keys for values that don't throw.
    const propertyNames = Object.keys(obj);

    propertyNames.forEach(key => {
      try {
        if (typeof clone[key] === "object" && this._deepCopy.includes(key)) {
          this[key] = _.merge(this[key], clone[key]);
        } else {
          this[key] = clone[key];
        }
      } catch (e) {
        // Do nothing.
      }
    });

    return this;
  }
}

Config.default = () => new Config();

Config.search = (options = {}, filename) => {
  const searchOptions = {
    cwd: options.working_directory || options.workingDirectory
  };

  if (!filename) {
    const isWin = /^win/.test(process.platform);
    const defaultConfig = findUp.sync(DEFAULT_CONFIG_FILENAME, searchOptions);
    const backupConfig = findUp.sync(BACKUP_CONFIG_FILENAME, searchOptions);
    if (defaultConfig && backupConfig) {
      console.warn(
        `Warning: Both ${DEFAULT_CONFIG_FILENAME} and ${BACKUP_CONFIG_FILENAME} were found. Using ${DEFAULT_CONFIG_FILENAME}.`
      );
      return defaultConfig;
    } else if (backupConfig && !defaultConfig) {
      if (isWin)
        console.warn(
          `Warning: Please rename ${BACKUP_CONFIG_FILENAME} to ${DEFAULT_CONFIG_FILENAME} to ensure Windows compatibility.`
        );
      return backupConfig;
    } else {
      return defaultConfig;
    }
  }

  return findUp.sync(filename, searchOptions);
};

Config.detect = (options = {}, filename) => {
  const configFile = Config.search(options, filename);

  if (!configFile) {
    throw new TruffleError("Could not find suitable configuration file.");
  }

  return Config.load(configFile, options);
};

Config.load = (file, options) => {
  const config = new Config();

  config.working_directory = path.dirname(path.resolve(file));

  // The require-nocache module used to do this for us, but
  // it doesn't bundle very well. So we've pulled it out ourselves.
  delete require.cache[Module._resolveFilename(file, module)];
  const static_config = originalrequire(file);

  config.merge(static_config);
  config.merge(options);

  return config;
};

Config.getUserConfig = () =>
  new Configstore("truffle", {}, { globalConfigPath: true });

Config.getTruffleDataDirectory = () => {
  const configStore = new Configstore(
    "truffle",
    {},
    { globalConfigPath: true }
  );
  return path.dirname(configStore.path);
};

module.exports = Config;
<|endoftext|>


<commit_before>/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*globals $: false, require: false, BUILDER: false, MVIEWER: false, editor: false*/
'use strict';

var shell = require('electron').shell;
var remote = require('remote');
 var dialog = remote.require('dialog');
 var fs = require('fs');

$(document).ready(function() {
    $('#run-button').on('click', function() {
      BUILDER.build();
    });

    $('#docs').on('click', function() {
      shell.openExternal('http://dcowden.github.io/cadquery/');
    });

    $('#videos').on('click', function() {
      shell.openExternal('https://groups.google.com/forum/#!topic/cadquery/4wPfbwxjloQ');
    });

    $('#user_group').on('click', function() {
      shell.openExternal('https://groups.google.com/forum/#!forum/cadquery');
    });

    $('#new_script').on('click', function() {
      editor.setValue("# 'import cadquery as cq' is run for you");
    });

    $('#open_script').on('click', function() {
      dialog.showOpenDialog({ filters: [{ name: 'Python', extensions: ['py'] }]}, function (fileNames) {
        if (fileNames === undefined) return;
        var fileName = fileNames[0];
        fs.readFile(fileName, 'utf-8', function (err, data) {
          editor.setValue(data);
        });
      });
    });

    //set up model viewer
    MVIEWER.init({
      initialView: 'ISO',
      width: 800,
      height: 600,
      containerId: "modelview"
    });
});
<commit_msg>Added a couple of lines to the New script template.<commit_after>/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*globals $: false, require: false, BUILDER: false, MVIEWER: false, editor: false*/
'use strict';

var shell = require('electron').shell;
var remote = require('remote');
 var dialog = remote.require('dialog');
 var fs = require('fs');

$(document).ready(function() {
    $('#run-button').on('click', function() {
      BUILDER.build();
    });

    $('#docs').on('click', function() {
      shell.openExternal('http://dcowden.github.io/cadquery/');
    });

    $('#videos').on('click', function() {
      shell.openExternal('https://groups.google.com/forum/#!topic/cadquery/4wPfbwxjloQ');
    });

    $('#user_group').on('click', function() {
      shell.openExternal('https://groups.google.com/forum/#!forum/cadquery');
    });

    $('#new_script').on('click', function() {
      editor.setValue("# 'import cadquery as cq' is run for you\n\n#Renders your scripted object\nbuild_object(result)");
    });

    $('#open_script').on('click', function() {
      dialog.showOpenDialog({ filters: [{ name: 'Python', extensions: ['py'] }]}, function (fileNames) {
        if (fileNames === undefined) return;
        var fileName = fileNames[0];
        fs.readFile(fileName, 'utf-8', function (err, data) {
          editor.setValue(data);
        });
      });
    });

    //set up model viewer
    MVIEWER.init({
      initialView: 'ISO',
      width: 800,
      height: 600,
      containerId: "modelview"
    });
});
<|endoftext|>


<commit_before>App.AskQuestionController = Ember.ArrayController.extend({
  needs: ['application'],
  sortProperties: ['date'],
  sortAscending: false,

  latestQuestions: function() {
    return this.slice(0,3);
  }.property('[]'),

  actions: {
    askQuestion: function() {
      var question = this.store.createRecord('question', {
        title: this.get('title'),
        question: this.get('question'),
        date: new Date()
      });

      this.get('controllers.application.signedInUser').then(function(user) {
        question.set('author', user);
      });

      var controller = this;

      question.save().then(function(question) {
        controller.setProperties({
          title: '',
          question: ''
        });

        controller.transitionToRoute('question', question);
      });
    }
  }
});<commit_msg>Chapter 10: Question controller with answerQuestion action<commit_after>App.AskQuestionController = Ember.ArrayController.extend({
  needs: ['application'],
  sortProperties: ['date'],
  sortAscending: false,

  latestQuestions: function() {
    return this.slice(0,3);
  }.property('[]'),

  actions: {
    askQuestion: function() {
      var question = this.store.createRecord('question', {
        title: this.get('title'),
        question: this.get('question'),
        date: new Date()
      });

      this.get('controllers.application.signedInUser').then(function(user) {
        question.set('author', user);
      });

      var controller = this;

      question.save().then(function(question) {
        controller.setProperties({
          title: '',
          question: ''
        });

        controller.transitionToRoute('question', question);
      });
    }
  }
});

App.QuestionController = Ember.ObjectController.extend({
  needs: ['application'],

  actions: {
    answerQuestion: function() {
      var answer = this.store.createRecord('answer', {
        answer: this.get('answer'),
        question: this.get('model'),
        date: new Date()
      });

      this.get('controllers.application.signedInUser').then(function(user) {
        answer.set('user', user);
      });

      var controller = this;

      answer.save().then(function(answer) {
        controller.get('model.answers').addObject(answer);

        controller.setProperties({
          answer: ''
        });
      });
    }
  }
});<|endoftext|>


<commit_before>
  const days = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];

  function isoDate ( date ) {
    return date.toISOString( ).slice( 0, 10 );
  }

  function getToday ( ) {
    return isoDate( new Date( ) );
  }

  function getMonday ( currentDate ) {
    const now = currentDate ? new Date( currentDate ) : new Date();
    const day = now.getDay( );
    const diff = now.getDate( ) - day + ( day == 0 ? -6 : 1 );

    const monday = new Date( now.setDate( diff ) );
    return isoDate( monday );
  }

  function toHours ( timeString ) {
    return timeString.split( /[:.]/ ).map(
      ( value, index ) => value * Math.pow( 60, -index )
    ).reduce(
      ( a, b ) => a + b
    );
  }

  function renderName ( user ) {
    return [
      user.name,
      user.family_name,
      user.nick_name && `(${user.nick_name})`
    ].filter(
      ( item ) => !!item
    ).join( " " );
  }

  function renderDay ( date ) {
    return days[ date.getDay() ] || "";
  }

  function renderHour ( hour ) {
    return `${hour}`.slice(0, 5);
  }

  function updatePointer ( ) {
    const now = new Date();
    const hours = now.getHours() + now.getMinutes() / 60;
    const top = ( hours - 8 ) * 50;

    const pointer = document.querySelector( ".calendar__classes-pointer" );

    if ( pointer ) {
      pointer.style.top = `${top}px`;
    }
  }

  function renderSlots(startDate, slots, calendar, displayEvery) {
    const monday = new Date( startDate );

    return new Array( 7 ).fill( monday ).map(
      ( monday, index ) => {
        const day = new Date( monday );
        day.setDate( day.getDate() + index );
        return day;
      }
    ).map(
      ( date ) => {
        let stack = slots.filter(
          // filter the slots so they will contain the slots of the current day
          ( cl ) => cl.date === isoDate( date )
        ).sort().map(
          // add number hours, and index for them
          ( cl, index ) =>
            Object.assign( {}, cl, {
              a: toHours( cl.start ),
              b: toHours( cl.finish ),
              index
            })
        ).map(
          // add edges to slots that contains the overlapping slots (bot not the actual slot)
          ( cl1, _, slots ) => Object.assign( {}, cl1, {
            edges:
              slots.filter(
                ( cl2 ) =>
                  cl1 !== cl2 && (
                    ( cl1.a <  cl2.a && cl2.a <  cl1.b ) ||
                    ( cl1.a <  cl2.b && cl2.b <  cl1.b ) ||
                    ( cl2.a <  cl1.a && cl1.a <  cl2.b ) ||
                    ( cl2.a <  cl1.b && cl1.b <  cl2.b ) ||
                    ( cl1.a == cl2.a )                   ||
                    ( cl1.b == cl2.b )
                  )
              ).map(
                ( cl ) => cl.index
              )
          })
        )

        /*
            calculate connected components of the graph
        */

        let slotsWithComponents = [];

        let componentCounter = 0;

        while ( stack.length ) {
          // pop the top of the stack
          let [ cl ] = stack.slice( -1 );

          // separate the rest into connected & not connected arrays
          let { connected, notConnected } = stack.slice( 0, -1 ).reduce(
            ( acc, item ) => ({
              connected:
                item.edges.includes( cl.index ) ? acc.connected.concat( [ item ] ) : acc.connected,
              notConnected:
                item.edges.includes( cl.index ) ? acc.notConnected : acc.notConnected.concat( [ item ] )
            }), { connected: [], notConnected: [] }
          )

          // set component if it does not present
          if ( !( "component" in cl ) ) {
            cl = Object.assign( {}, cl, { component: componentCounter++ } );
          }

          // set the component of the connected vertexes to the same
          connected = connected.map(
            ( connectedCl ) => Object.assign( {}, connectedCl, { component: cl.component } )
          );

          // we move the connected vertexes to the top of the stack
          stack = notConnected.concat( connected );

          // add the current to the output array
          slotsWithComponents = slotsWithComponents.concat( [ cl ] );
        }

        /*
            color components of the graph
        */

        let everyColoredSlots = slotsWithComponents.reduce(
          // separate them by component
          ( components, cl ) =>
            Object.assign(
              [],
              components,
              { [cl.component]: (components[ cl.component ] || []).concat( [ cl ] ) }
            )
          , []
        ).map(
          // color the components
          ( slots, _ ) => {
            let maxColor = 0;

            stack = slots.slice().sort(
              ( cl1, cl2 ) => cl1.edges.length > cl2.edges.length
            );

            let coloredSlots = [];

            while ( stack.length ) {
              let [ cl ] = stack.slice( -1 );
              stack = stack.slice( 0, -1 );

              const connectedColors = coloredSlots.filter(
                ( connectedCl ) => connectedCl.edges.includes( cl.index )
              ).map(
                ( connectedCl ) => connectedCl.color
              );

              let color = 0;

              while ( connectedColors.includes( color ) ) {
                color++;
              }

              cl = Object.assign( {}, cl, { color } );

              coloredSlots = coloredSlots.concat( [ cl ] );

              maxColor = Math.max( maxColor, color );
            }

            coloredSlots = coloredSlots.map(
              ( cl ) => Object.assign( {}, cl, { maxColor } )
            );

            return coloredSlots;
          }
        ).reduce(
          // merge the components into one array
          ( acc, component ) => acc.concat( component ), []
        )

        // console.log(s);

        return { slots: everyColoredSlots, date };
      }
    ).map(
      // calculate dimensions from the hours and colors
      ( day ) => Object.assign( {}, day, {
        slots:
          day.slots.map(
            ( cl ) => {
              const top = ( cl.a - 8 ) * 50;
              const height = ( cl.b - 8 ) * 50 - top;
              const left = cl.color / (cl.maxColor+1) * 100;
              const width = 100 / (cl.maxColor+1);

              return Object.assign( {}, cl, { top, height, left, width } );
            }
          )
      })
    ).map(
      ( day ) => `

            ${ renderDay( day.date ) }, ${ isoDate( day.date ) }

            ${
              new Array( 13 ).fill( 1 ).map(
                ( time ) => `

                `
              ).join( "" )
            }
            ${
              day.slots.map(
                ( cl, i ) => `

                      ${ cl.primary_name }

                      ${ cl.primary_users.map( ( teacher ) => renderName( teacher ) ).join( ", " ) }

                      ${ cl.place ? cl.place + "," : "" }
                      ${ renderHour( cl.start ) }-${ renderHour( cl.finish ) }

                  <div
                    class="
                      mdl-tooltip
                      ${ cl.color < cl.maxColor / 2 ? "mdl-tooltip--left" : "mdl-tooltip--right" }
                    "
                    for="${ isoDate( day.date ) }__${ cl.index }"
                  >
                    ${ cl.primary_name }

                    ${ cl.primary_users.map( ( teacher ) => renderName( teacher ) ).join( ", " ) }

                    ${ cl.place ? cl.place + "," : "" }
                    ${ renderHour( cl.start ) }-${ renderHour( cl.finish ) }

                `
              ).join( "" )
            }
            ${ isoDate(day.date) === getToday() ? "

" : "" }

      `
    ).join( "" );
  }

  function createCalendarSlots(classes, events){
    var classSlots = classes.map(function(item) {
        var slot = new Object();
        slot.primary_name = item.course_name;
        slot.secondary_name = item.term_name;
        slot.description = "";
        slot.date = item.date;
        slot.start = item.starting_at;
        slot.finish = item.finishes_at;
        slot.place = item.classroom;
        slot.primary_users = item.teachers;
        slot.seconday_users = [];
        return slot;
      });

    var eventSlots = events.map(function(item) {
        var slot = new Object();
        slot.primary_name = item.name;
        slot.secondary_name = "";
        slot.description = item.description;
        slot.date = item.date;
        slot.start = item.starting_time;
        slot.finish = item.finishing_time;
        slot.place = item.location;
        slot.primary_users = [];
        slot.seconday_users = item.users;
        return slot;
      });

    return classSlots.concat(eventSlots);
  }

  function renderCalendar ( startDate, renderedSlots, calendar, displayEvery ) {
    const monday = new Date( startDate );

    let previousMonday = new Date( startDate );
    previousMonday.setDate( monday.getDate() - 7 );

    let nextMonday = new Date( startDate );
    nextMonday.setDate( monday.getDate() + 7 );

    calendar.innerHTML = `

            previous week

            current week

            next week

          ${
            new Array(13).fill(8).map(
              ( startTime, index ) => startTime + index
            ).map(
              ( time ) => `<div class="calendar__time-hour">${ renderHour( time ) }</div>`
            ).join( "" )
          }

          ${ renderedSlots }

      ${
        ( USER_ROLE === "Teacher" || USER_ROLE === "Student" ) ?
          `

              Display every slot
              <input
                type="checkbox"
                id="calendar-switch"
                class="mdl-switch__input"
                ${ displayEvery ? "checked" : "" }
              >

`
        : ""
      }
    `;

    componentHandler.upgradeDom();

    updatePointer();
    setInterval( updatePointer, 10000 );
  }

  var calendarPointerInterval = null;

  function xhrGet ( path ) {
    return new Promise(
      function ( resolve, reject ) {
        const req = new XMLHttpRequest( );

        req.addEventListener( "load",
          function ( ) {
            var parsedData = JSON.parse( this.responseText );
            resolve(parsedData);
          }
        );

        req.addEventListener( "error", reject );

        req.open( "GET", path );
        req.setRequestHeader("authorization", `Bearer ${JWT}`)
        req.send( );
      }
    )
  }

  function loadCalendar ( displayEvery = false ) {
    const calendar = document.querySelector( ".calendar__wrapper" );

    const startDateParameter = window.location.search.slice( 1 ).split( "&" ).map(
      ( pairString ) => pairString.split( "=" ).map( decodeURIComponent )
    ).filter(
      ( pair ) => pair[0] === "date"
    );

    let startDate = startDateParameter.length && startDateParameter[0][1];
    startDate = getMonday( startDate );

    Promise.all([
      xhrGet(`/api/calendar?date=${ startDate }&my_classes=${ !displayEvery }`),
      xhrGet(`/api/events?date=${ startDate }&my_events=${ !displayEvery }`)
    ]).then(
      function ( responses ) {

        let slots = createCalendarSlots(responses[0].classes, responses[1].events)
        let renderedSlots = renderSlots(startDate, slots, calendar, displayEvery);
        renderCalendar( startDate, renderedSlots, calendar, displayEvery );

        clearInterval( calendarPointerInterval );
        updatePointer();
        calendarPointerInterval = setInterval( updatePointer, 10000 );
      }
    ).catch(
      function ( err ) {
        console.log(err);
      }
    )
  }

  function initCalendar ( ) {
    const calendar = document.querySelector( ".calendar__wrapper" );

    if ( calendar ) {
      loadCalendar();

      document.addEventListener( "change",
        function ( e ) {
          if ( e.target.id === "calendar-switch" ) {
            loadCalendar( e.target.checked )
          }
        }
      )
    }
  }

  module.exports.initCalendar = initCalendar;
<commit_msg>changes the color of slots based on if they are events or classes<commit_after>
  const days = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];

  function isoDate ( date ) {
    return date.toISOString( ).slice( 0, 10 );
  }

  function getToday ( ) {
    return isoDate( new Date( ) );
  }

  function getMonday ( currentDate ) {
    const now = currentDate ? new Date( currentDate ) : new Date();
    const day = now.getDay( );
    const diff = now.getDate( ) - day + ( day == 0 ? -6 : 1 );

    const monday = new Date( now.setDate( diff ) );
    return isoDate( monday );
  }

  function toHours ( timeString ) {
    return timeString.split( /[:.]/ ).map(
      ( value, index ) => value * Math.pow( 60, -index )
    ).reduce(
      ( a, b ) => a + b
    );
  }

  function renderName ( user ) {
    return [
      user.name,
      user.family_name,
      user.nick_name && `(${user.nick_name})`
    ].filter(
      ( item ) => !!item
    ).join( " " );
  }

  function renderDay ( date ) {
    return days[ date.getDay() ] || "";
  }

  function renderHour ( hour ) {
    return `${hour}`.slice(0, 5);
  }

  function updatePointer ( ) {
    const now = new Date();
    const hours = now.getHours() + now.getMinutes() / 60;
    const top = ( hours - 8 ) * 50;

    const pointer = document.querySelector( ".calendar__classes-pointer" );

    if ( pointer ) {
      pointer.style.top = `${top}px`;
    }
  }

  function renderSlots(startDate, slots, calendar, displayEvery) {
    const monday = new Date( startDate );

    return new Array( 7 ).fill( monday ).map(
      ( monday, index ) => {
        const day = new Date( monday );
        day.setDate( day.getDate() + index );
        return day;
      }
    ).map(
      ( date ) => {
        let stack = slots.filter(
          // filter the slots so they will contain the slots of the current day
          ( cl ) => cl.date === isoDate( date )
        ).sort().map(
          // add number hours, and index for them
          ( cl, index ) =>
            Object.assign( {}, cl, {
              a: toHours( cl.start ),
              b: toHours( cl.finish ),
              index
            })
        ).map(
          // add edges to slots that contains the overlapping slots (bot not the actual slot)
          ( cl1, _, slots ) => Object.assign( {}, cl1, {
            edges:
              slots.filter(
                ( cl2 ) =>
                  cl1 !== cl2 && (
                    ( cl1.a <  cl2.a && cl2.a <  cl1.b ) ||
                    ( cl1.a <  cl2.b && cl2.b <  cl1.b ) ||
                    ( cl2.a <  cl1.a && cl1.a <  cl2.b ) ||
                    ( cl2.a <  cl1.b && cl1.b <  cl2.b ) ||
                    ( cl1.a == cl2.a )                   ||
                    ( cl1.b == cl2.b )
                  )
              ).map(
                ( cl ) => cl.index
              )
          })
        )

        /*
            calculate connected components of the graph
        */

        let slotsWithComponents = [];

        let componentCounter = 0;

        while ( stack.length ) {
          // pop the top of the stack
          let [ cl ] = stack.slice( -1 );

          // separate the rest into connected & not connected arrays
          let { connected, notConnected } = stack.slice( 0, -1 ).reduce(
            ( acc, item ) => ({
              connected:
                item.edges.includes( cl.index ) ? acc.connected.concat( [ item ] ) : acc.connected,
              notConnected:
                item.edges.includes( cl.index ) ? acc.notConnected : acc.notConnected.concat( [ item ] )
            }), { connected: [], notConnected: [] }
          )

          // set component if it does not present
          if ( !( "component" in cl ) ) {
            cl = Object.assign( {}, cl, { component: componentCounter++ } );
          }

          // set the component of the connected vertexes to the same
          connected = connected.map(
            ( connectedCl ) => Object.assign( {}, connectedCl, { component: cl.component } )
          );

          // we move the connected vertexes to the top of the stack
          stack = notConnected.concat( connected );

          // add the current to the output array
          slotsWithComponents = slotsWithComponents.concat( [ cl ] );
        }

        /*
            color components of the graph
        */

        let everyColoredSlots = slotsWithComponents.reduce(
          // separate them by component
          ( components, cl ) =>
            Object.assign(
              [],
              components,
              { [cl.component]: (components[ cl.component ] || []).concat( [ cl ] ) }
            )
          , []
        ).map(
          // color the components
          ( slots, _ ) => {
            let maxColor = 0;

            stack = slots.slice().sort(
              ( cl1, cl2 ) => cl1.edges.length > cl2.edges.length
            );

            let coloredSlots = [];

            while ( stack.length ) {
              let [ cl ] = stack.slice( -1 );
              stack = stack.slice( 0, -1 );

              const connectedColors = coloredSlots.filter(
                ( connectedCl ) => connectedCl.edges.includes( cl.index )
              ).map(
                ( connectedCl ) => connectedCl.color
              );

              let color = 0;

              while ( connectedColors.includes( color ) ) {
                color++;
              }

              cl = Object.assign( {}, cl, { color } );

              coloredSlots = coloredSlots.concat( [ cl ] );

              maxColor = Math.max( maxColor, color );
            }

            coloredSlots = coloredSlots.map(
              ( cl ) => Object.assign( {}, cl, { maxColor } )
            );

            return coloredSlots;
          }
        ).reduce(
          // merge the components into one array
          ( acc, component ) => acc.concat( component ), []
        )

        // console.log(s);

        return { slots: everyColoredSlots, date };
      }
    ).map(
      // calculate dimensions from the hours and colors
      ( day ) => Object.assign( {}, day, {
        slots:
          day.slots.map(
            ( cl ) => {
              const top = ( cl.a - 8 ) * 50;
              const height = ( cl.b - 8 ) * 50 - top;
              const left = cl.color / (cl.maxColor+1) * 100;
              const width = 100 / (cl.maxColor+1);

              return Object.assign( {}, cl, { top, height, left, width } );
            }
          )
      })
    ).map(
      ( day ) => `

            ${ renderDay( day.date ) }, ${ isoDate( day.date ) }

            ${
              new Array( 13 ).fill( 1 ).map(
                ( time ) => `

                `
              ).join( "" )
            }
            ${
              day.slots.map(
                ( cl, i ) => `

                      ${ cl.primary_name }

                      ${ cl.primary_users.map( ( teacher ) => renderName( teacher ) ).join( ", " ) }

                      ${ cl.place ? cl.place + "," : "" }
                      ${ renderHour( cl.start ) }-${ renderHour( cl.finish ) }

                  <div
                    class="
                      mdl-tooltip
                      ${ cl.color < cl.maxColor / 2 ? "mdl-tooltip--left" : "mdl-tooltip--right" }
                    "
                    for="${ isoDate( day.date ) }__${ cl.index }"
                  >
                    ${ cl.primary_name }

                    ${ cl.primary_users.map( ( teacher ) => renderName( teacher ) ).join( ", " ) }

                    ${ cl.place ? cl.place + "," : "" }
                    ${ renderHour( cl.start ) }-${ renderHour( cl.finish ) }

                `
              ).join( "" )
            }
            ${ isoDate(day.date) === getToday() ? "

" : "" }

      `
    ).join( "" );
  }

  function createCalendarSlots(classes, events){
    var classSlots = classes.map(function(item) {
        var slot = new Object();
        slot.primary_name = item.course_name;
        slot.secondary_name = item.term_name;
        slot.description = "";
        slot.date = item.date;
        slot.start = item.starting_at;
        slot.finish = item.finishes_at;
        slot.place = item.classroom;
        slot.primary_users = item.teachers;
        slot.seconday_users = [];
        slot.color_css_class = "calendar__slot_green";
        return slot;
      });

    var eventSlots = events.map(function(item) {
        var slot = new Object();
        slot.primary_name = item.name;
        slot.secondary_name = "";
        slot.description = item.description;
        slot.date = item.date;
        slot.start = item.starting_time;
        slot.finish = item.finishing_time;
        slot.place = item.location;
        slot.primary_users = [];
        slot.seconday_users = item.users;
        slot.color_css_class = "calendar__slot_red";
        return slot;
      });

    return classSlots.concat(eventSlots);
  }

  function renderCalendar ( startDate, renderedSlots, calendar, displayEvery ) {
    const monday = new Date( startDate );

    let previousMonday = new Date( startDate );
    previousMonday.setDate( monday.getDate() - 7 );

    let nextMonday = new Date( startDate );
    nextMonday.setDate( monday.getDate() + 7 );

    calendar.innerHTML = `

            previous week

            current week

            next week

          ${
            new Array(13).fill(8).map(
              ( startTime, index ) => startTime + index
            ).map(
              ( time ) => `<div class="calendar__time-hour">${ renderHour( time ) }</div>`
            ).join( "" )
          }

          ${ renderedSlots }

      ${
        ( USER_ROLE === "Teacher" || USER_ROLE === "Student" ) ?
          `

              Display every slot
              <input
                type="checkbox"
                id="calendar-switch"
                class="mdl-switch__input"
                ${ displayEvery ? "checked" : "" }
              >

`
        : ""
      }
    `;

    componentHandler.upgradeDom();

    updatePointer();
    setInterval( updatePointer, 10000 );
  }

  var calendarPointerInterval = null;

  function xhrGet ( path ) {
    return new Promise(
      function ( resolve, reject ) {
        const req = new XMLHttpRequest( );

        req.addEventListener( "load",
          function ( ) {
            var parsedData = JSON.parse( this.responseText );
            resolve(parsedData);
          }
        );

        req.addEventListener( "error", reject );

        req.open( "GET", path );
        req.setRequestHeader("authorization", `Bearer ${JWT}`)
        req.send( );
      }
    )
  }

  function loadCalendar ( displayEvery = false ) {
    const calendar = document.querySelector( ".calendar__wrapper" );

    const startDateParameter = window.location.search.slice( 1 ).split( "&" ).map(
      ( pairString ) => pairString.split( "=" ).map( decodeURIComponent )
    ).filter(
      ( pair ) => pair[0] === "date"
    );

    let startDate = startDateParameter.length && startDateParameter[0][1];
    startDate = getMonday( startDate );

    Promise.all([
      xhrGet(`/api/calendar?date=${ startDate }&my_classes=${ !displayEvery }`),
      xhrGet(`/api/events?date=${ startDate }&my_events=${ !displayEvery }`)
    ]).then(
      function ( responses ) {

        let slots = createCalendarSlots(responses[0].classes, responses[1].events)
        let renderedSlots = renderSlots(startDate, slots, calendar, displayEvery);
        renderCalendar( startDate, renderedSlots, calendar, displayEvery );

        clearInterval( calendarPointerInterval );
        updatePointer();
        calendarPointerInterval = setInterval( updatePointer, 10000 );
      }
    ).catch(
      function ( err ) {
        console.log(err);
      }
    )
  }

  function initCalendar ( ) {
    const calendar = document.querySelector( ".calendar__wrapper" );

    if ( calendar ) {
      loadCalendar();

      document.addEventListener( "change",
        function ( e ) {
          if ( e.target.id === "calendar-switch" ) {
            loadCalendar( e.target.checked )
          }
        }
      )
    }
  }

  module.exports.initCalendar = initCalendar;
<|endoftext|>


<commit_before>/**
 * cq Query Resolver
 *
 * This file takes input code and a parsed query and extracts portions of the
 * code based on that query
 *
 */
import traverse from 'babel-traverse';
import parser from './query-parser';

import babylonEngine from './engines/babylon';
import typescriptEngine from './engines/typescript';
import { rangeExtents } from './engines/util';

import debugLib from 'debug';
const debug = debugLib('cq');

export const NodeTypes = {
  IDENTIFIER: 'IDENTIFIER',
  RANGE: 'RANGE',
  LINE_NUMBER: 'LINE_NUMBER',
  STRING: 'STRING',
  CALL_EXPRESSION: 'CALL_EXPRESSION'
};

const whitespace = new Set([' ', '\n', '\t', '\r']);

function nextNewlinePos(code, start) {
  let pos = start;
  while(pos < code.length && code[pos] !== '\n') {
    pos++;
  }
  return pos;
}

function isNumeric(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function movePositionByLines(code, numLines, position, opts={}) {
  if(numLines < 0) {
    let numPreviousLines = numLines * -1;
    position--;
    while(position > 0 && numPreviousLines > 0) {
      position--;
      if(code[position] === '\n') {
        numPreviousLines--;
      }
    }
    if(opts.trimNewline) position++; // don't include prior newline
  } else if(numLines > 0) {
    let numFollowingLines = numLines;
    position++;
    while(position < code.length && numFollowingLines > 0) {
      if(code[position] === '\n') {
        numFollowingLines--;
      }
      position++;
    }
    if(opts.trimNewline) position--; // don't include the last newline
  }

  return position;
}

function adjustRangeWithContext(code, linesBefore, linesAfter, {start, end}) {
  if(linesBefore && linesBefore !== 0) {
    let trimNewline = linesBefore > 0 ? true : false;
    start = movePositionByLines(code, -1 * linesBefore, start, {trimNewline});
  }

  if(linesAfter && linesAfter !== 0) {
    let trimNewline = linesAfter > 0 ? true : false;
    end = movePositionByLines(code, linesAfter, end, {trimNewline});
  }

  return {start, end};
}

function adjustRangeWithWindow(code, startingLine, endingLine, {start, end}) {
  // start, end are the range for the whole node
  let originalStart = start;

  if(isNumeric(startingLine)) {
    let trimNewline = startingLine > 0 ? false : true;
    start = movePositionByLines(code, startingLine, start, {trimNewline});
  }

  if(endingLine === 0) {
    end = nextNewlinePos(code, start);
    return {start, end};
  }

  if(isNumeric(endingLine)) {
    let trimNewline = endingLine > 0 ? true : false;
    let eol = nextNewlinePos(code, originalStart);
    end = movePositionByLines(code, endingLine, eol /* <- notice */, {trimNewline});
  }

  return {start, end};
}

function adjustRangeForComments(ast, code, leading, trailing, engine, {start, end, nodes}) {
  // this is going to be part of the engine

  nodes.map((node) => {
    let commentRange = engine.commentRange(node, code, leading, trailing);
    start = commentRange.start ? Math.min(commentRange.start, start) : start;
    end = commentRange.end ? Math.max(commentRange.end, end) : end;
  });

  return {start, end, nodes};
}

function adjustRangeForDecorators(ast, code, leading, trailing, engine, {start, end, nodes}) {
  nodes.map((node) => {
    let decoratorsRange = rangeExtents(node.decorators.map(d => engine.nodeToRange(d)));
    start = decoratorsRange.start ? Math.min(decoratorsRange.start, start) : start;
    end = decoratorsRange.end ? Math.max(decoratorsRange.end, end) : end;
  });

  return {start, end, nodes};
}

function modifyAnswerWithCall(ast, code, callee, args, engine, {start, end, nodes}) {
  switch(callee) {
  case 'upto':
    start--;
    // trim all of the whitespace before. TODO could be to make this optional
    while(start > 0 && whitespace.has(code[start])) {
      start--;
    }
    start++;
    return {start: start, end:start};
    break;
  case 'context':
    let [linesBefore, linesAfter] = args;
    return adjustRangeWithContext(code, linesBefore.value, linesAfter.value, {start, end})
    break;
  case 'window':
    let [startingLine, endingLine] = args;
    return adjustRangeWithWindow(code, startingLine.value, endingLine.value, {start, end})
    break;
  case 'comments':
    let leading = true, trailing = false;
    return adjustRangeForComments(ast, code, leading, trailing, engine, {start, end, nodes})
    break;
  case 'decorators':
    return adjustRangeForDecorators(ast, code, leading, trailing, engine, {start, end, nodes})
  default:
    throw new Error(`Unknown function call: ${callee}`);
  }
}

/*
 * Gets the range from a node and extends it to the preceeding and following
 * newlines
 */
function nodeToRangeLines(node, code, engine) {
  let range = engine.nodeToRange(node);

  // we want to keep starting indentation, so search back to the previous
  // newline
  let start = range.start;
  while(start > 0 && code[start] !== '\n') {
    start--;
  }
  start++; // don't include the newline

  // we also want to read to the end of the line for the node we found
  let end = range.end;
  while(end < code.length && code[end] !== '\n') {
    end++;
  }

  return {start,end};
}

function resolveSearchedQueryWithNodes(ast, root, code, query, engine, nodes, opts) {
  let nextRoot;

  // nodeIdx doesn't apply until there are no children e.g. if the parent is
  // specifying a nodeIdx, the idea is to apply to the childmost node, so pick
  // zero in the case where we have a child and pass on the opt
  let nodeIdx = (isNumeric(opts.nodeIdx) && !query.children) ? opts.nodeIdx : 0;

  if(opts.after) {
    for(let i=0; i<nodes.length; i++) {
      let node = nodes[i];
      let nodeRange = engine.nodeToRange(node);
      if(nodeRange.start >= opts.after) {
        nextRoot = node;
        break;
      }
    }
  } else {
    nextRoot = nodes[nodeIdx];
  }

  if(!nextRoot) {
    let unknownQueryError = new Error(`Cannot find node for query: ${query.matcher} (match ${nodeIdx})`);
    unknownQueryError.query = query;
    throw unknownQueryError;
  }

  if(query.children) {
    let resolvedChildren;
    let lastError;

    // search through all possible nodes for children that would result in a valid query
    for(let i=0; i<nodes.length; i++) {
      try {
        nextRoot = nodes[i];
        resolvedChildren = resolveListOfQueries(ast, nextRoot, code, query.children, engine, opts);
        return resolvedChildren;
      } catch (e) {
        if(e.query) { // keep this error but try the next node, if we have one
          lastError = e
        } else { // we don't recognize this error, throw it
          throw e
        }
      }
    }
    throw lastError; // really couldn't find one

  } else {
    let { start, end } = nodeToRangeLines(nextRoot, code, engine);
    let codeSlice = code.substring(start, end);
    return { code: codeSlice, nodes: [ nextRoot ], start, end };
  }
}

function resolveIndividualQuery(ast, root, code, query, engine, opts) {
  switch(query.type) {
  case NodeTypes.CALL_EXPRESSION: {
    let callee = query.callee;
    // for now, the first argument is always the inner selection
    let [childQuery, ...args] = query.arguments;

    let handled = false;
    // some operators modify before the target query
    // e.g. after() actually has two queries
    // TODO clean this up to unify design with `modifyAnswerWithCall`. `handled` is icky
    switch(callee) {
    case 'after':
      handled = true;
      let [ goalpostQuery ] = args;
      let goalpostNode = resolveIndividualQuery(ast, root, code, goalpostQuery, engine, opts);
      opts.after = goalpostNode.end;
      break;
    case 'choose':
      handled = true;
      let [ nodeIdx ] = args;
      opts.nodeIdx = nodeIdx.value;
      break;
    }

    let answer = resolveIndividualQuery(ast, root, code, childQuery, engine, opts);

    // whatever the child answer is, now we modify it given our callee
    // TODO - modifying the asnwer needs to be given not only the answer start and end range, but the child node which returned that start and end
    if(!handled) {
      answer = modifyAnswerWithCall(ast, code, callee, args, engine, answer);
    }

    // hmm, maybe do this later in the pipeline?
    answer.code = code.substring(answer.start, answer.end);

    // get the rest of the parameters
    return answer;
  }
  case NodeTypes.IDENTIFIER:
  case NodeTypes.STRING: {
    let matchingNodes;

    switch(query.type) {
    case NodeTypes.IDENTIFIER:
      matchingNodes = engine.findNodesWithIdentifier(ast, root, query);
      break;
    case NodeTypes.STRING:
      matchingNodes = engine.findNodesWithString(ast, root, query);
      break;
    }

    return resolveSearchedQueryWithNodes(ast, root, code, query, engine, matchingNodes, opts);

  }
  case NodeTypes.RANGE: {
    let rangeStart = resolveIndividualQuery(ast, root, code, query.start, engine, opts);
    let start = rangeStart.start;
    let rangeEnd = resolveIndividualQuery(ast, root, code, query.end, engine,
                                          Object.assign({}, opts, {after: rangeStart.start}));
    let end = rangeEnd.end;
    let codeSlice = code.substring(start, end);
    let nodes = [...(rangeStart.nodes || []), ...(rangeEnd.nodes || [])]
    return { code: codeSlice, nodes, start, end };
  }
  case NodeTypes.LINE_NUMBER: {

    // Parse special line numbers like EOF
    if(typeof query.value === 'string') {
      switch(query.value) {
      case 'EOF':
        return { code: '', start: code.length, end: code.length };
        break;
      default:
        throw new Error(`Unknown LINE_NUMBER: ${query.value}`);
      }
    } else {

      if(query.value === 0) {
        throw new Error(`Line numbers start at 1, not 0`);
      }

      // find the acutal line number
      let lines = code.split('\n');
      let line = lines[query.value - 1]; // one-indexed arguments to LINE_NUMBER

      // to get the starting index of this line...
      // we take the sum of all prior lines:
      let charIdx = lines.slice(0, query.value - 1).reduce(
        // + 1 b/c of the (now missing) newline
        (sum, line) => (sum + line.length + 1), 0);

      let start = charIdx;
      let end = charIdx + line.length;
      let codeSlice = code.substring(start, end);
      let nodes = []; // TODO - find the node that applies to this line number
      return { code: codeSlice, nodes, start, end };
    }

  }
  default:
    break;
  }

}

// given code, removes the smallest indent from each line (e.g. nested code becomes less-indented to the least indented line)
function undent(code) {
  let lines = code.split("\n");
  let minIndent = Number.MAX_VALUE;

  // find min indent
  lines.forEach((line) => {
    let startingSpaceMatch = line.match(/^\s*/);
    let indentLength = startingSpaceMatch[0].length;
    if(indentLength < minIndent) {
      minIndent = indentLength;
    }
  })

  // remove the indentation from each line
  return lines.map((line) => {
    return line.substring(minIndent);
  }).join('\n');
}

// given character index idx in code, returns the 1-indexed line number
function lineNumberOfCharacterIndex(code, idx) {
  const everythingUpUntilTheIndex = code.substring(0, idx);
  // computer science!
  return everythingUpUntilTheIndex.split('\n').length;
}

function resolveListOfQueries(ast, root, code, query, engine, opts) {
  return query.reduce((acc, q) => {
    let resolved = resolveIndividualQuery(ast, root, code, q, engine, opts);
    // thought: maybe do something clever here like put in a comment ellipsis if
    // the queries aren't contiguous
    acc.code = acc.code + resolved.code;
    acc.nodes = [...acc.nodes, resolved.node];
    acc.start = Math.min(acc.start, resolved.start);
    acc.end = Math.max(acc.end, resolved.end);
    acc.start_line = Math.min(acc.start_line, lineNumberOfCharacterIndex(code, resolved.start));
    acc.end_line = Math.max(acc.end_line, lineNumberOfCharacterIndex(code, resolved.end));
    return acc;
  }, {
    code: '',
    nodes: [],
    start: Number.MAX_VALUE,
    end: Number.MIN_VALUE,
    start_line: Number.MAX_VALUE,
    end_line: Number.MIN_VALUE
  })
}

export default async function cq(code, query, opts={}) {
  let engine = opts.engine || babylonEngine();

  if(typeof query === 'string') {
    query = [ parser.parse(query) ]; // parser returns single object for now, but eventually an array
  }

  if(typeof engine === 'string') {
    switch(engine) {
    case 'typescript':
      engine = typescriptEngine();
      break;
    case 'babylon':
      engine = babylonEngine();
      break;
    default:
      try {
        engine = require(`cq-${engine}-engine`);
      } catch (err) {
        throw new Error('unknown engine: ' + engine);
      }
      break;
    }
  }

  if(typeof engine === 'function') {
    // then just use it
  }

  debug(code);
  let ast = engine.parse(code, Object.assign({}, opts.parserOpts));
  debug(ast);
  let root = engine.getInitialRoot(ast);

  let results = resolveListOfQueries(ast, root, code, query, engine, opts);

  if(opts.undent) {
    results.code = undent(results.code);
  }

  return results;
}
<commit_msg>allow parse to be async<commit_after>/**
 * cq Query Resolver
 *
 * This file takes input code and a parsed query and extracts portions of the
 * code based on that query
 *
 */
import traverse from 'babel-traverse';
import parser from './query-parser';

import babylonEngine from './engines/babylon';
import typescriptEngine from './engines/typescript';
import { rangeExtents } from './engines/util';

import debugLib from 'debug';
const debug = debugLib('cq');

export const NodeTypes = {
  IDENTIFIER: 'IDENTIFIER',
  RANGE: 'RANGE',
  LINE_NUMBER: 'LINE_NUMBER',
  STRING: 'STRING',
  CALL_EXPRESSION: 'CALL_EXPRESSION'
};

const whitespace = new Set([' ', '\n', '\t', '\r']);

function nextNewlinePos(code, start) {
  let pos = start;
  while(pos < code.length && code[pos] !== '\n') {
    pos++;
  }
  return pos;
}

function isNumeric(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function movePositionByLines(code, numLines, position, opts={}) {
  if(numLines < 0) {
    let numPreviousLines = numLines * -1;
    position--;
    while(position > 0 && numPreviousLines > 0) {
      position--;
      if(code[position] === '\n') {
        numPreviousLines--;
      }
    }
    if(opts.trimNewline) position++; // don't include prior newline
  } else if(numLines > 0) {
    let numFollowingLines = numLines;
    position++;
    while(position < code.length && numFollowingLines > 0) {
      if(code[position] === '\n') {
        numFollowingLines--;
      }
      position++;
    }
    if(opts.trimNewline) position--; // don't include the last newline
  }

  return position;
}

function adjustRangeWithContext(code, linesBefore, linesAfter, {start, end}) {
  if(linesBefore && linesBefore !== 0) {
    let trimNewline = linesBefore > 0 ? true : false;
    start = movePositionByLines(code, -1 * linesBefore, start, {trimNewline});
  }

  if(linesAfter && linesAfter !== 0) {
    let trimNewline = linesAfter > 0 ? true : false;
    end = movePositionByLines(code, linesAfter, end, {trimNewline});
  }

  return {start, end};
}

function adjustRangeWithWindow(code, startingLine, endingLine, {start, end}) {
  // start, end are the range for the whole node
  let originalStart = start;

  if(isNumeric(startingLine)) {
    let trimNewline = startingLine > 0 ? false : true;
    start = movePositionByLines(code, startingLine, start, {trimNewline});
  }

  if(endingLine === 0) {
    end = nextNewlinePos(code, start);
    return {start, end};
  }

  if(isNumeric(endingLine)) {
    let trimNewline = endingLine > 0 ? true : false;
    let eol = nextNewlinePos(code, originalStart);
    end = movePositionByLines(code, endingLine, eol /* <- notice */, {trimNewline});
  }

  return {start, end};
}

function adjustRangeForComments(ast, code, leading, trailing, engine, {start, end, nodes}) {
  // this is going to be part of the engine

  nodes.map((node) => {
    let commentRange = engine.commentRange(node, code, leading, trailing);
    start = commentRange.start ? Math.min(commentRange.start, start) : start;
    end = commentRange.end ? Math.max(commentRange.end, end) : end;
  });

  return {start, end, nodes};
}

function adjustRangeForDecorators(ast, code, leading, trailing, engine, {start, end, nodes}) {
  nodes.map((node) => {
    let decoratorsRange = rangeExtents(node.decorators.map(d => engine.nodeToRange(d)));
    start = decoratorsRange.start ? Math.min(decoratorsRange.start, start) : start;
    end = decoratorsRange.end ? Math.max(decoratorsRange.end, end) : end;
  });

  return {start, end, nodes};
}

function modifyAnswerWithCall(ast, code, callee, args, engine, {start, end, nodes}) {
  switch(callee) {
  case 'upto':
    start--;
    // trim all of the whitespace before. TODO could be to make this optional
    while(start > 0 && whitespace.has(code[start])) {
      start--;
    }
    start++;
    return {start: start, end:start};
    break;
  case 'context':
    let [linesBefore, linesAfter] = args;
    return adjustRangeWithContext(code, linesBefore.value, linesAfter.value, {start, end})
    break;
  case 'window':
    let [startingLine, endingLine] = args;
    return adjustRangeWithWindow(code, startingLine.value, endingLine.value, {start, end})
    break;
  case 'comments':
    let leading = true, trailing = false;
    return adjustRangeForComments(ast, code, leading, trailing, engine, {start, end, nodes})
    break;
  case 'decorators':
    return adjustRangeForDecorators(ast, code, leading, trailing, engine, {start, end, nodes})
  default:
    throw new Error(`Unknown function call: ${callee}`);
  }
}

/*
 * Gets the range from a node and extends it to the preceeding and following
 * newlines
 */
function nodeToRangeLines(node, code, engine) {
  let range = engine.nodeToRange(node);

  // we want to keep starting indentation, so search back to the previous
  // newline
  let start = range.start;
  while(start > 0 && code[start] !== '\n') {
    start--;
  }
  start++; // don't include the newline

  // we also want to read to the end of the line for the node we found
  let end = range.end;
  while(end < code.length && code[end] !== '\n') {
    end++;
  }

  return {start,end};
}

function resolveSearchedQueryWithNodes(ast, root, code, query, engine, nodes, opts) {
  let nextRoot;

  // nodeIdx doesn't apply until there are no children e.g. if the parent is
  // specifying a nodeIdx, the idea is to apply to the childmost node, so pick
  // zero in the case where we have a child and pass on the opt
  let nodeIdx = (isNumeric(opts.nodeIdx) && !query.children) ? opts.nodeIdx : 0;

  if(opts.after) {
    for(let i=0; i<nodes.length; i++) {
      let node = nodes[i];
      let nodeRange = engine.nodeToRange(node);
      if(nodeRange.start >= opts.after) {
        nextRoot = node;
        break;
      }
    }
  } else {
    nextRoot = nodes[nodeIdx];
  }

  if(!nextRoot) {
    let unknownQueryError = new Error(`Cannot find node for query: ${query.matcher} (match ${nodeIdx})`);
    unknownQueryError.query = query;
    throw unknownQueryError;
  }

  if(query.children) {
    let resolvedChildren;
    let lastError;

    // search through all possible nodes for children that would result in a valid query
    for(let i=0; i<nodes.length; i++) {
      try {
        nextRoot = nodes[i];
        resolvedChildren = resolveListOfQueries(ast, nextRoot, code, query.children, engine, opts);
        return resolvedChildren;
      } catch (e) {
        if(e.query) { // keep this error but try the next node, if we have one
          lastError = e
        } else { // we don't recognize this error, throw it
          throw e
        }
      }
    }
    throw lastError; // really couldn't find one

  } else {
    let { start, end } = nodeToRangeLines(nextRoot, code, engine);
    let codeSlice = code.substring(start, end);
    return { code: codeSlice, nodes: [ nextRoot ], start, end };
  }
}

function resolveIndividualQuery(ast, root, code, query, engine, opts) {
  switch(query.type) {
  case NodeTypes.CALL_EXPRESSION: {
    let callee = query.callee;
    // for now, the first argument is always the inner selection
    let [childQuery, ...args] = query.arguments;

    let handled = false;
    // some operators modify before the target query
    // e.g. after() actually has two queries
    // TODO clean this up to unify design with `modifyAnswerWithCall`. `handled` is icky
    switch(callee) {
    case 'after':
      handled = true;
      let [ goalpostQuery ] = args;
      let goalpostNode = resolveIndividualQuery(ast, root, code, goalpostQuery, engine, opts);
      opts.after = goalpostNode.end;
      break;
    case 'choose':
      handled = true;
      let [ nodeIdx ] = args;
      opts.nodeIdx = nodeIdx.value;
      break;
    }

    let answer = resolveIndividualQuery(ast, root, code, childQuery, engine, opts);

    // whatever the child answer is, now we modify it given our callee
    // TODO - modifying the asnwer needs to be given not only the answer start and end range, but the child node which returned that start and end
    if(!handled) {
      answer = modifyAnswerWithCall(ast, code, callee, args, engine, answer);
    }

    // hmm, maybe do this later in the pipeline?
    answer.code = code.substring(answer.start, answer.end);

    // get the rest of the parameters
    return answer;
  }
  case NodeTypes.IDENTIFIER:
  case NodeTypes.STRING: {
    let matchingNodes;

    switch(query.type) {
    case NodeTypes.IDENTIFIER:
      matchingNodes = engine.findNodesWithIdentifier(ast, root, query);
      break;
    case NodeTypes.STRING:
      matchingNodes = engine.findNodesWithString(ast, root, query);
      break;
    }

    return resolveSearchedQueryWithNodes(ast, root, code, query, engine, matchingNodes, opts);

  }
  case NodeTypes.RANGE: {
    let rangeStart = resolveIndividualQuery(ast, root, code, query.start, engine, opts);
    let start = rangeStart.start;
    let rangeEnd = resolveIndividualQuery(ast, root, code, query.end, engine,
                                          Object.assign({}, opts, {after: rangeStart.start}));
    let end = rangeEnd.end;
    let codeSlice = code.substring(start, end);
    let nodes = [...(rangeStart.nodes || []), ...(rangeEnd.nodes || [])]
    return { code: codeSlice, nodes, start, end };
  }
  case NodeTypes.LINE_NUMBER: {

    // Parse special line numbers like EOF
    if(typeof query.value === 'string') {
      switch(query.value) {
      case 'EOF':
        return { code: '', start: code.length, end: code.length };
        break;
      default:
        throw new Error(`Unknown LINE_NUMBER: ${query.value}`);
      }
    } else {

      if(query.value === 0) {
        throw new Error(`Line numbers start at 1, not 0`);
      }

      // find the acutal line number
      let lines = code.split('\n');
      let line = lines[query.value - 1]; // one-indexed arguments to LINE_NUMBER

      // to get the starting index of this line...
      // we take the sum of all prior lines:
      let charIdx = lines.slice(0, query.value - 1).reduce(
        // + 1 b/c of the (now missing) newline
        (sum, line) => (sum + line.length + 1), 0);

      let start = charIdx;
      let end = charIdx + line.length;
      let codeSlice = code.substring(start, end);
      let nodes = []; // TODO - find the node that applies to this line number
      return { code: codeSlice, nodes, start, end };
    }

  }
  default:
    break;
  }

}

// given code, removes the smallest indent from each line (e.g. nested code becomes less-indented to the least indented line)
function undent(code) {
  let lines = code.split("\n");
  let minIndent = Number.MAX_VALUE;

  // find min indent
  lines.forEach((line) => {
    let startingSpaceMatch = line.match(/^\s*/);
    let indentLength = startingSpaceMatch[0].length;
    if(indentLength < minIndent) {
      minIndent = indentLength;
    }
  })

  // remove the indentation from each line
  return lines.map((line) => {
    return line.substring(minIndent);
  }).join('\n');
}

// given character index idx in code, returns the 1-indexed line number
function lineNumberOfCharacterIndex(code, idx) {
  const everythingUpUntilTheIndex = code.substring(0, idx);
  // computer science!
  return everythingUpUntilTheIndex.split('\n').length;
}

function resolveListOfQueries(ast, root, code, query, engine, opts) {
  return query.reduce((acc, q) => {
    let resolved = resolveIndividualQuery(ast, root, code, q, engine, opts);
    // thought: maybe do something clever here like put in a comment ellipsis if
    // the queries aren't contiguous
    acc.code = acc.code + resolved.code;
    acc.nodes = [...acc.nodes, resolved.node];
    acc.start = Math.min(acc.start, resolved.start);
    acc.end = Math.max(acc.end, resolved.end);
    acc.start_line = Math.min(acc.start_line, lineNumberOfCharacterIndex(code, resolved.start));
    acc.end_line = Math.max(acc.end_line, lineNumberOfCharacterIndex(code, resolved.end));
    return acc;
  }, {
    code: '',
    nodes: [],
    start: Number.MAX_VALUE,
    end: Number.MIN_VALUE,
    start_line: Number.MAX_VALUE,
    end_line: Number.MIN_VALUE
  })
}

export default async function cq(code, query, opts={}) {
  let engine = opts.engine || babylonEngine();

  if(typeof query === 'string') {
    query = [ parser.parse(query) ]; // parser returns single object for now, but eventually an array
  }

  if(typeof engine === 'string') {
    switch(engine) {
    case 'typescript':
      engine = typescriptEngine();
      break;
    case 'babylon':
      engine = babylonEngine();
      break;
    default:
      try {
        engine = require(`cq-${engine}-engine`);
      } catch (err) {
        throw new Error('unknown engine: ' + engine);
      }
      break;
    }
  }

  if(typeof engine === 'function') {
    // then just use it
  }

  debug(code);
  let ast = await Promise.resolve(engine.parse(code, Object.assign({}, opts.parserOpts)));
  debug(ast);
  let root = engine.getInitialRoot(ast);
  let results = resolveListOfQueries(ast, root, code, query, engine, opts);

  if(opts.undent) {
    results.code = undent(results.code);
  }

  return results;
}
<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
/*global require, db, ArangoCollection, ArangoDatabase, ArangoCursor, module,
         ShapedJson, RELOAD_AUTH, SYS_DEFINE_ACTION, SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION,
         AHUACATL_RUN, AHUACATL_PARSE, AHUACATL_EXPLAIN */

////////////////////////////////////////////////////////////////////////////////
/// @brief module "internal"
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-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 Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                 Module "internal"
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////

(function () {
  var internal = require("internal");
  var console = require("console");

////////////////////////////////////////////////////////////////////////////////
/// @brief hide global variables
////////////////////////////////////////////////////////////////////////////////

  internal.db = db;
  delete db;

  internal.ArangoCollection = ArangoCollection;
  delete ArangoCollection;

  internal.ArangoDatabase = ArangoDatabase;
  delete ArangoDatabase;

  internal.ArangoCursor = ArangoCursor;
  delete ArangoCursor;

  internal.ShapedJson = ShapedJson;
  delete ShapedJson;

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief execute an AQL query
////////////////////////////////////////////////////////////////////////////////

  internal.AQL_QUERY = AHUACATL_RUN;
  delete AHUACATL_RUN;

////////////////////////////////////////////////////////////////////////////////
/// @brief parse an AQL query
////////////////////////////////////////////////////////////////////////////////

  internal.AQL_PARSE = AHUACATL_PARSE;
  delete AHUACATL_PARSE;

////////////////////////////////////////////////////////////////////////////////
/// @brief explain an AQL query
////////////////////////////////////////////////////////////////////////////////

  internal.AQL_EXPLAIN = AHUACATL_EXPLAIN;
  delete AHUACATL_EXPLAIN;

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

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

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief resets engine in development mode
////////////////////////////////////////////////////////////////////////////////

  internal.resetEngine = function () {
    internal.flushModuleCache();
    require("org/arangodb/actions").reloadRouting();
  };

////////////////////////////////////////////////////////////////////////////////
/// @brief rebuilds the authentication cache
////////////////////////////////////////////////////////////////////////////////

  internal.reloadAuth = RELOAD_AUTH;
  delete RELOAD_AUTH;

////////////////////////////////////////////////////////////////////////////////
/// @brief defines an action
////////////////////////////////////////////////////////////////////////////////

  if (typeof SYS_DEFINE_ACTION === "undefined") {
    internal.defineAction = function() {
      console.error("SYS_DEFINE_ACTION not available");
    };

    internal.actionLoaded = function() {
    };
  }
  else {
    internal.defineAction = SYS_DEFINE_ACTION;
    delete SYS_DEFINE_ACTION;

    internal.actionLoaded = function() {
      console.debug("actions loaded");
    };
  }

////////////////////////////////////////////////////////////////////////////////
/// @brief initialize foxx applications
////////////////////////////////////////////////////////////////////////////////

  internal.initializeFoxx = function () {
    var fm = require("org/arangodb/foxx/manager");

    try {
      fm.scanAppDirectory();
    }
    catch (err) {
      console.error("cannot initialize Foxx application: %s", String(err));
    }

    var aal = internal.db._collection("_aal");

    if (aal !== null) {
      var systemAppPath = module.systemAppPath();

      var fs = require("fs");
      var apps = fs.list(systemAppPath);

      // make sure the aardvark app is always there
      if (apps.indexOf("aardvark") === -1) {
        apps.push("aardvark");
      }

      apps.forEach(function (appName) {
        // for all unknown system apps: check that the directory actually exists
        if (appName !== "aardvark" &&
            ! fs.isDirectory(fs.join(systemAppPath, appName))) {
          return;
        }

        try {
          var found = aal.firstExample({ type: "mount", mount: "/_admin/" + appName });

          if (found === null) {
            fm.mount(appName, "/_admin/" + appName, {reload: false});
          }
        }
        catch (err) {
          console.error("unable to mount system application '%s': %s", appName, String(err));
        }
      });
    }
  };

////////////////////////////////////////////////////////////////////////////////
/// @brief reloads the AQL user functions
////////////////////////////////////////////////////////////////////////////////

  if (typeof SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION === "undefined") {
    internal.reloadAqlFunctions = function () {
      require("org/arangodb/ahuacatl").reload();
    };
  }
  else {
    internal.reloadAqlFunctions = function () {
      internal.executeGlobalContextFunction("try { require(\"org/arangodb/ahuacatl\").reload(); } catch (err) { }");
      require("org/arangodb/ahuacatl").reload();
    };
  }

////////////////////////////////////////////////////////////////////////////////
/// @brief executes a string in all V8 contexts
////////////////////////////////////////////////////////////////////////////////

  if (typeof SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION === "undefined") {
    internal.executeGlobalContextFunction = function() {
      // nothing to do. we're probably in --console mode
    };
  }
  else {
    internal.executeGlobalContextFunction = SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION;
    delete SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION;
  }

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

}());

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

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
// End:
<commit_msg>mount default apps in /system<commit_after>/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
/*global require, db, ArangoCollection, ArangoDatabase, ArangoCursor, module,
         ShapedJson, RELOAD_AUTH, SYS_DEFINE_ACTION, SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION,
         AHUACATL_RUN, AHUACATL_PARSE, AHUACATL_EXPLAIN */

////////////////////////////////////////////////////////////////////////////////
/// @brief module "internal"
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-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 Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                 Module "internal"
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////

(function () {
  var internal = require("internal");
  var console = require("console");

////////////////////////////////////////////////////////////////////////////////
/// @brief hide global variables
////////////////////////////////////////////////////////////////////////////////

  internal.db = db;
  delete db;

  internal.ArangoCollection = ArangoCollection;
  delete ArangoCollection;

  internal.ArangoDatabase = ArangoDatabase;
  delete ArangoDatabase;

  internal.ArangoCursor = ArangoCursor;
  delete ArangoCursor;

  internal.ShapedJson = ShapedJson;
  delete ShapedJson;

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief execute an AQL query
////////////////////////////////////////////////////////////////////////////////

  internal.AQL_QUERY = AHUACATL_RUN;
  delete AHUACATL_RUN;

////////////////////////////////////////////////////////////////////////////////
/// @brief parse an AQL query
////////////////////////////////////////////////////////////////////////////////

  internal.AQL_PARSE = AHUACATL_PARSE;
  delete AHUACATL_PARSE;

////////////////////////////////////////////////////////////////////////////////
/// @brief explain an AQL query
////////////////////////////////////////////////////////////////////////////////

  internal.AQL_EXPLAIN = AHUACATL_EXPLAIN;
  delete AHUACATL_EXPLAIN;

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

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

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief resets engine in development mode
////////////////////////////////////////////////////////////////////////////////

  internal.resetEngine = function () {
    internal.flushModuleCache();
    require("org/arangodb/actions").reloadRouting();
  };

////////////////////////////////////////////////////////////////////////////////
/// @brief rebuilds the authentication cache
////////////////////////////////////////////////////////////////////////////////

  internal.reloadAuth = RELOAD_AUTH;
  delete RELOAD_AUTH;

////////////////////////////////////////////////////////////////////////////////
/// @brief defines an action
////////////////////////////////////////////////////////////////////////////////

  if (typeof SYS_DEFINE_ACTION === "undefined") {
    internal.defineAction = function() {
      console.error("SYS_DEFINE_ACTION not available");
    };

    internal.actionLoaded = function() {
    };
  }
  else {
    internal.defineAction = SYS_DEFINE_ACTION;
    delete SYS_DEFINE_ACTION;

    internal.actionLoaded = function() {
      console.debug("actions loaded");
    };
  }

////////////////////////////////////////////////////////////////////////////////
/// @brief initialize foxx applications
////////////////////////////////////////////////////////////////////////////////

  internal.initializeFoxx = function () {
    var fm = require("org/arangodb/foxx/manager");

    try {
      fm.scanAppDirectory();
    }
    catch (err) {
      console.error("cannot initialize Foxx application: %s", String(err));
    }

    var aal = internal.db._collection("_aal");

    if (aal !== null) {
      var systemAppPath = module.systemAppPath();

      var fs = require("fs");
      var apps = fs.list(systemAppPath);

      // make sure the aardvark app is always there
      if (apps.indexOf("aardvark") === -1) {
        apps.push("aardvark");
      }

      apps.forEach(function (appName) {
        // for all unknown system apps: check that the directory actually exists
        if (appName !== "aardvark" &&
            ! fs.isDirectory(fs.join(systemAppPath, appName))) {
          return;
        }

        try {
          var mount;
          if (appName === 'aardvark') {
            mount = '/_admin/' + appName;
          }
          else {
            mount = '/system/' + appName;
          }
          var found = aal.firstExample({ type: "mount", mount: mount });

          if (found === null) {
            fm.mount(appName, mount, {reload: false});
          }
        }
        catch (err) {
          console.error("unable to mount system application '%s': %s", appName, String(err));
        }
      });
    }
  };

////////////////////////////////////////////////////////////////////////////////
/// @brief reloads the AQL user functions
////////////////////////////////////////////////////////////////////////////////

  if (typeof SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION === "undefined") {
    internal.reloadAqlFunctions = function () {
      require("org/arangodb/ahuacatl").reload();
    };
  }
  else {
    internal.reloadAqlFunctions = function () {
      internal.executeGlobalContextFunction("try { require(\"org/arangodb/ahuacatl\").reload(); } catch (err) { }");
      require("org/arangodb/ahuacatl").reload();
    };
  }

////////////////////////////////////////////////////////////////////////////////
/// @brief executes a string in all V8 contexts
////////////////////////////////////////////////////////////////////////////////

  if (typeof SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION === "undefined") {
    internal.executeGlobalContextFunction = function() {
      // nothing to do. we're probably in --console mode
    };
  }
  else {
    internal.executeGlobalContextFunction = SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION;
    delete SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION;
  }

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

}());

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

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


<commit_before>class ApplicationConfiguration {
    constructor() {
        //this.configuratiun = require('./config.json');

        const json = this.loadTextFileAjaxSync('/config.json');
        this.configuratiun = JSON.parse(json);

        console.log(this.configuratiun);
    }

    get ApiEndpoint() {
        return this.configuratiun.ApiEndpoint;
    }

    get OldUIAddress() {
        return this.configuratiun.OldUIAddress;
    }

    get LoginPageAddress() {
        return this.configuratiun.LoginPageAddress;
    }

    loadTextFileAjaxSync(filePath)
    {
        const xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET",filePath,false);

        xmlhttp.send();

        if (xmlhttp.status==200 && xmlhttp.readyState == 4 )
        {
            return xmlhttp.responseText;
        }
        else {
            // TODO Throw exception
            return null;
        }
    }
}

export default new ApplicationConfiguration();
<commit_msg>Update configuration loading<commit_after>class ApplicationConfiguration {
    constructor() {
        //this.configuratiun = require('./config.json');

        const json = this.loadTextFileAjaxSync('config.json');
        this.configuratiun = JSON.parse(json);

        console.log(this.configuratiun);
    }

    get ApiEndpoint() {
        return this.configuratiun.ApiEndpoint;
    }

    get OldUIAddress() {
        return this.configuratiun.OldUIAddress;
    }

    get LoginPageAddress() {
        return this.configuratiun.LoginPageAddress;
    }

    loadTextFileAjaxSync(filePath)
    {
        const xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET",filePath,false);

        xmlhttp.send();

        if (xmlhttp.status==200 && xmlhttp.readyState == 4 )
        {
            return xmlhttp.responseText;
        }
        else {
            // TODO Throw exception
            return null;
        }
    }
}

export default new ApplicationConfiguration();
<|endoftext|>


<commit_before>'use strict'

/* @flow */

import FS from 'fs'
import Path from 'path'
import promisify from 'sb-promisify'

export const readFile = promisify(FS.readFile)
export const writeFile = promisify(FS.writeFile)
export async function readJSON(filePath: string, encoding: string = 'utf8'): Promise {
  const contents = await readFile(filePath)
  return JSON.parse(contents.toString(encoding))
}
export async function writeJSON(filePath: string, contents: Object): Promise {
  await writeFile(filePath, JSON.stringify(contents))
}
export function exists(filePath: string): Promise<boolean> {
  return new Promise(function(resolve) {
    FS.access(filePath, FS.R_OK, function(error) {
      resolve(error === null)
    })
  })
}
<commit_msg>:new: Add unlink helper<commit_after>'use strict'

/* @flow */

import FS from 'fs'
import Path from 'path'
import promisify from 'sb-promisify'

export const unlink = promisify(FS.unlink)
export const readFile = promisify(FS.readFile)
export const writeFile = promisify(FS.writeFile)
export async function readJSON(filePath: string, encoding: string = 'utf8'): Promise {
  const contents = await readFile(filePath)
  return JSON.parse(contents.toString(encoding))
}
export async function writeJSON(filePath: string, contents: Object): Promise {
  await writeFile(filePath, JSON.stringify(contents))
}
export function exists(filePath: string): Promise<boolean> {
  return new Promise(function(resolve) {
    FS.access(filePath, FS.R_OK, function(error) {
      resolve(error === null)
    })
  })
}
<|endoftext|>