<commit_before>var NumberController = function() {

	this.type = "number";

    Controller.apply(this, arguments);

    var _this = this;

    // If we simply click and release a number field, we want to highlight it.
    // This variable keeps track of whether or not we've dragged
    var draggedNumberField = false;

    var clickedNumberField = false;

    var y = py = 0;

    var min = arguments[3];
    var max = arguments[4];
    var step = arguments[5];

    if (!step) {
    	if (min != undefined && max != undefined) {
    		step = (max-min)*0.01;
    	} else {
    		step = 1;
    	}
    }

    var numberField = document.createElement('input');
    numberField.setAttribute('id', this.propertyName);
    numberField.setAttribute('type', 'text');
    numberField.setAttribute('value', this.getValue());

    if (step) numberField.setAttribute('step', step);

    this.domElement.appendChild(numberField);

    var slider;

    if (min != undefined && max != undefined) {
    	slider = new Slider(this, min, max, step, this.getValue());
    	this.domElement.appendChild(slider.domElement);
    }

    numberField.addEventListener('blur', function(e) {
        var val = parseFloat(this.value);
        if (!isNaN(val)) {
	        _this.updateDisplay();
        } else {
        	this.value = _this.getValue();
        }
    }, false);

    numberField.addEventListener('mousewheel', function(e) {
    	e.preventDefault();
    	_this.setValue(_this.getValue() + Math.abs(e.wheelDeltaY)/e.wheelDeltaY*step);
    	return false;
    }, false);

    numberField.addEventListener('mousedown', function(e) {
        py = y = e.pageY;
		clickedNumberField = true;
        document.addEventListener('mousemove', dragNumberField, false);
    }, false);

	// Handle up arrow and down arrow
	numberField.addEventListener('keyup', function(e) {
		switch(e.keyCode) {
			case 38: 	// up
				var newVal = _this.getValue() + step;
				_this.setValue(newVal);
				break;
			case 40: 	// down
				var newVal = _this.getValue() - step;
				_this.setValue(newVal);
				break;
		}
	}, false);

    document.addEventListener('mouseup', function(e) {
        document.removeEventListener('mousemove', dragNumberField, false);
        GUI.makeSelectable(_this.parent.domElement);
        GUI.makeSelectable(numberField);
        if (clickedNumberField && !draggedNumberField) {
	        numberField.focus();
	        numberField.select();
        }
        draggedNumberField = false;
        clickedNumberField = false;
    }, false);

    var dragNumberField = function(e) {
    	draggedNumberField = true;
		e.preventDefault();

		// We don't want to be highlighting this field as we scroll.
		// Or any other fields in this gui for that matter ...
		// TODO: Make makeUselectable go through each element and child element.

		GUI.makeUnselectable(_this.parent.domElement);
		GUI.makeUnselectable(numberField);

		py = y;
		y = e.pageY;
		var dy = py - y;
		var newVal = _this.getValue() + dy*step;
		_this.setValue(newVal);
		return false;
    }

    this.setValue = function(val) {

		val = parseFloat(val);

    	if (min != undefined && val <= min) {
    		val = min;
    	} else if (max != undefined && val >= max) {
    		val = max;
    	}

    	return Controller.prototype.setValue.call(this, val);

    }

    this.updateDisplay = function() {
        numberField.value = GUI.roundToDecimal(_this.getValue(), 4);
        if (slider) slider.value = _this.getValue();
	}
};

NumberController.prototype = new Controller();
NumberController.prototype.constructor = NumberController;
<commit_msg>changed keyEvent from keyup to keydown<commit_after>var NumberController = function() {

	this.type = "number";

    Controller.apply(this, arguments);

    var _this = this;

    // If we simply click and release a number field, we want to highlight it.
    // This variable keeps track of whether or not we've dragged
    var draggedNumberField = false;

    var clickedNumberField = false;

    var y = py = 0;

    var min = arguments[3];
    var max = arguments[4];
    var step = arguments[5];

    if (!step) {
    	if (min != undefined && max != undefined) {
    		step = (max-min)*0.01;
    	} else {
    		step = 1;
    	}
    }

    var numberField = document.createElement('input');
    numberField.setAttribute('id', this.propertyName);
    numberField.setAttribute('type', 'text');
    numberField.setAttribute('value', this.getValue());

    if (step) numberField.setAttribute('step', step);

    this.domElement.appendChild(numberField);

    var slider;

    if (min != undefined && max != undefined) {
    	slider = new Slider(this, min, max, step, this.getValue());
    	this.domElement.appendChild(slider.domElement);
    }

    numberField.addEventListener('blur', function(e) {
        var val = parseFloat(this.value);
        if (!isNaN(val)) {
	        _this.updateDisplay();
        } else {
        	this.value = _this.getValue();
        }
    }, false);

    numberField.addEventListener('mousewheel', function(e) {
    	e.preventDefault();
    	_this.setValue(_this.getValue() + Math.abs(e.wheelDeltaY)/e.wheelDeltaY*step);
    	return false;
    }, false);

    numberField.addEventListener('mousedown', function(e) {
        py = y = e.pageY;
		clickedNumberField = true;
        document.addEventListener('mousemove', dragNumberField, false);
    }, false);

	// Handle up arrow and down arrow
	numberField.addEventListener('keydown', function(e) {
		switch(e.keyCode) {
			case 38: 	// up
				var newVal = _this.getValue() + step;
				_this.setValue(newVal);
				break;
			case 40: 	// down
				var newVal = _this.getValue() - step;
				_this.setValue(newVal);
				break;
		}
	}, false);

    document.addEventListener('mouseup', function(e) {
        document.removeEventListener('mousemove', dragNumberField, false);
        GUI.makeSelectable(_this.parent.domElement);
        GUI.makeSelectable(numberField);
        if (clickedNumberField && !draggedNumberField) {
	        numberField.focus();
	        numberField.select();
        }
        draggedNumberField = false;
        clickedNumberField = false;
    }, false);

    var dragNumberField = function(e) {
    	draggedNumberField = true;
		e.preventDefault();

		// We don't want to be highlighting this field as we scroll.
		// Or any other fields in this gui for that matter ...
		// TODO: Make makeUselectable go through each element and child element.

		GUI.makeUnselectable(_this.parent.domElement);
		GUI.makeUnselectable(numberField);

		py = y;
		y = e.pageY;
		var dy = py - y;
		var newVal = _this.getValue() + dy*step;
		_this.setValue(newVal);
		return false;
    }

    this.setValue = function(val) {

		val = parseFloat(val);

    	if (min != undefined && val <= min) {
    		val = min;
    	} else if (max != undefined && val >= max) {
    		val = max;
    	}

    	return Controller.prototype.setValue.call(this, val);

    }

    this.updateDisplay = function() {
        numberField.value = GUI.roundToDecimal(_this.getValue(), 4);
        if (slider) slider.value = _this.getValue();
	}
};

NumberController.prototype = new Controller();
NumberController.prototype.constructor = NumberController;
<|endoftext|>


<commit_before>// Builds the site using Metalsmith as the top-level build runner.

const Metalsmith = require('metalsmith');
const archive = require('metalsmith-archive');
const assets = require('metalsmith-assets');
const blc = require('metalsmith-broken-link-checker');
const collections = require('metalsmith-collections');
const commandLineArgs = require('command-line-args');
const dateInFilename = require('metalsmith-date-in-filename');
const define = require('metalsmith-define');
const filenames = require('metalsmith-filenames');
const inPlace = require('metalsmith-in-place');
const layouts = require('metalsmith-layouts');
const liquid = require('tinyliquid');
const markdown = require('metalsmith-markdownit');
const moment = require('moment');
const navigation = require('metalsmith-navigation');
const permalinks = require('metalsmith-permalinks');
const redirect = require('metalsmith-redirect');
const sitemap = require('metalsmith-sitemap');
const watch = require('metalsmith-watch');
const webpack = require('metalsmith-webpack');
const webpackConfigGenerator = require('../config/webpack.config');
const webpackDevServer = require('metalsmith-webpack-dev-server');
const semver = require('semver');

const fs = require('fs');
const path = require('path');

const sourceDir = '../content/pages';
const minimumNpmVersion = '3.8.9';
const minimumNodeVersion = '4.4.7';
// Make sure git pre-commit hooks are installed
['pre-commit'].forEach(hook => {
  const src = `../hooks/${hook}`;
  const dest = `../.git/hooks/${hook}`;
  if (fs.existsSync(src)) {
    if (!fs.existsSync(dest)) {
      // Install hooks
      fs.linkSync(src, dest);
    }
  }
});

if (semver.compare(process.env.npm_package_engines_npm, minimumNpmVersion) === -1) {
  process.stdout.write(
    `NPM version (mininum): ${minimumNpmVersion}\n`);
  process.stdout.write(`NPM version (installed): ${process.env.npm_package_engines_npm}\n`);
  process.exit();
}

if (semver.compare(process.version, minimumNodeVersion) === -1) {
  process.stdout.write(`Node.js version (mininum): v${minimumNodeVersion}\n`);
  process.stdout.write(`Node.js version (installed): ${process.version}\n`);
  process.exit();
}

const smith = Metalsmith(__dirname); // eslint-disable-line new-cap

const optionDefinitions = [
  { name: 'buildtype', type: String, defaultValue: 'development' },
  { name: 'no-sanity-check-node-env', type: Boolean, defaultValue: false },
  { name: 'port', type: Number, defaultValue: 3001 },
  { name: 'watch', type: Boolean, defaultValue: false },
  { name: 'entry', type: String, defaultValue: null },
  { name: 'host', type: String, defaultValue: 'localhost' },

  // Catch-all for bad arguments.
  { name: 'unexpected', type: String, multile: true, defaultOption: true },
];
const options = commandLineArgs(optionDefinitions);

const env = require('get-env')();

if (options.unexpected && options.unexpected.length !== 0) {
  throw new Error(`Unexpected arguments: '${options.unexpected}'`);
}

if (options.buildtype === undefined) {
  options.buildtype = 'development';
}

switch (options.buildtype) {
  case 'development':
    // No extra checks needed in dev.
    break;

  case 'staging':
    break;

  case 'production':
    if (options['no-sanity-check-node-env'] === false) {
      if (env !== 'prod') {
        throw new Error(`buildtype ${options.buildtype} expects NODE_ENV to be production, not '${process.env.NODE_ENV}'`);
      }
    }
    break;

  default:
    throw new Error(`Unknown buildtype: '${options.buildtype}'`);
}

const webpackConfig = webpackConfigGenerator(options);

// Custom liquid filter(s)
liquid.filters.humanizeDate = (dt) => moment(dt).format('MMMM D, YYYY');

// Set up Metalsmith. BE CAREFUL if you change the order of the plugins. Read the comments and
// add comments about any implicit dependencies you are introducing!!!
//
smith.source(sourceDir);
smith.destination(`../build/${options.buildtype}`);

// TODO(awong): Verify that memorial-benefits should still be in the source tree.
//    https://github.com/department-of-veterans-affairs/vets-website/issues/2721

// To use:
// const ignore = require('metalsmith-ignore');
// const ignoreList = [];
// if (options.buildtype === 'production') {
//   ignoreList.push('disability-benefits/track-claims/*');
// }
// smith.use(ignore(ignoreList));

const ignore = require('metalsmith-ignore');
const ignoreList = [];
if (options.buildtype === 'production') {
  ignoreList.push('healthcare/blue-button/*');
}
smith.use(ignore(ignoreList));

// This adds the filename into the "entry" that is passed to other plugins. Without this errors
// during templating end up not showing which file they came from. Load it very early in in the
// plugin chain.
smith.use(filenames());

smith.use(define({
  // Does anything even look at `site`?
  site: require('../config/site'),
  buildtype: options.buildtype
}));

smith.use(collections());
smith.use(dateInFilename(true));
smith.use(archive());  // TODO(awong): Can this be removed?

if (options.watch) {
  // TODO(awong): Enable live reload of metalsmith pages per instructions at
  //   https://www.npmjs.com/package/metalsmith-watch
  smith.use(
    watch({
      paths: {
        '../content/**/*': '**/*.{md,html}',
      },
      livereload: true,
    })
  );

  // If in watch mode, assume hot reloading for JS and use webpack devserver.
  const devServerConfig = {
    contentBase: `build/${options.buildtype}`,
    historyApiFallback: {
      rewrites: [
        { from: '^/track-claims(.*)', to: '/track-claims/' },
        { from: '^/disability-benefits/track-claims(.*)', to: '/disability-benefits/track-claims/' },
        { from: '^/education/apply-for-education-benefits/application(.*)', to: '/education/apply-for-education-benefits/application/' },
        { from: '^/facilities(.*)', to: '/facilities/' },
        { from: '^/healthcare/apply/application(.*)', to: '/healthcare/apply/application/' },
        { from: '^/healthcare/blue-button(.*)', to: '/healthcare/blue-button/' },
        { from: '^/healthcare/messaging(.*)', to: '/healthcare/messaging/' },
        { from: '^/healthcare/prescriptions(.*)', to: '/healthcare/prescriptions/' },
        { from: '^/(.*)', to(context) { return context.parsedUrl.pathname; } }
      ],
    },
    hot: true,
    port: options.port,
    publicPath: '/generated/',
    host: options.host,
    stats: {
      colors: true,
      assets: false,
      version: false,
      hash: false,
      timings: true,
      chunks: false,
      chunkModules: false,
      children: false
    }
  };

  // Route all API requests through webpack's node-http-proxy
  // Useful for local development.
  try {
    // Check to see if we have a proxy config file
    const api = require('../config/config.proxy.js').api;
    devServerConfig.proxy = {
      '/api/v0/*': {
        target: `https://${api.host}/`,
        auth: api.auth,
        secure: true,
        changeOrigin: true,
        pathRewrite: { '^/api': '' },
        rewrite: function rewrite(req) {
          /* eslint-disable no-param-reassign */
          req.headers.host = api.host;
          /* eslint-enable no-param-reassign */
          return;
        }
      }
    };
    // eslint-disable-next-line no-console
    console.log('API proxy enabled');
  } catch (e) {
    // No proxy config file found.
  }

  smith.use(webpackDevServer(webpackConfig, devServerConfig));
} else {
  // Broken link checking does not work well with watch. It continually shows broken links
  // for permalink processed files. Only run outside of watch mode.

  smith.use(webpack(webpackConfig));
}

smith.use(assets({ source: '../assets', destination: './' }));

const destination = path.resolve(__dirname, `../build/${options.buildtype}`);

// Webpack paths are absolute, convert to relative
smith.use((files, metalsmith, done) => {
  Object.keys(files).forEach((file) => {
    if (file.indexOf(destination) === 0) {
      /* eslint-disable no-param-reassign */
      files[file.substr(destination.length + 1)] = files[file];
      delete files[file];
      /* esling-enable no-param-reassign */
    }
  });

  done();
});

// smith.use(cspHash({ pattern: ['js/*.js', 'generated/*.css', 'generated/*.js'] }))

// Liquid substitution must occur before markdown is run otherwise markdown will escape the
// bits of liquid commands (eg., quotes) and break things.
//
// Unfortunately this must come before permalinks and navgation because of limitation in both
// modules regarding what files they understand. The consequence here is that liquid templates
// *within* a single file do NOT have access to the final path that they will be rendered under
// or any other metadata added by the permalinks() and navigation() filters.
//
// Thus far this has not been a problem because the only references to such paths are in the
// includes which are handled by the layout module. The layout module, luckily, can be run
// near the end of the filter chain and therefore has access to all the metadata.
//
// If this becomes a barrier in the future, permalinks should be patched to understand
// translating .md files which would allow inPlace() and markdown() to be moved under the
// permalinks() and navigation() filters making the variable stores uniform between inPlace()
// and layout().
smith.use(inPlace({ engine: 'liquid', pattern: '*.{md,html}' }));
smith.use(markdown({
  typographer: true,
  html: true
}));

// Responsible for create permalink structure. Most commonly used change foo.md to foo/index.html.
//
// This must come before navigation module, otherwise breadcrunmbs will see the wrong URLs.
//
// It also must come AFTER the markdown() module because it only recognizes .html files. See
// comment above the inPlace() module for explanation of effects on the metadata().
smith.use(permalinks({
  relative: false,
  linksets: [{
    match: { collection: 'posts' },
    pattern: ':date/:slug'
  }]
}));

smith.use(navigation({
  navConfigs: {
    sortByNameFirst: true,
    breadcrumbProperty: 'breadcrumb_path',
    pathProperty: 'nav_path',
    includeDirs: true
  }, navSettings: {} }));

// Note that there is no default layout specified.
// All pages must explicitly declare a layout or else it will be rendered as raw html.
smith.use(layouts({
  engine: 'liquid',
  directory: '../content/layouts/',
  // Only apply layouts to markdown and html files.
  pattern: '**/*.{md,html}'
}));

// TODO(awong): This URL needs to change based on target environment.
smith.use(sitemap({
  hostname: 'http://www.vets.gov',
  omitIndex: true
}));
// TODO(awong): Does anything even use the results of this plugin?

if (!options.watch) {
  smith.use(blc({
    allowRedirects: true,  // Don't require trailing slash for index.html links.
    warn: false,           // Throw an Error when encountering the first broken link not just a warning.
    allowRegex: new RegExp(
        ['/employment/commitments',
          '/employment/employers',
          '/employment/job-seekers/create-resume',
          '/employment/job-seekers/search-jobs',
          '/employment/job-seekers/skills-translator',
          '/gi-bill-comparison-tool/',
          '/education/apply-for-education-benefits/application',
          '/healthcare/apply/application'].join('|'))
  }));
}

if (options.buildtype !== 'development') {
  //
  // In non-development modes, we add hashes to the names of asset files in order to support
  // cache busting. That is done via WebPack, but WebPack doesn't know anything about our HTML
  // files, so we have to replace the references to those files in HTML and CSS files after the
  // rest of the build has completed. This is done by reading in a manifest file created by
  // WebPack that maps the original file names to their hashed versions. Metalsmith actions
  // are passed a list of files that are included in the build. Those files are not yet written
  // to disk, but the contents are held in memory.
  //
  smith.use((files, metalsmith, done) => {
    // Read in the data from the manifest file.
    const manifestKey = Object.keys(files).find((filename) => {
      return filename.match(/file-manifest.json$/) !== null;
    });
    const originalManifest = JSON.parse(files[manifestKey].contents.toString());

    // The manifest contains the original filenames without the addition of .entry
    // on the JS files. This finds all of those and modifies them to add .entry.
    const manifest = {};
    Object.keys(originalManifest).forEach((originalManifestKey) => {
      const matchData = originalManifestKey.match(/(.*)\.js$/);
      if (matchData !== null && matchData[1] !== 'vendor') {
        const newKey = `${matchData[1]}.entry.js`;
        manifest[newKey] = originalManifest[originalManifestKey];
      } else {
        manifest[originalManifestKey] = originalManifest[originalManifestKey];
      }
    });

    // For each file in the build, if it is a HTML or CSS file, loop over all
    // the keys in the manifest object and do a search and replace for the
    // key with the value.
    Object.keys(files).forEach((filename) => {
      if (filename.match(/\.(html|css)$/) !== null) {
        Object.keys(manifest).forEach((originalAssetFilename) => {
          const newAssetFilename = manifest[originalAssetFilename];
          const file = files[filename];
          const contents = file.contents.toString();
          const regex = new RegExp(originalAssetFilename, 'g');
          file.contents = new Buffer(contents.replace(regex, newAssetFilename));
        });
      }
    });
    done();
  });

  smith.use((files, metalsmith, done) => {
    // Read in the data from the manifest file.
    const chunkManifestKey = Object.keys(files).find((filename) => {
      return filename.match(/chunk-manifest.json$/) !== null;
    });
    const chunkManifest = files[chunkManifestKey].contents.toString();

    Object.keys(files).forEach((filename) => {
      if (filename.match(/\.html$/) !== null) {
        const file = files[filename];
        const contents = file.contents.toString();
        const regex = new RegExp("'CHUNK_MANIFEST_PLACEHOLDER'", 'g');
        file.contents = new Buffer(contents.replace(regex, chunkManifest));
      }
    });
    done();
  });
}

smith.use(redirect({
  '/2015/11/11/why-we-are-designing-in-beta.html': '/2015/11/11/why-we-are-designing-in-beta/'
}));

/* eslint-disable no-console */
smith.build((err) => {
  if (err) throw err;
  if (options.watch) {
    console.log('Metalsmith build finished!  Starting webpack-dev-server...');
  } else {
    console.log('Build finished!');
  }
});
<commit_msg>Exit with failure if node version incompatible<commit_after>// Builds the site using Metalsmith as the top-level build runner.

const Metalsmith = require('metalsmith');
const archive = require('metalsmith-archive');
const assets = require('metalsmith-assets');
const blc = require('metalsmith-broken-link-checker');
const collections = require('metalsmith-collections');
const commandLineArgs = require('command-line-args');
const dateInFilename = require('metalsmith-date-in-filename');
const define = require('metalsmith-define');
const filenames = require('metalsmith-filenames');
const inPlace = require('metalsmith-in-place');
const layouts = require('metalsmith-layouts');
const liquid = require('tinyliquid');
const markdown = require('metalsmith-markdownit');
const moment = require('moment');
const navigation = require('metalsmith-navigation');
const permalinks = require('metalsmith-permalinks');
const redirect = require('metalsmith-redirect');
const sitemap = require('metalsmith-sitemap');
const watch = require('metalsmith-watch');
const webpack = require('metalsmith-webpack');
const webpackConfigGenerator = require('../config/webpack.config');
const webpackDevServer = require('metalsmith-webpack-dev-server');
const semver = require('semver');

const fs = require('fs');
const path = require('path');

const sourceDir = '../content/pages';
const minimumNpmVersion = '3.8.9';
const minimumNodeVersion = '4.4.7';
// Make sure git pre-commit hooks are installed
['pre-commit'].forEach(hook => {
  const src = `../hooks/${hook}`;
  const dest = `../.git/hooks/${hook}`;
  if (fs.existsSync(src)) {
    if (!fs.existsSync(dest)) {
      // Install hooks
      fs.linkSync(src, dest);
    }
  }
});

if (semver.compare(process.env.npm_package_engines_npm, minimumNpmVersion) === -1) {
  process.stdout.write(
    `NPM version (mininum): ${minimumNpmVersion}\n`);
  process.stdout.write(`NPM version (installed): ${process.env.npm_package_engines_npm}\n`);
  process.exit(1);
}

if (semver.compare(process.version, minimumNodeVersion) === -1) {
  process.stdout.write(`Node.js version (mininum): v${minimumNodeVersion}\n`);
  process.stdout.write(`Node.js version (installed): ${process.version}\n`);
  process.exit();
}

const smith = Metalsmith(__dirname); // eslint-disable-line new-cap

const optionDefinitions = [
  { name: 'buildtype', type: String, defaultValue: 'development' },
  { name: 'no-sanity-check-node-env', type: Boolean, defaultValue: false },
  { name: 'port', type: Number, defaultValue: 3001 },
  { name: 'watch', type: Boolean, defaultValue: false },
  { name: 'entry', type: String, defaultValue: null },
  { name: 'host', type: String, defaultValue: 'localhost' },

  // Catch-all for bad arguments.
  { name: 'unexpected', type: String, multile: true, defaultOption: true },
];
const options = commandLineArgs(optionDefinitions);

const env = require('get-env')();

if (options.unexpected && options.unexpected.length !== 0) {
  throw new Error(`Unexpected arguments: '${options.unexpected}'`);
}

if (options.buildtype === undefined) {
  options.buildtype = 'development';
}

switch (options.buildtype) {
  case 'development':
    // No extra checks needed in dev.
    break;

  case 'staging':
    break;

  case 'production':
    if (options['no-sanity-check-node-env'] === false) {
      if (env !== 'prod') {
        throw new Error(`buildtype ${options.buildtype} expects NODE_ENV to be production, not '${process.env.NODE_ENV}'`);
      }
    }
    break;

  default:
    throw new Error(`Unknown buildtype: '${options.buildtype}'`);
}

const webpackConfig = webpackConfigGenerator(options);

// Custom liquid filter(s)
liquid.filters.humanizeDate = (dt) => moment(dt).format('MMMM D, YYYY');

// Set up Metalsmith. BE CAREFUL if you change the order of the plugins. Read the comments and
// add comments about any implicit dependencies you are introducing!!!
//
smith.source(sourceDir);
smith.destination(`../build/${options.buildtype}`);

// TODO(awong): Verify that memorial-benefits should still be in the source tree.
//    https://github.com/department-of-veterans-affairs/vets-website/issues/2721

// To use:
// const ignore = require('metalsmith-ignore');
// const ignoreList = [];
// if (options.buildtype === 'production') {
//   ignoreList.push('disability-benefits/track-claims/*');
// }
// smith.use(ignore(ignoreList));

const ignore = require('metalsmith-ignore');
const ignoreList = [];
if (options.buildtype === 'production') {
  ignoreList.push('healthcare/blue-button/*');
}
smith.use(ignore(ignoreList));

// This adds the filename into the "entry" that is passed to other plugins. Without this errors
// during templating end up not showing which file they came from. Load it very early in in the
// plugin chain.
smith.use(filenames());

smith.use(define({
  // Does anything even look at `site`?
  site: require('../config/site'),
  buildtype: options.buildtype
}));

smith.use(collections());
smith.use(dateInFilename(true));
smith.use(archive());  // TODO(awong): Can this be removed?

if (options.watch) {
  // TODO(awong): Enable live reload of metalsmith pages per instructions at
  //   https://www.npmjs.com/package/metalsmith-watch
  smith.use(
    watch({
      paths: {
        '../content/**/*': '**/*.{md,html}',
      },
      livereload: true,
    })
  );

  // If in watch mode, assume hot reloading for JS and use webpack devserver.
  const devServerConfig = {
    contentBase: `build/${options.buildtype}`,
    historyApiFallback: {
      rewrites: [
        { from: '^/track-claims(.*)', to: '/track-claims/' },
        { from: '^/disability-benefits/track-claims(.*)', to: '/disability-benefits/track-claims/' },
        { from: '^/education/apply-for-education-benefits/application(.*)', to: '/education/apply-for-education-benefits/application/' },
        { from: '^/facilities(.*)', to: '/facilities/' },
        { from: '^/healthcare/apply/application(.*)', to: '/healthcare/apply/application/' },
        { from: '^/healthcare/blue-button(.*)', to: '/healthcare/blue-button/' },
        { from: '^/healthcare/messaging(.*)', to: '/healthcare/messaging/' },
        { from: '^/healthcare/prescriptions(.*)', to: '/healthcare/prescriptions/' },
        { from: '^/(.*)', to(context) { return context.parsedUrl.pathname; } }
      ],
    },
    hot: true,
    port: options.port,
    publicPath: '/generated/',
    host: options.host,
    stats: {
      colors: true,
      assets: false,
      version: false,
      hash: false,
      timings: true,
      chunks: false,
      chunkModules: false,
      children: false
    }
  };

  // Route all API requests through webpack's node-http-proxy
  // Useful for local development.
  try {
    // Check to see if we have a proxy config file
    const api = require('../config/config.proxy.js').api;
    devServerConfig.proxy = {
      '/api/v0/*': {
        target: `https://${api.host}/`,
        auth: api.auth,
        secure: true,
        changeOrigin: true,
        pathRewrite: { '^/api': '' },
        rewrite: function rewrite(req) {
          /* eslint-disable no-param-reassign */
          req.headers.host = api.host;
          /* eslint-enable no-param-reassign */
          return;
        }
      }
    };
    // eslint-disable-next-line no-console
    console.log('API proxy enabled');
  } catch (e) {
    // No proxy config file found.
  }

  smith.use(webpackDevServer(webpackConfig, devServerConfig));
} else {
  // Broken link checking does not work well with watch. It continually shows broken links
  // for permalink processed files. Only run outside of watch mode.

  smith.use(webpack(webpackConfig));
}

smith.use(assets({ source: '../assets', destination: './' }));

const destination = path.resolve(__dirname, `../build/${options.buildtype}`);

// Webpack paths are absolute, convert to relative
smith.use((files, metalsmith, done) => {
  Object.keys(files).forEach((file) => {
    if (file.indexOf(destination) === 0) {
      /* eslint-disable no-param-reassign */
      files[file.substr(destination.length + 1)] = files[file];
      delete files[file];
      /* esling-enable no-param-reassign */
    }
  });

  done();
});

// smith.use(cspHash({ pattern: ['js/*.js', 'generated/*.css', 'generated/*.js'] }))

// Liquid substitution must occur before markdown is run otherwise markdown will escape the
// bits of liquid commands (eg., quotes) and break things.
//
// Unfortunately this must come before permalinks and navgation because of limitation in both
// modules regarding what files they understand. The consequence here is that liquid templates
// *within* a single file do NOT have access to the final path that they will be rendered under
// or any other metadata added by the permalinks() and navigation() filters.
//
// Thus far this has not been a problem because the only references to such paths are in the
// includes which are handled by the layout module. The layout module, luckily, can be run
// near the end of the filter chain and therefore has access to all the metadata.
//
// If this becomes a barrier in the future, permalinks should be patched to understand
// translating .md files which would allow inPlace() and markdown() to be moved under the
// permalinks() and navigation() filters making the variable stores uniform between inPlace()
// and layout().
smith.use(inPlace({ engine: 'liquid', pattern: '*.{md,html}' }));
smith.use(markdown({
  typographer: true,
  html: true
}));

// Responsible for create permalink structure. Most commonly used change foo.md to foo/index.html.
//
// This must come before navigation module, otherwise breadcrunmbs will see the wrong URLs.
//
// It also must come AFTER the markdown() module because it only recognizes .html files. See
// comment above the inPlace() module for explanation of effects on the metadata().
smith.use(permalinks({
  relative: false,
  linksets: [{
    match: { collection: 'posts' },
    pattern: ':date/:slug'
  }]
}));

smith.use(navigation({
  navConfigs: {
    sortByNameFirst: true,
    breadcrumbProperty: 'breadcrumb_path',
    pathProperty: 'nav_path',
    includeDirs: true
  }, navSettings: {} }));

// Note that there is no default layout specified.
// All pages must explicitly declare a layout or else it will be rendered as raw html.
smith.use(layouts({
  engine: 'liquid',
  directory: '../content/layouts/',
  // Only apply layouts to markdown and html files.
  pattern: '**/*.{md,html}'
}));

// TODO(awong): This URL needs to change based on target environment.
smith.use(sitemap({
  hostname: 'http://www.vets.gov',
  omitIndex: true
}));
// TODO(awong): Does anything even use the results of this plugin?

if (!options.watch) {
  smith.use(blc({
    allowRedirects: true,  // Don't require trailing slash for index.html links.
    warn: false,           // Throw an Error when encountering the first broken link not just a warning.
    allowRegex: new RegExp(
        ['/employment/commitments',
          '/employment/employers',
          '/employment/job-seekers/create-resume',
          '/employment/job-seekers/search-jobs',
          '/employment/job-seekers/skills-translator',
          '/gi-bill-comparison-tool/',
          '/education/apply-for-education-benefits/application',
          '/healthcare/apply/application'].join('|'))
  }));
}

if (options.buildtype !== 'development') {
  //
  // In non-development modes, we add hashes to the names of asset files in order to support
  // cache busting. That is done via WebPack, but WebPack doesn't know anything about our HTML
  // files, so we have to replace the references to those files in HTML and CSS files after the
  // rest of the build has completed. This is done by reading in a manifest file created by
  // WebPack that maps the original file names to their hashed versions. Metalsmith actions
  // are passed a list of files that are included in the build. Those files are not yet written
  // to disk, but the contents are held in memory.
  //
  smith.use((files, metalsmith, done) => {
    // Read in the data from the manifest file.
    const manifestKey = Object.keys(files).find((filename) => {
      return filename.match(/file-manifest.json$/) !== null;
    });
    const originalManifest = JSON.parse(files[manifestKey].contents.toString());

    // The manifest contains the original filenames without the addition of .entry
    // on the JS files. This finds all of those and modifies them to add .entry.
    const manifest = {};
    Object.keys(originalManifest).forEach((originalManifestKey) => {
      const matchData = originalManifestKey.match(/(.*)\.js$/);
      if (matchData !== null && matchData[1] !== 'vendor') {
        const newKey = `${matchData[1]}.entry.js`;
        manifest[newKey] = originalManifest[originalManifestKey];
      } else {
        manifest[originalManifestKey] = originalManifest[originalManifestKey];
      }
    });

    // For each file in the build, if it is a HTML or CSS file, loop over all
    // the keys in the manifest object and do a search and replace for the
    // key with the value.
    Object.keys(files).forEach((filename) => {
      if (filename.match(/\.(html|css)$/) !== null) {
        Object.keys(manifest).forEach((originalAssetFilename) => {
          const newAssetFilename = manifest[originalAssetFilename];
          const file = files[filename];
          const contents = file.contents.toString();
          const regex = new RegExp(originalAssetFilename, 'g');
          file.contents = new Buffer(contents.replace(regex, newAssetFilename));
        });
      }
    });
    done();
  });

  smith.use((files, metalsmith, done) => {
    // Read in the data from the manifest file.
    const chunkManifestKey = Object.keys(files).find((filename) => {
      return filename.match(/chunk-manifest.json$/) !== null;
    });
    const chunkManifest = files[chunkManifestKey].contents.toString();

    Object.keys(files).forEach((filename) => {
      if (filename.match(/\.html$/) !== null) {
        const file = files[filename];
        const contents = file.contents.toString();
        const regex = new RegExp("'CHUNK_MANIFEST_PLACEHOLDER'", 'g');
        file.contents = new Buffer(contents.replace(regex, chunkManifest));
      }
    });
    done();
  });
}

smith.use(redirect({
  '/2015/11/11/why-we-are-designing-in-beta.html': '/2015/11/11/why-we-are-designing-in-beta/'
}));

/* eslint-disable no-console */
smith.build((err) => {
  if (err) throw err;
  if (options.watch) {
    console.log('Metalsmith build finished!  Starting webpack-dev-server...');
  } else {
    console.log('Build finished!');
  }
});
<|endoftext|>


<commit_before>import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import WsClient from '../../WsClient';
import { addValidatedPlatba, saveUcast } from './PrihlaskyActions';

const successfulResponseSaveUdaje = {
  code: 'ok',
  response: {
    id: '===id==='
  },
  requestId: '0.9310306652587377'
};

const successfulResponseSavePrihlaska = {
  code: 'ok',
  requestId: '0.9310306652587377'
};

const successfulResponseSavePlatby = {
  code: 'ok',
  requestId: '0.9310306652587377'
};

const unsuccessfulResponse = {
  code: 'unfulfilled request',
  status: 'A strange error occurred.'
};

const authTokenInvalidResponse = {
  code: 'authentication token invalid',
  status: 'Neplatný ověřovací token.'
};

let responseNumber;
beforeEach(() => {
  responseNumber = 0;
});

const mockWsClient = new WsClient();
let responses = [];
// eslint-disable-next-line no-plusplus
mockWsClient.sendRequest = async () => responses[responseNumber++];

const middlewares = [thunk.withExtraArgument(mockWsClient)];
const mockStore = configureStore(middlewares);

it('saveUcast() should dispatch four successful actions', async () => {
 responses = [
    successfulResponseSaveUdaje,
    successfulResponseSavePrihlaska,
    successfulResponseSavePlatby
  ];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { validateForm: false, udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      id: '===id===',
      type: 'PRIHLASKY_SAVE_SUCCESS'
    })
  );
  expect(actions[3]).toEqual({ type: 'PRIHLASKY_SAVE_SHOW_MODAL' });
});

it('saveUcast() should dispatch two unsuccessful actions 1/2', async () => {
  responses = [unsuccessfulResponse, unsuccessfulResponse];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'PRIHLASKY_SAVE_ERROR',
      code: 'unfulfilled request',
      status: 'A strange error occurred.'
    })
  );
});

it('saveUcast() should dispatch two unsuccessful actions 2/2', async () => {
  responses = [successfulResponseSaveUdaje, unsuccessfulResponse];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'PRIHLASKY_SAVE_ERROR',
      code: 'unfulfilled request',
      status: 'A strange error occurred.'
    })
  );
});

it('saveUcast() should dispatch two unsuccessful actions on an invalid token', async () => {
  responses = [authTokenInvalidResponse, unsuccessfulResponse];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'SIGN_IN_ERROR',
      code: 'authentication token invalid',
      status: 'Platnost ověřovacího tokenu pravděpodobně vypršela. Neplatný ověřovací token.'
    })
  );
});

it('saveUcast() should dispatch validation error', async () => {
  responses = [
    successfulResponseSaveUdaje,
    successfulResponseSavePrihlaska,
    successfulResponseSavePlatby
  ];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { validateForm: true, udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({
    type: 'PRIHLASKY_FORM_INVALID',
    code: 'nejde uložit',
    status: 'Přihláška nejde uložit. Povinná pole nejsou vyplněna.'
  });
});

/* Beware: overrides mockWsClient.sendRequest! */
it('saveUcast() should dispatch two unsuccessful actions on error', async () => {
  mockWsClient.sendRequest = async () => Promise.reject(new Error('Parse error!'));
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'PRIHLASKY_SAVE_ERROR',
      code: 'internal error',
      err: new Error('Parse error!')
    })
  );
});

/* Beware: overrides mockWsClient.sendRequest! */
it('saveUcast() should use auth token if available', async () => {
  const tokenSent = { tokenSent: false };
  mockWsClient.sendRequest = async token => {
    if (token) {
      tokenSent.tokenSent = true;
    }
  };
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  expect(tokenSent.tokenSent).toBe(true);
});

it('addValidatedPlatba() should dispatch two successful actions', async () => {
  const store = mockStore({
    registrator: {
      prihlasky: {
        validatePlatba: false,
        novaPlatba: { castka: '200', datum: '2018-05-12T00:00:00Z', typ: 'převodem' }
      }
    }
  });

  await store.dispatch(addValidatedPlatba());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_PLATBA' });
  expect(actions[1]).toEqual({
    type: 'PRIHLASKY_ADD_PLATBA'
  });
});

it('addValidatedPlatba() should dispatch only one action', async () => {
  const store = mockStore({
    registrator: {
      prihlasky: {
        validatePlatba: false,
        novaPlatba: { castka: 'rozepsáno', datum: '2018-05-12T00:00:00Z', typ: 'převodem' }
      }
    }
  });

  await store.dispatch(addValidatedPlatba());
  const actions = store.getActions();
  expect(actions).toHaveLength(1);
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_PLATBA' });
});
<commit_msg>Fix JS-style with prettier.<commit_after>import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import WsClient from '../../WsClient';
import { addValidatedPlatba, saveUcast } from './PrihlaskyActions';

const successfulResponseSaveUdaje = {
  code: 'ok',
  response: {
    id: '===id==='
  },
  requestId: '0.9310306652587377'
};

const successfulResponseSavePrihlaska = {
  code: 'ok',
  requestId: '0.9310306652587377'
};

const successfulResponseSavePlatby = {
  code: 'ok',
  requestId: '0.9310306652587377'
};

const unsuccessfulResponse = {
  code: 'unfulfilled request',
  status: 'A strange error occurred.'
};

const authTokenInvalidResponse = {
  code: 'authentication token invalid',
  status: 'Neplatný ověřovací token.'
};

let responseNumber;
beforeEach(() => {
  responseNumber = 0;
});

const mockWsClient = new WsClient();
let responses = [];
// eslint-disable-next-line no-plusplus
mockWsClient.sendRequest = async () => responses[responseNumber++];

const middlewares = [thunk.withExtraArgument(mockWsClient)];
const mockStore = configureStore(middlewares);

it('saveUcast() should dispatch four successful actions', async () => {
  responses = [
    successfulResponseSaveUdaje,
    successfulResponseSavePrihlaska,
    successfulResponseSavePlatby
  ];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { validateForm: false, udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      id: '===id===',
      type: 'PRIHLASKY_SAVE_SUCCESS'
    })
  );
  expect(actions[3]).toEqual({ type: 'PRIHLASKY_SAVE_SHOW_MODAL' });
});

it('saveUcast() should dispatch two unsuccessful actions 1/2', async () => {
  responses = [unsuccessfulResponse, unsuccessfulResponse];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'PRIHLASKY_SAVE_ERROR',
      code: 'unfulfilled request',
      status: 'A strange error occurred.'
    })
  );
});

it('saveUcast() should dispatch two unsuccessful actions 2/2', async () => {
  responses = [successfulResponseSaveUdaje, unsuccessfulResponse];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'PRIHLASKY_SAVE_ERROR',
      code: 'unfulfilled request',
      status: 'A strange error occurred.'
    })
  );
});

it('saveUcast() should dispatch two unsuccessful actions on an invalid token', async () => {
  responses = [authTokenInvalidResponse, unsuccessfulResponse];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'SIGN_IN_ERROR',
      code: 'authentication token invalid',
      status: 'Platnost ověřovacího tokenu pravděpodobně vypršela. Neplatný ověřovací token.'
    })
  );
});

it('saveUcast() should dispatch validation error', async () => {
  responses = [
    successfulResponseSaveUdaje,
    successfulResponseSavePrihlaska,
    successfulResponseSavePlatby
  ];
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { validateForm: true, udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({
    type: 'PRIHLASKY_FORM_INVALID',
    code: 'nejde uložit',
    status: 'Přihláška nejde uložit. Povinná pole nejsou vyplněna.'
  });
});

/* Beware: overrides mockWsClient.sendRequest! */
it('saveUcast() should dispatch two unsuccessful actions on error', async () => {
  mockWsClient.sendRequest = async () => Promise.reject(new Error('Parse error!'));
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_FORM' });
  expect(actions[1]).toEqual({ type: 'PRIHLASKY_SAVE_REQUEST' });
  expect(actions[2]).toEqual(
    expect.objectContaining({
      type: 'PRIHLASKY_SAVE_ERROR',
      code: 'internal error',
      err: new Error('Parse error!')
    })
  );
});

/* Beware: overrides mockWsClient.sendRequest! */
it('saveUcast() should use auth token if available', async () => {
  const tokenSent = { tokenSent: false };
  mockWsClient.sendRequest = async token => {
    if (token) {
      tokenSent.tokenSent = true;
    }
  };
  const store = mockStore({
    auth: { token: '===token===' },
    registrator: { prihlasky: { udaje: { narozeni: {} }, prihlaska: {} } }
  });

  await store.dispatch(saveUcast());
  expect(tokenSent.tokenSent).toBe(true);
});

it('addValidatedPlatba() should dispatch two successful actions', async () => {
  const store = mockStore({
    registrator: {
      prihlasky: {
        validatePlatba: false,
        novaPlatba: { castka: '200', datum: '2018-05-12T00:00:00Z', typ: 'převodem' }
      }
    }
  });

  await store.dispatch(addValidatedPlatba());
  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_PLATBA' });
  expect(actions[1]).toEqual({
    type: 'PRIHLASKY_ADD_PLATBA'
  });
});

it('addValidatedPlatba() should dispatch only one action', async () => {
  const store = mockStore({
    registrator: {
      prihlasky: {
        validatePlatba: false,
        novaPlatba: { castka: 'rozepsáno', datum: '2018-05-12T00:00:00Z', typ: 'převodem' }
      }
    }
  });

  await store.dispatch(addValidatedPlatba());
  const actions = store.getActions();
  expect(actions).toHaveLength(1);
  expect(actions[0]).toEqual({ type: 'PRIHLASKY_VALIDATE_PLATBA' });
});
<|endoftext|>


<commit_before>/*global define*/
define([
    'jquery','underscore',
    'backbone',
    'masseuse',
    'loadMainContent'
], function (
    $, _,
    Backbone,
    masseuse,
    loadMainContent) {
    'use strict';

    var MasseuseRouter = masseuse.MasseuseRouter;

    return MasseuseRouter.extend({
        userModel : null,
        routes: {
            'login' : 'getLogin',
            'logout' : 'getLogout',
            '' : 'getIndex'
        },
        getLogin : getLogin,
        getLogout : getLogout,
        getIndex : getIndex
    });

    function getLogin() {
        loadMainContent('login');
    }

    function getLogout() {
        loadMainContent('logout');
    }

    function getIndex() {
        loadMainContent('index');
    }

});<commit_msg>Adding a register path to primary router.<commit_after>/*global define*/
define([
    'jquery','underscore',
    'backbone',
    'masseuse',
    'loadMainContent'
], function (
    $, _,
    Backbone,
    masseuse,
    loadMainContent) {
    'use strict';

    var MasseuseRouter = masseuse.MasseuseRouter;

    return MasseuseRouter.extend({
        userModel : null,
        routes: {
            'login' : 'getLogin',
            'logout' : 'getLogout',
            'register' : 'getRegister',
            '' : 'getIndex'
        },
        getLogin : getLogin,
        getLogout : getLogout,
        getRegister : getRegister,
        getIndex : getIndex
    });

    function getLogin() {
        loadMainContent('login');
    }

    function getLogout() {
        loadMainContent('logout');
    }

    function getRegister() {
        loadMainContent('register');
    }

    function getIndex() {
        loadMainContent('index');
    }

});<|endoftext|>


<commit_before>// Visual Studio Code uses these to hush warnings about
//   variable names it can't find declared.
/* global dat */
/* global Stats */
/* global THREE */

var colors = {
	axes: 0x5d5d5d,
	background: 0xeeeeee,
	black: 0x000000,
	pink: 0xff00ff,
	soft_white: 0x404040,
	terrain_frame: 0x009900,
	white: 0xffffff,
};

function View(property){

	var container, stats;
	var camera, cameraOrtho, scene, sceneOrtho, controls, raycaster, renderer;
	var maxDimension;
	var mouse = new THREE.Vector2();
	var INTERSECTED;
	var reticle;
	var size = property.box.size;
	var maxDimension = Math.max(size.x, size.y, size.z);
	var stats;

	var tooltipSprite, tooltipSpriteLocation = new THREE.Vector2();

	var cylinders=[];

	init();
	render();

	function init() {

		raycaster = new THREE.Raycaster();

		container = document.createElement('div');
		document.body.appendChild(container);

		var width = window.innerWidth;		//used to make the camera declarations prettier
		var height = window.innerHeight;
		maxDimension = Math.max(property.box.size.x, property.box.size.y, property.box.size.z);

		var center = property.box.center;

		//Sets up the camera object for the 3d scene
		camera = new THREE.PerspectiveCamera(45, width / height, 0.1, maxDimension*70);
		camera.up.set(0,0,1);
		camera.position.set(Math.max(maxDimension/5, size.x*1.2), Math.max(maxDimension/5,size.y*1.2), Math.max(maxDimension/5, size.z*1.2));
		camera.lookAt(center);

		//Sets up the 2d orthographic camera for tooltips
		cameraOrtho = new THREE.OrthographicCamera( width/-2, width/2, height/2, height/-2, 1, 1000);
		cameraOrtho.position.z = 1;
		cameraOrtho.position.x = 0;
		cameraOrtho.position.y = 0;

		sceneOrtho = new THREE.Scene();

		scene = new THREE.Scene;
		scene.add(new THREE.AmbientLight(colors.soft_white));

		controls = new THREE.OrbitControls(camera);
		controls.zoomSpeed = 3.0;
		controls.minDistance = maxDimension / 100;
		controls.maxDistance = maxDimension * 2;
		controls.target = property.box.center;

		renderer = new THREE.WebGLRenderer({antialias: true});
		renderer.setSize(window.innerWidth, window.innerHeight);
		renderer.setClearColor(colors.background, 1);
		renderer.sortObjects = false;
		renderer.autoClear=false;
		container.appendChild(renderer.domElement);

		var property_boundary = new THREE.Mesh(new THREE.BoxGeometry(size.x, size.y, size.z));
		var box = new THREE.EdgesHelper(property_boundary, colors.axes);
		box.applyMatrix(new THREE.Matrix4().makeTranslation(center.x, center.y, center.z));
		scene.add(box);

		stats = new Stats();
		stats.domElement.style.position = 'absolute';
		stats.domElement.style.right = '0px';
		stats.domElement.style.bottom = '0px';
		container.appendChild(stats.domElement);

		addReticle();

		addSurveyLines();
		setTimeout(addMinerals, 2000);
		addRandomTerrain();
		labelAxis();
	}

	function addRandomTerrain() {
		var maxX = property.box.size.x;
		var maxY = property.box.size.y;

		// Draw 100 lines on each side.
		var dx = maxX / 100.0;
		var dy = maxY / 100.0;
		var mindz = property.box.size.z;
		var maxdz = property.box.size.z / 5.0;

		var meshGeometry = new THREE.Geometry();
		var material = new THREE.LineBasicMaterial({
			color: colors.terrain_frame,
		});

		var heights = [];

		// Draw lines along the y axis.
		for (var x = 0; x < maxX; x += dx) {
			var lineGeometry = new THREE.Geometry();
			heights[x] = [];
			for (var y = 0; y < maxY; y += dy) {
				var z = maxdz * Math.random() + mindz;
				heights[x][y] = z;
				lineGeometry.vertices.push(new THREE.Vector3(x, y, z));
			}
			scene.add(new THREE.Line(lineGeometry, material));
			meshGeometry.merge(lineGeometry);
		}

		// And then along the x axis.
		for (var y = 0; y < maxY; y += dy) {
			var lineGeometry = new THREE.Geometry();
			for (var x = 0; x < maxX; x += dx) {
				var z = heights[x][y];
				lineGeometry.vertices.push(new THREE.Vector3(x, y, z));
			}
			scene.add(new THREE.Line(lineGeometry, material));
			meshGeometry.merge(lineGeometry);
		}

		var mesh = new THREE.Mesh(meshGeometry, material);
		//scene.add(mesh);
	}

	function addReticle(){
		reticle = new THREE.Mesh(
			new THREE.SphereGeometry(maxDimension / 1000),
			new THREE.MeshLambertMaterial({ color: colors.black }));
		reticle.position.x = controls.target.x;
		reticle.position.y = controls.target.y;
		reticle.position.z = controls.target.z;
		scene.add(reticle);
	}

	function addMinerals(){

		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
		var totalGeom = new THREE.Geometry();

		property.holes.forEach(function(hole){
			hole.minerals.forEach(function(mineral){
				mineral.intervals.forEach(function(interval){
					/*var geometry = new THREE.Geometry();
					geometry.vertices.push(interval.start);
					geometry.vertices.push(interval.end);
					scene.add(new THREE.Line(geometry, material));*/
					cylinder = cylinderMesh(interval.start, interval.end,25,material);
					cylinder.updateMatrix();
					cylinders.push(cylinder);
					cylinder.oreConcentration=interval.value;
					totalGeom.merge(cylinder.geometry, cylinder.matrix);

					scene.add(cylinder);
					cylinder.visible=false;
				});
			});
		});
		var total = new THREE.Mesh(totalGeom);
		total.matrixAutoUpdate = false;
    	scene.add(total);
	}

	function cylinderMesh(pointX, pointY, width) {
            var direction = new THREE.Vector3().subVectors(pointY, pointX);
            var orientation = new THREE.Matrix4();
            orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
            orientation.multiply(new THREE.Matrix4().set(1, 0, 0, 0,
                0, 0, 1, 0,
                0, -1, 0, 0,
                0, 0, 0, 1));
            var edgeGeometry = new THREE.CylinderGeometry(width, width, direction.length(), 8, 1);
            var edge = new THREE.Mesh(edgeGeometry);
            edge.applyMatrix(orientation);
            edge.position.x = (pointY.x + pointX.x) / 2;
            edge.position.y = (pointY.y + pointX.y) / 2;
            edge.position.z = (pointY.z + pointX.z) / 2;
            return edge;
    }
	function addSurveyLines(){
		var material = new THREE.LineBasicMaterial({color:colors.black});
		property.holes.forEach(function(hole){
			geometry = new THREE.Geometry();
			hole.surveyPoints.forEach(function(point){
				geometry.vertices.push(point);
			});

			scene.add(new THREE.Line(geometry, material));
		});
	}

	function labelAxis(){
		var axis_format = {
			fontsize: 400,
			size: 1024
		};
		function kFormatter(num) {
			return (num > 999 ? (num/1000) + ' k' : num) + "m";
		}

		var spriteX = makeTextSprite("X", axis_format);
		spriteX.position.set(property.box.size.x, 0, 0);
		scene.add(spriteX);

		var spriteY = makeTextSprite("Y", axis_format);
		spriteY.position.set(0, property.box.size.y, 0);
		scene.add(spriteY);

		var spriteZ = makeTextSprite("Z", axis_format);
		spriteZ.position.set(0, 0, 1.5 * property.box.size.z);
		scene.add(spriteZ);

		for(var i=0; i< property.box.size.x;i+=property.box.size.x/10){
			interval=Math.floor(i);
			interval=parseFloat(interval.toPrecision(2));
			var spriteLabel = makeTextSprite(kFormatter(interval), axis_format);
			spriteLabel.position.set(interval, 0, 0);
			scene.add(spriteLabel);
		}

		for(var i=0; i< property.box.size.y;i+=property.box.size.y/10){
			interval=Math.floor(i);
			interval=parseFloat(interval.toPrecision(2));
			var spriteLabel = makeTextSprite(kFormatter(interval), axis_format);
			spriteLabel.position.set(0, interval, 0);
			scene.add(spriteLabel);
		}

		for(var i=0; i< property.box.size.z;i+=property.box.size.z/3){
			interval=Math.floor(i);
			interval=parseFloat(interval.toPrecision(2));
			var spriteLabel = makeTextSprite(kFormatter(interval), axis_format);
			spriteLabel.position.set(0, 0, interval);
			scene.add(spriteLabel);
		}
	}

	function render(){
		requestAnimationFrame(render);
		controls.update();

		stats.update();

		camera.updateMatrixWorld();

		checkMouseIntercept();

		reticle.position.x = controls.target.x;
		reticle.position.y = controls.target.y;
		reticle.position.z = controls.target.z;

		renderer.clear();
		renderer.render(scene,camera);
		renderer.clearDepth();
		renderer.render(sceneOrtho,cameraOrtho);
	}

	function makeTextSprite(message, parameters) {
		if (parameters === undefined) parameters = {};
		var fontface = parameters.hasOwnProperty("fontface") ? parameters["fontface"] : "Arial";
		var fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 18;
		var size = parameters.hasOwnProperty("size") ? parameters["size"] : 100;
		var textColor = parameters.hasOwnProperty("textColor") ? parameters["textColor"] : { r: 0, g: 0, b: 0, a: 1.0 };

		var canvas = document.createElement('canvas');
		canvas.width = size;
		canvas.height = size;
		var context = canvas.getContext('2d');
		context.font = "Bold " + fontsize + "px " + fontface;

		context.textAlign = 'center';
		context.fillStyle = "rgba(" + textColor.r + ", " + textColor.g + ", " + textColor.b + ", 1.0)";
		context.fillText(message, size / 2, size / 2);

		var texture = new THREE.Texture(canvas);
		texture.needsUpdate = true;

		var spriteMaterial = new THREE.SpriteMaterial({ map: texture, transparent: true });
		var sprite = new THREE.Sprite(spriteMaterial);
		sprite.scale.set(maxDimension/50, maxDimension/50,maxDimension/50);
		return sprite;
	}

	function checkMouseIntercept(){
		raycaster.setFromCamera(mouse, camera);
		var intersects = raycaster.intersectObjects(cylinders);

		if (intersects.length > 0) {
			if (INTERSECTED != intersects[0].object) {
				if (INTERSECTED) {
					var material = INTERSECTED.material;
					if (material.emissive) {
						material.emissive.setHex(INTERSECTED.currentHex);
					} else {
						material.color.setHex(INTERSECTED.currentHex);
					}
				}
				INTERSECTED = intersects[0].object;
				//set sprite to be in front of the orthographic camera so it is visible
				sceneOrtho.remove(tooltipSprite);
				tooltipSprite = makeTextSprite(INTERSECTED.oreConcentration+" g/ton", {fontsize: 18, size: 256}); //Create a basic tooltip display sprite TODO: Make tooltip display info about current drillhole
				tooltipSprite.scale.set(250,250,1);
				tooltipSprite.position.z=0;
				tooltipSprite.position.x=tooltipSpriteLocation.x;
				tooltipSprite.position.y=tooltipSpriteLocation.y;
				sceneOrtho.add(tooltipSprite);

				material = INTERSECTED.material;
				if (material.emissive) {
					INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
					material.emissive.setHex(0xff0000);
				}
				else {
					INTERSECTED.currentHex = material.color.getHex();
					material.color.setHex(0xff0000);
				}

			}

		} else {
			if (INTERSECTED) {
				material = INTERSECTED.material;

				if (material.emissive) {
					material.emissive.setHex(INTERSECTED.currentHex);
				} else {
					material.color.setHex(INTERSECTED.currentHex);
				}
			}
			//set sprite to be behind the ortographic camer so it is not visible
			sceneOrtho.remove(tooltipSprite);
			INTERSECTED = null;
		}
	}

	window.addEventListener('resize', function (event) {

		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();

		renderer.setSize(window.innerWidth, window.innerHeight);
	});

	document.addEventListener('mousemove', onDocumentMouseMove, false);
	function onDocumentMouseMove(event) {

		event.preventDefault();

		mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
		mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

		//this will update the mouse position as well as make the tooltipSprite follow the mouse
		tooltipSpriteLocation.x=event.clientX-(window.innerWidth/2);
		tooltipSpriteLocation.y=-event.clientY+(window.innerHeight/2)+20;
	}
	// Resize the camera when the window is resized.
	window.addEventListener('resize', function (event) {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();

		cameraOrtho.left= - window.innerWidth / 2;
		cameraOrtho.right=  window.innerWidth / 2;
		cameraOrtho.top= window.innerHeight / 2;
		cameraOrtho.bottom=- window.innerHeight / 2;

		cameraOrtho.updateProjectionMatrix();

		renderer.setSize(window.innerWidth, window.innerHeight);
	});
}
<commit_msg>Incrased the texture size of the axis labels.<commit_after>// Visual Studio Code uses these to hush warnings about
//   variable names it can't find declared.
/* global dat */
/* global Stats */
/* global THREE */

var colors = {
	axes: 0x5d5d5d,
	background: 0xeeeeee,
	black: 0x000000,
	pink: 0xff00ff,
	soft_white: 0x404040,
	terrain_frame: 0x009900,
	white: 0xffffff,
};

function View(property){

	var container, stats;
	var camera, cameraOrtho, scene, sceneOrtho, controls, raycaster, renderer;
	var maxDimension;
	var mouse = new THREE.Vector2();
	var INTERSECTED;
	var reticle;
	var size = property.box.size;
	var maxDimension = Math.max(size.x, size.y, size.z);
	var stats;

	var tooltipSprite, tooltipSpriteLocation = new THREE.Vector2();

	var cylinders=[];

	init();
	render();

	function init() {

		raycaster = new THREE.Raycaster();

		container = document.createElement('div');
		document.body.appendChild(container);

		var width = window.innerWidth;		//used to make the camera declarations prettier
		var height = window.innerHeight;
		maxDimension = Math.max(property.box.size.x, property.box.size.y, property.box.size.z);

		var center = property.box.center;

		//Sets up the camera object for the 3d scene
		camera = new THREE.PerspectiveCamera(45, width / height, 0.1, maxDimension*70);
		camera.up.set(0,0,1);
		camera.position.set(Math.max(maxDimension/5, size.x*1.2), Math.max(maxDimension/5,size.y*1.2), Math.max(maxDimension/5, size.z*1.2));
		camera.lookAt(center);

		//Sets up the 2d orthographic camera for tooltips
		cameraOrtho = new THREE.OrthographicCamera( width/-2, width/2, height/2, height/-2, 1, 1000);
		cameraOrtho.position.z = 1;
		cameraOrtho.position.x = 0;
		cameraOrtho.position.y = 0;

		sceneOrtho = new THREE.Scene();

		scene = new THREE.Scene;
		scene.add(new THREE.AmbientLight(colors.soft_white));

		controls = new THREE.OrbitControls(camera);
		controls.zoomSpeed = 3.0;
		controls.minDistance = maxDimension / 100;
		controls.maxDistance = maxDimension * 2;
		controls.target = property.box.center;

		renderer = new THREE.WebGLRenderer({antialias: true});
		renderer.setSize(window.innerWidth, window.innerHeight);
		renderer.setClearColor(colors.background, 1);
		renderer.sortObjects = false;
		renderer.autoClear=false;
		container.appendChild(renderer.domElement);

		var property_boundary = new THREE.Mesh(new THREE.BoxGeometry(size.x, size.y, size.z));
		var box = new THREE.EdgesHelper(property_boundary, colors.axes);
		box.applyMatrix(new THREE.Matrix4().makeTranslation(center.x, center.y, center.z));
		scene.add(box);

		stats = new Stats();
		stats.domElement.style.position = 'absolute';
		stats.domElement.style.right = '0px';
		stats.domElement.style.bottom = '0px';
		container.appendChild(stats.domElement);

		addReticle();

		addSurveyLines();
		setTimeout(addMinerals, 2000);
		addRandomTerrain();
		labelAxis();
	}

	function addRandomTerrain() {
		var maxX = property.box.size.x;
		var maxY = property.box.size.y;

		// Draw 100 lines on each side.
		var dx = maxX / 100.0;
		var dy = maxY / 100.0;
		var mindz = property.box.size.z;
		var maxdz = property.box.size.z / 5.0;

		var meshGeometry = new THREE.Geometry();
		var material = new THREE.LineBasicMaterial({
			color: colors.terrain_frame,
		});

		var heights = [];

		// Draw lines along the y axis.
		for (var x = 0; x < maxX; x += dx) {
			var lineGeometry = new THREE.Geometry();
			heights[x] = [];
			for (var y = 0; y < maxY; y += dy) {
				var z = maxdz * Math.random() + mindz;
				heights[x][y] = z;
				lineGeometry.vertices.push(new THREE.Vector3(x, y, z));
			}
			scene.add(new THREE.Line(lineGeometry, material));
			meshGeometry.merge(lineGeometry);
		}

		// And then along the x axis.
		for (var y = 0; y < maxY; y += dy) {
			var lineGeometry = new THREE.Geometry();
			for (var x = 0; x < maxX; x += dx) {
				var z = heights[x][y];
				lineGeometry.vertices.push(new THREE.Vector3(x, y, z));
			}
			scene.add(new THREE.Line(lineGeometry, material));
			meshGeometry.merge(lineGeometry);
		}

		var mesh = new THREE.Mesh(meshGeometry, material);
		//scene.add(mesh);
	}

	function addReticle(){
		reticle = new THREE.Mesh(
			new THREE.SphereGeometry(maxDimension / 1000),
			new THREE.MeshLambertMaterial({ color: colors.black }));
		reticle.position.x = controls.target.x;
		reticle.position.y = controls.target.y;
		reticle.position.z = controls.target.z;
		scene.add(reticle);
	}

	function addMinerals(){

		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
		var totalGeom = new THREE.Geometry();

		property.holes.forEach(function(hole){
			hole.minerals.forEach(function(mineral){
				mineral.intervals.forEach(function(interval){
					/*var geometry = new THREE.Geometry();
					geometry.vertices.push(interval.start);
					geometry.vertices.push(interval.end);
					scene.add(new THREE.Line(geometry, material));*/
					cylinder = cylinderMesh(interval.start, interval.end,25,material);
					cylinder.updateMatrix();
					cylinders.push(cylinder);
					cylinder.oreConcentration=interval.value;
					totalGeom.merge(cylinder.geometry, cylinder.matrix);

					scene.add(cylinder);
					cylinder.visible=false;
				});
			});
		});
		var total = new THREE.Mesh(totalGeom);
		total.matrixAutoUpdate = false;
    	scene.add(total);
	}

	function cylinderMesh(pointX, pointY, width) {
            var direction = new THREE.Vector3().subVectors(pointY, pointX);
            var orientation = new THREE.Matrix4();
            orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
            orientation.multiply(new THREE.Matrix4().set(1, 0, 0, 0,
                0, 0, 1, 0,
                0, -1, 0, 0,
                0, 0, 0, 1));
            var edgeGeometry = new THREE.CylinderGeometry(width, width, direction.length(), 8, 1);
            var edge = new THREE.Mesh(edgeGeometry);
            edge.applyMatrix(orientation);
            edge.position.x = (pointY.x + pointX.x) / 2;
            edge.position.y = (pointY.y + pointX.y) / 2;
            edge.position.z = (pointY.z + pointX.z) / 2;
            return edge;
    }
	function addSurveyLines(){
		var material = new THREE.LineBasicMaterial({color:colors.black});
		property.holes.forEach(function(hole){
			geometry = new THREE.Geometry();
			hole.surveyPoints.forEach(function(point){
				geometry.vertices.push(point);
			});

			scene.add(new THREE.Line(geometry, material));
		});
	}

	function labelAxis(){
		var axis_format = {
			fontsize: 400,
			size: 2048 // This should be a power of 2!
		};
		function kFormatter(num) {
			return (num > 999 ? (num/1000) + ' k' : num) + "m";
		}

		var spriteX = makeTextSprite("X", axis_format);
		spriteX.position.set(property.box.size.x, 0, 0);
		scene.add(spriteX);

		var spriteY = makeTextSprite("Y", axis_format);
		spriteY.position.set(0, property.box.size.y, 0);
		scene.add(spriteY);

		var spriteZ = makeTextSprite("Z", axis_format);
		spriteZ.position.set(0, 0, 1.5 * property.box.size.z);
		scene.add(spriteZ);

		for(var i=0; i< property.box.size.x;i+=property.box.size.x/10){
			interval=Math.floor(i);
			interval=parseFloat(interval.toPrecision(2));
			var spriteLabel = makeTextSprite(kFormatter(interval), axis_format);
			spriteLabel.position.set(interval, 0, 0);
			scene.add(spriteLabel);
		}

		for(var i=0; i< property.box.size.y;i+=property.box.size.y/10){
			interval=Math.floor(i);
			interval=parseFloat(interval.toPrecision(2));
			var spriteLabel = makeTextSprite(kFormatter(interval), axis_format);
			spriteLabel.position.set(0, interval, 0);
			scene.add(spriteLabel);
		}

		for(var i=0; i< property.box.size.z;i+=property.box.size.z/3){
			interval=Math.floor(i);
			interval=parseFloat(interval.toPrecision(2));
			var spriteLabel = makeTextSprite(kFormatter(interval), axis_format);
			spriteLabel.position.set(0, 0, interval);
			scene.add(spriteLabel);
		}
	}

	function render(){
		requestAnimationFrame(render);
		controls.update();

		stats.update();

		camera.updateMatrixWorld();

		checkMouseIntercept();

		reticle.position.x = controls.target.x;
		reticle.position.y = controls.target.y;
		reticle.position.z = controls.target.z;

		renderer.clear();
		renderer.render(scene,camera);
		renderer.clearDepth();
		renderer.render(sceneOrtho,cameraOrtho);
	}

	function makeTextSprite(message, parameters) {
		if (parameters === undefined) parameters = {};
		var fontface = parameters.hasOwnProperty("fontface") ? parameters["fontface"] : "Arial";
		var fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 18;
		var size = parameters.hasOwnProperty("size") ? parameters["size"] : 100;
		var textColor = parameters.hasOwnProperty("textColor") ? parameters["textColor"] : { r: 0, g: 0, b: 0, a: 1.0 };

		var canvas = document.createElement('canvas');
		canvas.width = size;
		canvas.height = size;
		var context = canvas.getContext('2d');
		context.font = "Bold " + fontsize + "px " + fontface;

		context.textAlign = 'center';
		context.fillStyle = "rgba(" + textColor.r + ", " + textColor.g + ", " + textColor.b + ", 1.0)";
		context.fillText(message, size / 2, size / 2);

		var texture = new THREE.Texture(canvas);
		texture.needsUpdate = true;

		var spriteMaterial = new THREE.SpriteMaterial({ map: texture, transparent: true });
		var sprite = new THREE.Sprite(spriteMaterial);
		sprite.scale.set(maxDimension/50, maxDimension/50,maxDimension/50);
		return sprite;
	}

	function checkMouseIntercept(){
		raycaster.setFromCamera(mouse, camera);
		var intersects = raycaster.intersectObjects(cylinders);

		if (intersects.length > 0) {
			if (INTERSECTED != intersects[0].object) {
				if (INTERSECTED) {
					var material = INTERSECTED.material;
					if (material.emissive) {
						material.emissive.setHex(INTERSECTED.currentHex);
					} else {
						material.color.setHex(INTERSECTED.currentHex);
					}
				}
				INTERSECTED = intersects[0].object;
				//set sprite to be in front of the orthographic camera so it is visible
				sceneOrtho.remove(tooltipSprite);
				tooltipSprite = makeTextSprite(INTERSECTED.oreConcentration+" g/ton", {fontsize: 18, size: 256}); //Create a basic tooltip display sprite TODO: Make tooltip display info about current drillhole
				tooltipSprite.scale.set(250,250,1);
				tooltipSprite.position.z=0;
				tooltipSprite.position.x=tooltipSpriteLocation.x;
				tooltipSprite.position.y=tooltipSpriteLocation.y;
				sceneOrtho.add(tooltipSprite);

				material = INTERSECTED.material;
				if (material.emissive) {
					INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
					material.emissive.setHex(0xff0000);
				}
				else {
					INTERSECTED.currentHex = material.color.getHex();
					material.color.setHex(0xff0000);
				}

			}

		} else {
			if (INTERSECTED) {
				material = INTERSECTED.material;

				if (material.emissive) {
					material.emissive.setHex(INTERSECTED.currentHex);
				} else {
					material.color.setHex(INTERSECTED.currentHex);
				}
			}
			//set sprite to be behind the ortographic camer so it is not visible
			sceneOrtho.remove(tooltipSprite);
			INTERSECTED = null;
		}
	}

	window.addEventListener('resize', function (event) {

		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();

		renderer.setSize(window.innerWidth, window.innerHeight);
	});

	document.addEventListener('mousemove', onDocumentMouseMove, false);
	function onDocumentMouseMove(event) {

		event.preventDefault();

		mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
		mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

		//this will update the mouse position as well as make the tooltipSprite follow the mouse
		tooltipSpriteLocation.x=event.clientX-(window.innerWidth/2);
		tooltipSpriteLocation.y=-event.clientY+(window.innerHeight/2)+20;
	}
	// Resize the camera when the window is resized.
	window.addEventListener('resize', function (event) {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();

		cameraOrtho.left= - window.innerWidth / 2;
		cameraOrtho.right=  window.innerWidth / 2;
		cameraOrtho.top= window.innerHeight / 2;
		cameraOrtho.bottom=- window.innerHeight / 2;

		cameraOrtho.updateProjectionMatrix();

		renderer.setSize(window.innerWidth, window.innerHeight);
	});
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

const inquirer = require('inquirer');
const { spawnSync } = require('child_process');
const { resolve } = require('path');
const {userInfo} = require('os');

const PROJECT_ROOT = resolve(process.cwd(), '..');

(async () => {
  const {postName, openEditor} = await promptUser();
  const postPath = createNewPost(postName);
  if (openEditor) {
    editPost(resolve(PROJECT_ROOT, postPath));
  }
})();

async function promptUser() {
  return new Promise((resolve, reject) => {
    inquirer.prompt(
      [
        {
          type: 'input',
          name: 'postName',
          message: 'What is the name of the new post?',
        },
        {
          type: 'confirm',
          name: 'openEditor',
          message: 'Open editor to start editing?',
          default: true,
        }
      ]
    ).then((answers) => {
      return resolve(answers);
    }).catch(err => reject(err));
  });
}

function createNewPost(postName) {
  const postPath = `blog/${replaceWhitespaces(postName)}/index.md`;
  try {
    spawnSync('npm', ['run', 'create', postPath], {
      cwd: PROJECT_ROOT,
      uid: userInfo().uid,
      gid: userInfo().gid,
    });

    return `content/${postPath}`;
  } catch (err) {
    throw err;
  }
}

function editPost(postPath) {
  try {
    const finished = spawnSync(process.env.EDITOR, [postPath], {
      uid: userInfo().uid,
      gid: userInfo().gid,
      stdio: 'inherit'
    });

    if (finished.error) {
      throw finished.error;
    }

    console.log('Finished with code', finished.status);
  } catch (err) {
    throw err;
  }
}

function replaceWhitespaces(str) {
  return str.replace(/\ /g, '-');
}
<commit_msg>Fix the path of the project's root<commit_after>#!/usr/bin/env node

const inquirer = require('inquirer');
const { spawnSync } = require('child_process');
const { resolve } = require('path');
const {userInfo} = require('os');

const PROJECT_ROOT = resolve(__dirname, '..');

(async () => {
  const {postName, openEditor} = await promptUser();
  const postPath = createNewPost(postName);
  if (openEditor) {
    editPost(resolve(PROJECT_ROOT, postPath));
  }
})();

async function promptUser() {
  return new Promise((resolve, reject) => {
    inquirer.prompt(
      [
        {
          type: 'input',
          name: 'postName',
          message: 'What is the name of the new post?',
        },
        {
          type: 'confirm',
          name: 'openEditor',
          message: 'Open editor to start editing?',
          default: true,
        }
      ]
    ).then((answers) => {
      return resolve(answers);
    }).catch(err => reject(err));
  });
}

function createNewPost(postName) {
  const postPath = `blog/${replaceWhitespaces(postName)}/index.md`;
  try {
    spawnSync('npm', ['run', 'create', postPath], {
      cwd: PROJECT_ROOT,
      uid: userInfo().uid,
      gid: userInfo().gid,
    });

    return `content/${postPath}`;
  } catch (err) {
    throw err;
  }
}

function editPost(postPath) {
  try {
    const finished = spawnSync(process.env.EDITOR, [postPath], {
      uid: userInfo().uid,
      gid: userInfo().gid,
      stdio: 'inherit'
    });

    if (finished.error) {
      throw finished.error;
    }

    console.log('Finished with code', finished.status);
  } catch (err) {
    throw err;
  }
}

function replaceWhitespaces(str) {
  return str.replace(/\ /g, '-');
}
<|endoftext|>


<commit_before>
<commit_msg>Delete setExample.js<commit_after><|endoftext|>


<commit_before>(function(window, $){
	window.ITCheck = window.ITCheck || {};

	var baseUrl = "http://ivorytower.com/IvoryTower/";
	var isLoggedIn = false;
	var lastCheck = 1;
	var delayIfLoggedOut = 1000 * 60 * 10; // 10 minutes

	function shouldSkipRequest(){
		if(isLoggedIn) return false;
		var shouldSkip = (lastCheck + delayIfLoggedOut > Date.now());
		if(!shouldSkip){
			lastCheck = Date.now();
		}
		return shouldSkip;
	}

	function getUnreadThreadCount(alarm) {
		if(shouldSkipRequest()) return;

		// Scrape the unread thread count page
		$.get(baseUrl + 'Forums.asmx/GetUnreadThreadCount', function(data) {
			var numberOfUnread = $(data).find('int').text();
			if(numberOfUnread == 0){
				updateBadge("");
			} else {
				updateBadge(numberOfUnread);
			}
		}, "xml")
		.fail(function(){
			updateBadge("X"); // Let the user know they're probably not logged in.
		});
	}

	function updateBadge(unreadCount) {
		if(unreadCount == "X"){
			isLoggedIn = false;
			setBadgeBackgroundColor([120, 120, 120, 255]);
			setTitle("Logged Out");
		} else {
			isLoggedIn = true;
			setBadgeBackgroundColor([0, 0, 255, 255]);
			setTitle((unreadCount == "" ? "No " : unreadCount) + " unread threads");
		}
		setBadgeText(unreadCount);
	}

	function setBadgeText(newText){
		chrome.browserAction.setBadgeText({text:newText});
	}

	function setBadgeBackgroundColor(colorArray){
		chrome.browserAction.setBadgeBackgroundColor({color:colorArray});
	}

	function setTitle(newTitle){
		chrome.browserAction.setTitle({ title: newTitle});
	}

	var storage = {
		storageGet: function(key, callback){
			var k = key;
			chrome.storage.sync.get(k, function(storageObj){
				callback(storageObj[k]);
			});
		},

		storageSet: function(key, val){
			var pair = {};
			pair[key] = val;
			chrome.storage.sync.set(pair);
		},

		shortcutsEnabledKey: 'ITCheck.shortcuts',
		showCohortsEnabledKey: 'ITCheck.showCohorts',
		shortcutKeys: 'ITCheck.shortcutKeys',
		shortcutKeyKeys: ["nextPost","previousPost", "unreadThread", "rateUp", "rateDown", "showHidden"],

		getShortcutKeyKey: function(name){
			return 'ITCheck.shortcutKey.'+name;
		},

	};

	storage.storageSet(storage.shortcutKeys, storage.shortcutKeyKeys);

	// core exports
	window.ITCheck.getUnreadThreadCount = getUnreadThreadCount;
	window.ITCheck.shouldSkipRequest = shouldSkipRequest;
	window.ITCheck.updateBadge = updateBadge;
	window.ITCheck.setTitle = setTitle;
	window.ITCheck.baseUrl = baseUrl;
	window.ITCheck.storage = storage;
	//window.ITCheck.storageSet = storageSet;
	//window.ITCheck.shortcutKeys = shortcutKeys;

})(window, jQuery);<commit_msg>Only expose one ITCheck object<commit_after>(function(window, $){
	//window.ITCheck = window.ITCheck || {};

	var ITCheck = {
		baseUrl: "http://ivorytower.com/IvoryTower/",
		getUnreadThreadCount: function(alarm) {
			if(this.shouldSkipRequest()) return;

			// Scrape the unread thread count page
			$.get(ITCheck.baseUrl + 'Forums.asmx/GetUnreadThreadCount', function(data) {
				var numberOfUnread = $(data).find('int').text();
				if(numberOfUnread == 0){
					this.updateBadge("");
				} else {
					this.updateBadge(numberOfUnread);
				}
			}, "xml")
			.fail(function(){
				this.updateBadge("X"); // Let the user know they're probably not logged in.
			});
		},

		updateBadge: function(unreadCount) {
			if(unreadCount == "X"){
				isLoggedIn = false;
				setBadgeBackgroundColor([120, 120, 120, 255]);
				this.setTitle("Logged Out");
			} else {
				isLoggedIn = true;
				setBadgeBackgroundColor([0, 0, 255, 255]);
				this.setTitle((unreadCount == "" ? "No " : unreadCount) + " unread threads");
			}
			setBadgeText(unreadCount);
		},
		shouldSkipRequest: function(){
			if(isLoggedIn) return false;
			var shouldSkip = (lastCheck + delayIfLoggedOut > Date.now());
			if(!shouldSkip){
				lastCheck = Date.now();
			}
			return shouldSkip;
		},
		setTitle: function(newTitle){
			chrome.browserAction.setTitle({ title: newTitle});
		},
		storage: {
			storageGet: function(key, callback){
				var k = key;
				chrome.storage.sync.get(k, function(storageObj){
					callback(storageObj[k]);
				});
			},

			storageSet: function(key, val){
				var pair = {};
				pair[key] = val;
				chrome.storage.sync.set(pair);
			},

			shortcutsEnabledKey: 'ITCheck.shortcuts',
			showCohortsEnabledKey: 'ITCheck.showCohorts',
			shortcutKeys: 'ITCheck.shortcutKeys',
			shortcutKeyKeys: ["nextPost","previousPost", "unreadThread", "rateUp", "rateDown", "showHidden"],

			getShortcutKeyKey: function(name){
				return 'ITCheck.shortcutKey.'+name;
			},

		}
	};
	var storage = ITCheck.storage;
	storage.storageSet(storage.shortcutKeys, storage.shortcutKeyKeys);
	var isLoggedIn = false;
	var lastCheck = 1;
	var delayIfLoggedOut = 1000 * 60 * 10; // 10 minutes

	function setBadgeText(newText){
		chrome.browserAction.setBadgeText({text:newText});
	}

	function setBadgeBackgroundColor(colorArray){
		chrome.browserAction.setBadgeBackgroundColor({color:colorArray});
	}

	// export on window
	window.ITCheck = ITCheck;
})(window, jQuery);<|endoftext|>


<commit_before>import Service from '@ember/service';
import {ICON_MAPPING} from 'ghost-admin/components/modal-portal-settings';
import {inject as service} from '@ember/service';
export default class MembersUtilsService extends Service {
    @service config;
    @service settings;

    get isStripeEnabled() {
        const stripeDirect = this.config.get('stripeDirect');

        const hasDirectKeys = !!this.settings.get('stripeSecretKey') && !!this.settings.get('stripePublishableKey');
        const hasConnectKeys = !!this.settings.get('stripeConnectSecretKey') && !!this.settings.get('stripeConnectPublishableKey');

        if (stripeDirect) {
            return hasDirectKeys;
        }

        return hasConnectKeys || hasDirectKeys;
    }

    getPortalPreviewUrl(args) {
        let {
            disableBackground,
            buttonIcon,
            page = 'signup',
            isFree = true,
            isMonthly = true,
            isYearly = true,
            monthlyPrice,
            yearlyPrice,
            currency
        } = args;

        if (!buttonIcon) {
            const defaultIconKeys = ICON_MAPPING.map(icon => icon.value);
            buttonIcon = this.settings.get('portalButtonIcon') || defaultIconKeys[0];
        }

        const baseUrl = this.config.get('blogUrl');
        const portalBase = '/#/portal/preview';
        const settingsParam = new URLSearchParams();
        const signupButtonText = this.settings.get('portalButtonSignupText') || '';

        settingsParam.append('button', this.settings.get('portalButton'));
        settingsParam.append('name', this.settings.get('portalName'));
        settingsParam.append('isFree', isFree);
        settingsParam.append('isMonthly', isMonthly);
        settingsParam.append('isYearly', isYearly);
        settingsParam.append('page', page);
        settingsParam.append('buttonIcon', encodeURIComponent(buttonIcon));
        settingsParam.append('signupButtonText', encodeURIComponent(signupButtonText));

        if (this.settings.get('accentColor') === '' || this.settings.get('accentColor')) {
            settingsParam.append('accentColor', encodeURIComponent(`${this.settings.get('accentColor')}`));
        }
        if (this.settings.get('portalButtonStyle')) {
            settingsParam.append('buttonStyle', encodeURIComponent(this.settings.get('portalButtonStyle')));
        }

        if (monthlyPrice) {
            settingsParam.append('monthlyPrice', monthlyPrice);
        }
        if (yearlyPrice) {
            settingsParam.append('yearlyPrice', yearlyPrice);
        }
        if (currency) {
            settingsParam.append('currency', currency);
        }

        if (disableBackground) {
            settingsParam.append('disableBackground', true);
        }

        return `${baseUrl}${portalBase}?${settingsParam.toString()}`;
    }
}
<commit_msg>Fixed portal plan params in preview mode<commit_after>import Service from '@ember/service';
import {ICON_MAPPING} from 'ghost-admin/components/modal-portal-settings';
import {inject as service} from '@ember/service';
export default class MembersUtilsService extends Service {
    @service config;
    @service settings;

    get isStripeEnabled() {
        const stripeDirect = this.config.get('stripeDirect');

        const hasDirectKeys = !!this.settings.get('stripeSecretKey') && !!this.settings.get('stripePublishableKey');
        const hasConnectKeys = !!this.settings.get('stripeConnectSecretKey') && !!this.settings.get('stripeConnectPublishableKey');

        if (stripeDirect) {
            return hasDirectKeys;
        }

        return hasConnectKeys || hasDirectKeys;
    }

    getPortalPreviewUrl(args) {
        let {
            disableBackground,
            buttonIcon,
            page = 'signup',
            isFreeChecked = true,
            isMonthlyChecked = true,
            isYearlyChecked = true,
            monthlyPrice,
            yearlyPrice,
            currency
        } = args;

        if (!buttonIcon) {
            const defaultIconKeys = ICON_MAPPING.map(icon => icon.value);
            buttonIcon = this.settings.get('portalButtonIcon') || defaultIconKeys[0];
        }

        const baseUrl = this.config.get('blogUrl');
        const portalBase = '/#/portal/preview';
        const settingsParam = new URLSearchParams();
        const signupButtonText = this.settings.get('portalButtonSignupText') || '';

        settingsParam.append('button', this.settings.get('portalButton'));
        settingsParam.append('name', this.settings.get('portalName'));
        settingsParam.append('isFree', isFreeChecked);
        settingsParam.append('isMonthly', isMonthlyChecked);
        settingsParam.append('isYearly', isYearlyChecked);
        settingsParam.append('page', page);
        settingsParam.append('buttonIcon', encodeURIComponent(buttonIcon));
        settingsParam.append('signupButtonText', encodeURIComponent(signupButtonText));

        if (this.settings.get('accentColor') === '' || this.settings.get('accentColor')) {
            settingsParam.append('accentColor', encodeURIComponent(`${this.settings.get('accentColor')}`));
        }
        if (this.settings.get('portalButtonStyle')) {
            settingsParam.append('buttonStyle', encodeURIComponent(this.settings.get('portalButtonStyle')));
        }

        if (monthlyPrice) {
            settingsParam.append('monthlyPrice', monthlyPrice);
        }
        if (yearlyPrice) {
            settingsParam.append('yearlyPrice', yearlyPrice);
        }
        if (currency) {
            settingsParam.append('currency', currency);
        }

        if (disableBackground) {
            settingsParam.append('disableBackground', true);
        }

        return `${baseUrl}${portalBase}?${settingsParam.toString()}`;
    }
}
<|endoftext|>