<commit_before>/**
 * Copyright 2014 Ian Davies
 *
 * 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.
 */
define([], function() {

	return ["$location", function($location) {

		return {

			scope: true,

			restrict: 'A',

			templateUrl: "/partials/content/Accordion.html",

			link: function(scope, element, attrs) {

				// Work out whether we're on a question page. If we are, open the first accordion section. Otherwise, only open it if it is the first item on the page.
				var isOnQuestionPage = false;
				var p = scope;
				while(p = p.$parent) {
					if (!p.doc)
						continue;

					if (p.doc.type == "isaacQuestionPage")
						isOnQuestionPage = true;
				}

				scope.openChildren = {
					0: scope.contentChunkIndex == 0 || isOnQuestionPage,
				};

				scope.titleSuffixes = {};

				scope.toggleChild = function(i) {
					scope.openChildren[i] = !scope.openChildren[i];

					if (scope.openChildren[i]) {
						// This section was just opened.

						scope.$emit("accordionsectionopen", i, scope.doc.children[i]);
						scope.$broadcast("accordionSectionOpened", i);
					}
				}

				// Assuming we have questions in every accordion section, we are guaranteed to get
				// one newQuestionAnswer event per section on initialisation. The order is NOT guaranteed.

				var answersOnLoad = {};

				var updateLoadedQuestions = function() {
					if ($location.hash())
						return;

					var encounteredNotCorrect = false;
					for (var i = 0; i < scope.doc.children.length; i++) {
						if (!(i in answersOnLoad))
							break;

						var ans = answersOnLoad[i];

						// If there is an answer, close the tab and display the answer.
						if (ans) {
							scope.openChildren[i] = false;
							scope.titleSuffixes[i] = ans;
						} else {
							if (!encounteredNotCorrect) {
								// This is the first incorrect or not-answered question part. Open it.
								scope.openChildren[i] = true;
							} else {
								// This is NOT the first incorrect or not-answered question part. Close it.
								scope.openChildren[i] = false;
							}
							encounteredNotCorrect = true;
						}
					}
				};

				scope.$on("newQuestionAnswer", function(e, index, ans) {
					// TODO: Make sure we can go "back" to this question. This accordion stuff only works on refresh

					if (index in answersOnLoad) {

						// This is a change - someone has submitted an answer.
						if (ans) {
							// They got the answer right. Display the answer and if the next question isn't open, open it.
							scope.titleSuffixes[index] = ans;
							scope.openChildren[index+1] = true;
						} else {
							// They got the answer wrong. Don't change anything.
						}

					} else {
						// We have not had any communication from this section before. This must be a page load.
						answersOnLoad[index] = ans;

						updateLoadedQuestions();
					}
				});

				scope.$on("ensureVisible", function(e) {

					if (e.targetScope == scope)
						return;

					e.stopPropagation();
					var section = e.targetScope.accordionSection;

					scope.openChildren[section] = true;

					scope.$emit("ensureVisible");
				});
			}
		};
	}];
});<commit_msg>Render mathjax properly in accordion titles.<commit_after>/**
 * Copyright 2014 Ian Davies
 *
 * 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.
 */
define([], function() {

	return ["$location", function($location) {

		return {

			scope: true,

			restrict: 'A',

			templateUrl: "/partials/content/Accordion.html",

			link: function(scope, element, attrs) {

				// Work out whether we're on a question page. If we are, open the first accordion section. Otherwise, only open it if it is the first item on the page.
				var isOnQuestionPage = false;
				var p = scope;
				while(p = p.$parent) {
					if (!p.doc)
						continue;

					if (p.doc.type == "isaacQuestionPage")
						isOnQuestionPage = true;
				}

				scope.openChildren = {
					0: scope.contentChunkIndex == 0 || isOnQuestionPage,
				};

				scope.titleSuffixes = {};

				scope.toggleChild = function(i) {
					scope.openChildren[i] = !scope.openChildren[i];

					if (scope.openChildren[i]) {
						// This section was just opened.

						scope.$emit("accordionsectionopen", i, scope.doc.children[i]);
						scope.$broadcast("accordionSectionOpened", i);
					}
				}

				// Assuming we have questions in every accordion section, we are guaranteed to get
				// one newQuestionAnswer event per section on initialisation. The order is NOT guaranteed.

				var answersOnLoad = {};

				var updateLoadedQuestions = function() {
					if ($location.hash())
						return;

					var encounteredNotCorrect = false;
					for (var i = 0; i < scope.doc.children.length; i++) {
						if (!(i in answersOnLoad))
							break;

						var ans = answersOnLoad[i];

						// If there is an answer, close the tab and display the answer.
						if (ans) {
							scope.openChildren[i] = false;
							scope.titleSuffixes[i] = ans;
						} else {
							if (!encounteredNotCorrect) {
								// This is the first incorrect or not-answered question part. Open it.
								scope.openChildren[i] = true;
							} else {
								// This is NOT the first incorrect or not-answered question part. Close it.
								scope.openChildren[i] = false;
							}
							encounteredNotCorrect = true;
						}
					}
				};

				scope.$on("newQuestionAnswer", function(e, index, ans) {
					// TODO: Make sure we can go "back" to this question. This accordion stuff only works on refresh

					if (index in answersOnLoad) {

						// This is a change - someone has submitted an answer.
						if (ans) {
							// They got the answer right. Display the answer and if the next question isn't open, open it.
							scope.titleSuffixes[index] = ans;
							scope.openChildren[index+1] = true;
						} else {
							// They got the answer wrong. Don't change anything.
						}

					} else {
						// We have not had any communication from this section before. This must be a page load.
						answersOnLoad[index] = ans;

						updateLoadedQuestions();
					}
					setTimeout(function() {
						$rootScope.requestMathjaxRender();
					}, 0);
				});

				scope.$on("ensureVisible", function(e) {

					if (e.targetScope == scope)
						return;

					e.stopPropagation();
					var section = e.targetScope.accordionSection;

					scope.openChildren[section] = true;

					scope.$emit("ensureVisible");
				});
			}
		};
	}];
});<|endoftext|>


<commit_before>/**
 * @author: @AngularClass
 */

const helpers = require('./helpers');
const webpackMerge = require('webpack-merge'); // used to merge webpack configs
const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev

/**
 * Webpack Plugins
 */
const DedupePlugin = require('webpack/lib/optimize/DedupePlugin');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const IgnorePlugin = require('webpack/lib/IgnorePlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin');
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const ngtools = require('@ngtools/webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

/**
 * Webpack Constants
 */
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
const FABRIC8_WIT_API_URL = process.env.FABRIC8_WIT_API_URL || 'http://api.almighty.io/api/';
const FABRIC8_RECOMMENDER_API_URL = process.env.FABRIC8_RECOMMENDER_API_URL || 'http://api-bayesian.dev.rdu2c.fabric8.io/api/v1/';
const FABRIC8_FORGE_URL = process.env.FORGE_URL;
const PUBLIC_PATH = process.env.PUBLIC_PATH || '/';

const HOST = process.env.HOST || 'localhost';
const PORT = process.env.PORT || 8080;
const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
  host: HOST,
  port: PORT,
  ENV: ENV,
  HMR: false,
  FABRIC8_WIT_API_URL: FABRIC8_WIT_API_URL,
  FABRIC8_RECOMMENDER_API_URL: FABRIC8_RECOMMENDER_API_URL,
  FABRIC8_FORGE_URL: FABRIC8_FORGE_URL,
  PUBLIC_PATH: PUBLIC_PATH

});

module.exports = function (env) {
  console.log('The env from the webpack.prod config: ' + JSON.stringify(env, null, 2));
  return webpackMerge(commonConfig({env: ENV}), {

    /**
     * Developer tool to enhance debugging
     *
     * See: http://webpack.github.io/docs/configuration.html#devtool
     * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
     */
    devtool: 'source-map',

    /**
     * Options affecting the output of the compilation.
     *
     * See: http://webpack.github.io/docs/configuration.html#output
     */
    output: {

      /**
       * The output directory as absolute path (required).
       *
       * See: http://webpack.github.io/docs/configuration.html#output-path
       */
      path: helpers.root('dist'),
      // path: path.join(process.cwd(), 'dist'),
      publicPath: METADATA.PUBLIC_PATH,

      /**
       * Specifies the name of each output file on disk.
       * IMPORTANT: You must not specify an absolute path here!
       *
       * See: http://webpack.github.io/docs/configuration.html#output-filename
       */
      filename: '[name].[chunkhash].bundle.js',

      /**
       * The filename of the SourceMaps for the JavaScript files.
       * They are inside the output.path directory.
       *
       * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename
       */
      sourceMapFilename: '[name].[chunkhash].bundle.map',

      /**
       * The filename of non-entry chunks as relative path
       * inside the output.path directory.
       *
       * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename
       */
      chunkFilename: '[id].[chunkhash].chunk.js'

    },

    /**
     * Add additional plugins to the compiler.
     *
     * See: http://webpack.github.io/docs/configuration.html#plugins
     */
    plugins: [

      /**
       * Plugin: @ngtools/webpack
       * Description: Set up AoT for webpack, including SASS precompile
       */
 /*     new ngtools.AotPlugin({
        tsConfigPath: 'tsconfig-aot.json',
        // mainPath: "src/main.browser.ts"
        // entryModule: 'src/app/app.module#AppModule',
        // genDir: 'aot'
      }),
*/
      /**
       * Plugin: WebpackMd5Hash
       * Description: Plugin to replace a standard webpack chunkhash with md5.
       *
       * See: https://www.npmjs.com/package/webpack-md5-hash
       */
      new WebpackMd5Hash(),

      /**
       * Webpack plugin and CLI utility that represents bundle content as convenient interactive zoomable treemap
       */
/*
      new BundleAnalyzerPlugin({
        generateStatsFile: true
      }),
*/

      /**
       * Plugin: DedupePlugin
       * Description: Prevents the inclusion of duplicate code into your bundle
       * and instead applies a copy of the function at runtime.
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
       * See: https://github.com/webpack/docs/wiki/optimization#deduplication
       */
      // new DedupePlugin(), // see: https://github.com/angular/angular-cli/issues/1587

      /**
       * Plugin: DefinePlugin
       * Description: Define free variables.
       * Useful for having development builds with debug logging or adding global constants.
       *
       * Environment helpers
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
       */
      // NOTE: when adding more properties make sure you include them in custom-typings.d.ts
      new DefinePlugin({
        'ENV': JSON.stringify(METADATA.ENV),
        'HMR': METADATA.HMR,
        'process.env': {
          'ENV': JSON.stringify(METADATA.ENV),
          'NODE_ENV': JSON.stringify(METADATA.ENV),
          'HMR': METADATA.HMR,
          'FABRIC8_WIT_API_URL' : JSON.stringify(METADATA.FABRIC8_WIT_API_URL),
          'FABRIC8_RECOMMENDER_API_URL' : JSON.stringify(METADATA.FABRIC8_RECOMMENDER_API_URL),
          'FABRIC8_FORGE_URL': JSON.stringify(METADATA.FABRIC8_FORGE_URL),
          'PUBLIC_PATH' : JSON.stringify(METADATA.PUBLIC_PATH)
        }
      }),

      /**
       * Plugin: UglifyJsPlugin
       * Description: Minimize all JavaScript output of chunks.
       * Loaders are switched into minimizing mode.
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
       */
      // NOTE: To debug prod builds uncomment //debug lines and comment //prod lines
      new UglifyJsPlugin({
        // beautify: true, //debug
        // mangle: false, //debug
        // dead_code: false, //debug
        // unused: false, //debug
        // deadCode: false, //debug
        // compress: {
        //   screw_ie8: true,
        //   keep_fnames: true,
        //   drop_debugger: false,
        //   dead_code: false,
        //   unused: false
        // }, // debug
        // comments: true, //debug

        beautify: false, //prod
        mangle: {
          screw_ie8: true,
          keep_fnames: true
        }, //prod
        compress: {
          screw_ie8: true
        }, //prod
        comments: false //prod
      }),

      /**
       * Plugin: NormalModuleReplacementPlugin
       * Description: Replace resources that matches resourceRegExp with newResource
       *
       * See: http://webpack.github.io/docs/list-of-plugins.html#normalmodulereplacementplugin
       */

      new NormalModuleReplacementPlugin(
        /angular2-hmr/,
        helpers.root('config/modules/angular2-hmr-prod.js')
      ),

      /**
       * Plugin: IgnorePlugin
       * Description: Don’t generate modules for requests matching the provided RegExp.
       *
       * See: http://webpack.github.io/docs/list-of-plugins.html#ignoreplugin
       */

      // new IgnorePlugin(/angular2-hmr/),

      /**
       * Plugin: CompressionPlugin
       * Description: Prepares compressed versions of assets to serve
       * them with Content-Encoding
       *
       * See: https://github.com/webpack/compression-webpack-plugin
       */
      //  install compression-webpack-plugin
      // new CompressionPlugin({
      //   regExp: /\.css$|\.html$|\.js$|\.map$/,
      //   threshold: 2 * 1024
      // })

      /**
       * Plugin LoaderOptionsPlugin (experimental)
       *
       * See: https://gist.github.com/sokra/27b24881210b56bbaff7
       */
      new LoaderOptionsPlugin({
        debug: false,
        options: {

          /**
           * Static analysis linter for TypeScript advanced options configuration
           * Description: An extensible linter for the TypeScript language.
           *
           * See: https://github.com/wbuchwalter/tslint-loader
           */
          tslint: {
            emitErrors: true,
            failOnHint: true,
            resourcePath: 'src'
          },

          /**
           * Html loader advanced options
           *
           * See: https://github.com/webpack/html-loader#advanced-options
           */
          // TODO: Need to workaround Angular 2's html syntax => #id [bind] (event) *ngFor
          htmlLoader: {
            minimize: true,
            removeAttributeQuotes: false,
            caseSensitive: true,
            customAttrSurround: [
              [/#/, /(?:)/],
              [/\*/, /(?:)/],
              [/\[?\(?/, /(?:)/]
            ],
            customAttrAssign: [/\)?\]?=/]
          }
        }
      })
    ],

    /*
     * Include polyfills or mocks for various node stuff
     * Description: Node configuration
     *
     * See: https://webpack.github.io/docs/configuration.html#node
     */
    node: {
      global: true,
      crypto: 'empty',
      process: false,
      module: false,
      clearImmediate: false,
      setImmediate: false
    }

  });
};
<commit_msg>Add source maps to prod<commit_after>/**
 * @author: @AngularClass
 */

const helpers = require('./helpers');
const webpackMerge = require('webpack-merge'); // used to merge webpack configs
const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev

/**
 * Webpack Plugins
 */
const DedupePlugin = require('webpack/lib/optimize/DedupePlugin');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const IgnorePlugin = require('webpack/lib/IgnorePlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin');
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const ngtools = require('@ngtools/webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

/**
 * Webpack Constants
 */
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
const FABRIC8_WIT_API_URL = process.env.FABRIC8_WIT_API_URL || 'http://api.almighty.io/api/';
const FABRIC8_RECOMMENDER_API_URL = process.env.FABRIC8_RECOMMENDER_API_URL || 'http://api-bayesian.dev.rdu2c.fabric8.io/api/v1/';
const FABRIC8_FORGE_URL = process.env.FORGE_URL;
const PUBLIC_PATH = process.env.PUBLIC_PATH || '/';

const HOST = process.env.HOST || 'localhost';
const PORT = process.env.PORT || 8080;
const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
  host: HOST,
  port: PORT,
  ENV: ENV,
  HMR: false,
  FABRIC8_WIT_API_URL: FABRIC8_WIT_API_URL,
  FABRIC8_RECOMMENDER_API_URL: FABRIC8_RECOMMENDER_API_URL,
  FABRIC8_FORGE_URL: FABRIC8_FORGE_URL,
  PUBLIC_PATH: PUBLIC_PATH

});

module.exports = function (env) {
  console.log('The env from the webpack.prod config: ' + JSON.stringify(env, null, 2));
  return webpackMerge(commonConfig({env: ENV}), {

    /**
     * Developer tool to enhance debugging
     *
     * See: http://webpack.github.io/docs/configuration.html#devtool
     * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
     */
    devtool: 'cheap-module-source-map',

    /**
     * Options affecting the output of the compilation.
     *
     * See: http://webpack.github.io/docs/configuration.html#output
     */
    output: {

      /**
       * The output directory as absolute path (required).
       *
       * See: http://webpack.github.io/docs/configuration.html#output-path
       */
      path: helpers.root('dist'),
      // path: path.join(process.cwd(), 'dist'),
      publicPath: METADATA.PUBLIC_PATH,

      /**
       * Specifies the name of each output file on disk.
       * IMPORTANT: You must not specify an absolute path here!
       *
       * See: http://webpack.github.io/docs/configuration.html#output-filename
       */
      filename: '[name].[chunkhash].bundle.js',

      /**
       * The filename of the SourceMaps for the JavaScript files.
       * They are inside the output.path directory.
       *
       * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename
       */
      sourceMapFilename: '[name].[chunkhash].bundle.map',

      /**
       * The filename of non-entry chunks as relative path
       * inside the output.path directory.
       *
       * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename
       */
      chunkFilename: '[id].[chunkhash].chunk.js'

    },

    /**
     * Add additional plugins to the compiler.
     *
     * See: http://webpack.github.io/docs/configuration.html#plugins
     */
    plugins: [

      /**
       * Plugin: @ngtools/webpack
       * Description: Set up AoT for webpack, including SASS precompile
       */
 /*     new ngtools.AotPlugin({
        tsConfigPath: 'tsconfig-aot.json',
        // mainPath: "src/main.browser.ts"
        // entryModule: 'src/app/app.module#AppModule',
        // genDir: 'aot'
      }),
*/
      /**
       * Plugin: WebpackMd5Hash
       * Description: Plugin to replace a standard webpack chunkhash with md5.
       *
       * See: https://www.npmjs.com/package/webpack-md5-hash
       */
      new WebpackMd5Hash(),

      /**
       * Webpack plugin and CLI utility that represents bundle content as convenient interactive zoomable treemap
       */
/*
      new BundleAnalyzerPlugin({
        generateStatsFile: true
      }),
*/

      /**
       * Plugin: DedupePlugin
       * Description: Prevents the inclusion of duplicate code into your bundle
       * and instead applies a copy of the function at runtime.
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
       * See: https://github.com/webpack/docs/wiki/optimization#deduplication
       */
      // new DedupePlugin(), // see: https://github.com/angular/angular-cli/issues/1587

      /**
       * Plugin: DefinePlugin
       * Description: Define free variables.
       * Useful for having development builds with debug logging or adding global constants.
       *
       * Environment helpers
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
       */
      // NOTE: when adding more properties make sure you include them in custom-typings.d.ts
      new DefinePlugin({
        'ENV': JSON.stringify(METADATA.ENV),
        'HMR': METADATA.HMR,
        'process.env': {
          'ENV': JSON.stringify(METADATA.ENV),
          'NODE_ENV': JSON.stringify(METADATA.ENV),
          'HMR': METADATA.HMR,
          'FABRIC8_WIT_API_URL' : JSON.stringify(METADATA.FABRIC8_WIT_API_URL),
          'FABRIC8_RECOMMENDER_API_URL' : JSON.stringify(METADATA.FABRIC8_RECOMMENDER_API_URL),
          'FABRIC8_FORGE_URL': JSON.stringify(METADATA.FABRIC8_FORGE_URL),
          'PUBLIC_PATH' : JSON.stringify(METADATA.PUBLIC_PATH)
        }
      }),

      /**
       * Plugin: UglifyJsPlugin
       * Description: Minimize all JavaScript output of chunks.
       * Loaders are switched into minimizing mode.
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
       */
      // NOTE: To debug prod builds uncomment //debug lines and comment //prod lines
      new UglifyJsPlugin({
        // beautify: true, //debug
        // mangle: false, //debug
        // dead_code: false, //debug
        // unused: false, //debug
        // deadCode: false, //debug
        // compress: {
        //   screw_ie8: true,
        //   keep_fnames: true,
        //   drop_debugger: false,
        //   dead_code: false,
        //   unused: false
        // }, // debug
        // comments: true, //debug

        beautify: false, //prod
        mangle: {
          screw_ie8: true,
          keep_fnames: true
        }, //prod
        compress: {
          screw_ie8: true
        }, //prod
        comments: false //prod
      }),

      /**
       * Plugin: NormalModuleReplacementPlugin
       * Description: Replace resources that matches resourceRegExp with newResource
       *
       * See: http://webpack.github.io/docs/list-of-plugins.html#normalmodulereplacementplugin
       */

      new NormalModuleReplacementPlugin(
        /angular2-hmr/,
        helpers.root('config/modules/angular2-hmr-prod.js')
      ),

      /**
       * Plugin: IgnorePlugin
       * Description: Don’t generate modules for requests matching the provided RegExp.
       *
       * See: http://webpack.github.io/docs/list-of-plugins.html#ignoreplugin
       */

      // new IgnorePlugin(/angular2-hmr/),

      /**
       * Plugin: CompressionPlugin
       * Description: Prepares compressed versions of assets to serve
       * them with Content-Encoding
       *
       * See: https://github.com/webpack/compression-webpack-plugin
       */
      //  install compression-webpack-plugin
      // new CompressionPlugin({
      //   regExp: /\.css$|\.html$|\.js$|\.map$/,
      //   threshold: 2 * 1024
      // })

      /**
       * Plugin LoaderOptionsPlugin (experimental)
       *
       * See: https://gist.github.com/sokra/27b24881210b56bbaff7
       */
      new LoaderOptionsPlugin({
        debug: false,
        options: {

          /**
           * Static analysis linter for TypeScript advanced options configuration
           * Description: An extensible linter for the TypeScript language.
           *
           * See: https://github.com/wbuchwalter/tslint-loader
           */
          tslint: {
            emitErrors: true,
            failOnHint: true,
            resourcePath: 'src'
          },

          /**
           * Html loader advanced options
           *
           * See: https://github.com/webpack/html-loader#advanced-options
           */
          // TODO: Need to workaround Angular 2's html syntax => #id [bind] (event) *ngFor
          htmlLoader: {
            minimize: true,
            removeAttributeQuotes: false,
            caseSensitive: true,
            customAttrSurround: [
              [/#/, /(?:)/],
              [/\*/, /(?:)/],
              [/\[?\(?/, /(?:)/]
            ],
            customAttrAssign: [/\)?\]?=/]
          }
        }
      })
    ],

    /*
     * Include polyfills or mocks for various node stuff
     * Description: Node configuration
     *
     * See: https://webpack.github.io/docs/configuration.html#node
     */
    node: {
      global: true,
      crypto: 'empty',
      process: false,
      module: false,
      clearImmediate: false,
      setImmediate: false
    }

  });
};
<|endoftext|>


<commit_before>/** **********************
 *   HELPER FUNCTIONS    *
 *********************** */

const removeDollarFields = (obj) => {
  Object.keys(obj).forEach((property) => {
    if (property.startsWith('$$') && property != '$$meta') {
      delete obj[property];
    } else if (obj.property !== null && typeof obj.property === 'object') {
      removeDollarFields(obj[property]);
    }
  });
  return obj;
};

/**
 * Helper function to compute a hash code from a string as found here:
 *  https://stackoverflow.com/a/7616484
 */
function hashCode(theString) {
  let hash = 0;
  let chr;
  if (theString.length === 0) return hash;
  for (let i = 0; i < theString.length; i++) {
    chr = theString.charCodeAt(i);
    hash = ((hash << 5) - hash) + chr;
    // eslint-disable-next-line no-bitwise
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
}

/**
 * This function will make a few fixes to old api's that weren't fully compliant
 * to make sure the assumptions we make later on in the code will be valid.
 *
 * For example:
 *  * if a resource doesn't have a key, then we generate a key from the permalink
 *  * if a resource doesn't have $$meta.modified, then we'll add a default date in there
 *
 * @param {object} r
 */
function fixResourceForStoring(r) {
  if (r.$$meta && r.$$meta.modified && r.key) {
    return r;
  }
  retVal = clonedeep(r);
  if (!(r.$$meta && r.$$meta.modified)) {
    retVal.$$meta.modified = new Date().toISOString();
  }
  if (!r.key && r.$$meta && r.$$meta.permalink) {
    retVal.key = r.$$meta.permalink.substring(r.$$meta.permalink.lastIndexOf('/') + 1);
  }
  return retVal;
}

/**
 * Either adds expand= to the url or replaces the existing expand= with
 * the given expansion
 * @param {*} path
 * @param {*} expansion
 */
function setExpandOnPath(path, expansion) {
  if (path.includes('?') && path.includes('expand=')) {
    return path.replace(/expand=[^&$]*/, `expand=${expansion}`);
  }

  return `${path}${path.includes('?') ? '&' : '?'}expand=${expansion}`;
}

/**
 * @param {Number} nrOfMilliseconds
 * @param {String} unit can be ms, s, m, h, d
 */
const msToOtherUnit = (milliseconds, unit) => {
  let elapsedInUnit;
  switch (unit) {
    case 'ms': elapsedInUnit = milliseconds; break;
    case 's': elapsedInUnit = milliseconds / 1000; break;
    case 'm': elapsedInUnit = milliseconds / 1000 / 60; break;
    case 'h': elapsedInUnit = milliseconds / 1000 / 60 / 60; break;
    case 'd': elapsedInUnit = milliseconds / 1000 / 60 / 60 / 24; break;
    default: elapsedInUnit = milliseconds; break;
  }
  return elapsedInUnit;
};

/**
 * elapsedTimeCalculations calculates the elapsedMilliseconds given
 *
 * @param {Number} startDate obtained with a Date.now() call
 * @param {String} unit can be ms, s, m, h, d
 * @param {Number} amount [optional] if present will add avg per second/minute/hour
 * @param {String} avgUnit [optional] if not set, same unit as above, but you can make it avg per m, h, d, ... if you want
 * @param {Number} endDate [optional] obtained with a Date.now() call, if missing this function will do a Date.now() call for you
 */
/**
 *
 */
const elapsedTimeCalculations = (startDate, unit = 'ms', amount = false, avgUnit = false, endDate = Date.now()) => {
  // eslint-disable-next-line no-param-reassign
  if (!avgUnit) avgUnit = unit;
  const retVal = {
    unit, amount, avgUnit, startDate, endDate,
  };
  retVal.elapsedMilliseconds = (endDate - startDate);
  retVal.elapsedInUnit = msToOtherUnit(retVal.elapsedMilliseconds, unit);
  retVal.elapsedInAvgUnit = msToOtherUnit(retVal.elapsedMilliseconds, avgUnit);
  retVal.avgPerAvgUnit = amount ? Math.round(amount / retVal.elapsedInAvgUnit) : null;
  return retVal;
};

const elapsedTimeCalculationsToString = (calc) => {
  const avgPerSecondPart = calc.avgPerAvgUnit ? ` (${calc.avgPerAvgUnit}/${calc.avgUnit})` : '';
  return `${Math.round(calc.elapsedInUnit * 100) / 100}${calc.unit}${avgPerSecondPart}`;
};

/**
 *
 * @param {Date} startDate
 * @param {String} unit can be ms, s, m, h, d
 * @param {Number} amount [optional] if present will add avg per second/minute/hour
 * @param {String} avgUnit [optional] if not set, same unit as above, but you can make it avg per m, h, d, ... if you want
 */
const elapsedTimeString = (startDate, unit = 'ms', amount = false, avgUnit = false, endDate = Date.now()) => {
  const calc = elapsedTimeCalculations(startDate, unit, amount, avgUnit, endDate);
  return elapsedTimeCalculationsToString(calc);
};

module.exports = {
  removeDollarFields,
  hashCode,
  fixResourceForStoring,
  setExpandOnPath,
  msToOtherUnit,
  elapsedTimeCalculations,
  elapsedTimeCalculationsToString,
  elapsedTimeString,
}<commit_msg>required missing lodash.clonedeep in utils.js<commit_after>/** **********************
 *   HELPER FUNCTIONS    *
 *********************** */

const clonedeep = require('lodash.clonedeep');

const removeDollarFields = (obj) => {
  Object.keys(obj).forEach((property) => {
    if (property.startsWith('$$') && property != '$$meta') {
      delete obj[property];
    } else if (obj.property !== null && typeof obj.property === 'object') {
      removeDollarFields(obj[property]);
    }
  });
  return obj;
};

/**
 * Helper function to compute a hash code from a string as found here:
 *  https://stackoverflow.com/a/7616484
 */
function hashCode(theString) {
  let hash = 0;
  let chr;
  if (theString.length === 0) return hash;
  for (let i = 0; i < theString.length; i++) {
    chr = theString.charCodeAt(i);
    hash = ((hash << 5) - hash) + chr;
    // eslint-disable-next-line no-bitwise
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
}

/**
 * This function will make a few fixes to old api's that weren't fully compliant
 * to make sure the assumptions we make later on in the code will be valid.
 *
 * For example:
 *  * if a resource doesn't have a key, then we generate a key from the permalink
 *  * if a resource doesn't have $$meta.modified, then we'll add a default date in there
 *
 * @param {object} r
 */
function fixResourceForStoring(r) {
  if (r.$$meta && r.$$meta.modified && r.key) {
    return r;
  }
  retVal = clonedeep(r);
  if (!(r.$$meta && r.$$meta.modified)) {
    retVal.$$meta.modified = new Date().toISOString();
  }
  if (!r.key && r.$$meta && r.$$meta.permalink) {
    retVal.key = r.$$meta.permalink.substring(r.$$meta.permalink.lastIndexOf('/') + 1);
  }
  return retVal;
}

/**
 * Either adds expand= to the url or replaces the existing expand= with
 * the given expansion
 * @param {*} path
 * @param {*} expansion
 */
function setExpandOnPath(path, expansion) {
  if (path.includes('?') && path.includes('expand=')) {
    return path.replace(/expand=[^&$]*/, `expand=${expansion}`);
  }

  return `${path}${path.includes('?') ? '&' : '?'}expand=${expansion}`;
}

/**
 * @param {Number} nrOfMilliseconds
 * @param {String} unit can be ms, s, m, h, d
 */
const msToOtherUnit = (milliseconds, unit) => {
  let elapsedInUnit;
  switch (unit) {
    case 'ms': elapsedInUnit = milliseconds; break;
    case 's': elapsedInUnit = milliseconds / 1000; break;
    case 'm': elapsedInUnit = milliseconds / 1000 / 60; break;
    case 'h': elapsedInUnit = milliseconds / 1000 / 60 / 60; break;
    case 'd': elapsedInUnit = milliseconds / 1000 / 60 / 60 / 24; break;
    default: elapsedInUnit = milliseconds; break;
  }
  return elapsedInUnit;
};

/**
 * elapsedTimeCalculations calculates the elapsedMilliseconds given
 *
 * @param {Number} startDate obtained with a Date.now() call
 * @param {String} unit can be ms, s, m, h, d
 * @param {Number} amount [optional] if present will add avg per second/minute/hour
 * @param {String} avgUnit [optional] if not set, same unit as above, but you can make it avg per m, h, d, ... if you want
 * @param {Number} endDate [optional] obtained with a Date.now() call, if missing this function will do a Date.now() call for you
 */
/**
 *
 */
const elapsedTimeCalculations = (startDate, unit = 'ms', amount = false, avgUnit = false, endDate = Date.now()) => {
  // eslint-disable-next-line no-param-reassign
  if (!avgUnit) avgUnit = unit;
  const retVal = {
    unit, amount, avgUnit, startDate, endDate,
  };
  retVal.elapsedMilliseconds = (endDate - startDate);
  retVal.elapsedInUnit = msToOtherUnit(retVal.elapsedMilliseconds, unit);
  retVal.elapsedInAvgUnit = msToOtherUnit(retVal.elapsedMilliseconds, avgUnit);
  retVal.avgPerAvgUnit = amount ? Math.round(amount / retVal.elapsedInAvgUnit) : null;
  return retVal;
};

const elapsedTimeCalculationsToString = (calc) => {
  const avgPerSecondPart = calc.avgPerAvgUnit ? ` (${calc.avgPerAvgUnit}/${calc.avgUnit})` : '';
  return `${Math.round(calc.elapsedInUnit * 100) / 100}${calc.unit}${avgPerSecondPart}`;
};

/**
 *
 * @param {Date} startDate
 * @param {String} unit can be ms, s, m, h, d
 * @param {Number} amount [optional] if present will add avg per second/minute/hour
 * @param {String} avgUnit [optional] if not set, same unit as above, but you can make it avg per m, h, d, ... if you want
 */
const elapsedTimeString = (startDate, unit = 'ms', amount = false, avgUnit = false, endDate = Date.now()) => {
  const calc = elapsedTimeCalculations(startDate, unit, amount, avgUnit, endDate);
  return elapsedTimeCalculationsToString(calc);
};

module.exports = {
  removeDollarFields,
  hashCode,
  fixResourceForStoring,
  setExpandOnPath,
  msToOtherUnit,
  elapsedTimeCalculations,
  elapsedTimeCalculationsToString,
  elapsedTimeString,
}<|endoftext|>


<commit_before>/**
 *  Copyright (C) 2014 3D Repo Ltd
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Corresponds to repoNodeMesh in C++ definition of 3D Repo
var mongodb = require('mongodb');
var assert = require('assert');
var UUID = require('node-uuid');
var C = require('./constants');

exports.decode = function(bson, materials) {
    // There should be always only a single material with the mesh!
    // Takes the very first match if multiple materials attached as children.
    // Children are appended on the fly from other repository components.
    // If a single mesh is being decoded on it's own, it will not have the
	// children array attached!
	if (bson[C.REPO_NODE_LABEL_CHILDREN]) {
		for (var i = 0; i < bson[C.REPO_NODE_LABEL_CHILDREN].length; ++i) {
			var childIDbytes = bson[C.REPO_NODE_LABEL_CHILDREN][i][C.REPO_NODE_LABEL_ID].buffer;
			var childID = UUID.unparse(childIDbytes);
			var material = materials[childID];
			if (material) {
				// TODO: change mMaterialIndex to material
				bson[C.M_MATERIAL_INDEX] = childID;
				break;
			}
		}
	}

    var myUUID = bson["id"];

    if (bson[C.REPO_NODE_LABEL_COMBINED_MAP])
    {
        // TODO: Here we have multiple maps, including ones that
        // are no originally ours, let's hope we never have an example
        // of this.
        var myMap = bson[C.REPO_NODE_LABEL_COMBINED_MAP][myUUID];

        if (myUUID in bson[C.REPO_NODE_LABEL_COMBINED_MAP])
        {
            bson[C.REPO_NODE_LABEL_COMBINED_MAP] = bson[C.REPO_NODE_LABEL_COMBINED_MAP][myUUID];

            for(var i = 0; i < bson[C.REPO_NODE_LABEL_COMBINED_MAP].length; i++)
            {
                bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID] =
                    UUID.unparse(bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID].buffer);

                bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MATERIAL_ID] =
                    UUID.unparse(bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MATERIAL_ID].buffer);

				bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_OFFSET] =
					bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_FROM];
            }
        }

        delete bson[C.REPO_NODE_LABEL_COMBINED_MAP][myUUID];
    }

    /*
    if (bson[C.REPO_NODE_LABEL_VERTEX_MAP]) {
        bson[C.REPO_NODE_LABEL_COMBINED_MAP] = {};

        var vertexMapIDs = Object.keys(bson[C.REPO_NODE_LABEL_VERTEX_MAP][myUUID]);

        for (var i = 0; i < vertexMapIDs.length; ++i) {
            var currentVertObj = bson[C.REPO_NODE_LABEL_VERTEX_MAP][myUUID][vertexMapIDs[i]];
            var vertexMeshID = UUID.unparse(currentVertObj[C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID].buffer);

            if (!bson[C.REPO_NODE_LABEL_COMBINED_MAP][vertexMeshID])
                bson[C.REPO_NODE_LABEL_COMBINED_MAP][vertexMeshID] = [];

            var tmpMapObj = {};
            tmpMapObj[C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_FROM] = currentVertObj[C.REPO_NODE_LABEL_MERGE_MAP_FROM];
            tmpMapObj[C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_TO]   = currentVertObj[C.REPO_NODE_LABEL_MERGE_MAP_TO];

            bson[C.REPO_NODE_LABEL_COMBINED_MAP][vertexMeshID].push(tmpMapObj);
        }

        delete bson[C.REPO_NODE_LABEL_VERTEX_MAP];
    }

    if (bson[C.REPO_NODE_LABEL_TRIANGLE_MAP]) {
        var triangleMapIDs = Object.keys(bson[C.REPO_NODE_LABEL_TRIANGLE_MAP][myUUID]);

        for (var i = 0; i < triangleMapIDs.length; ++i) {
            var currentTriObj = bson[C.REPO_NODE_LABEL_TRIANGLE_MAP][myUUID][triangleMapIDs[i]];
            var triangleMeshID = UUID.unparse(currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID].buffer);
            var matchingVertexMap = {};

            if (!bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID])
            {
                console.log("No matching vertex map");
            } else {
                var offset = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_OFFSET];

                var numVertexMaps = bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID].length;
                var foundMatch = false;

                for(var v = 0; v < numVertexMaps; v++)
                {
                    //console.log(bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID]);

                    if (bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID][v][C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_FROM] == offset)
                    {
                        matchingVertexMap = bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID][v];
                        foundMatch = true;
                        break;
                    }
                }

                if (!foundMatch)
                {
                        matchingVertexMap = new Object();
                        bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID].push(matchingVertexMap);
                }
            }

            matchingVertexMap[C.REPO_NODE_LABEL_MERGE_MAP_TRIANGLE_FROM] = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_FROM];
            matchingVertexMap[C.REPO_NODE_LABEL_MERGE_MAP_TRIANGLE_TO]   = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_TO];
            matchingVertexMap[C.REPO_NODE_LABEL_MERGE_MAP_OFFSET]        = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_OFFSET];
        }

        delete bson[C.REPO_NODE_LABEL_TRIANGLE_MAP];
    }
    */

	return bson;
}

/**
 * Extracts the mesh's bounding box
 *
 * @param {Object} mesh
 */
exports.extractBoundingBox = function(mesh) {
    var bbox = {};

	if (mesh['bounding_box'])
	{
		bbox.min = mesh['bounding_box'][0];
		bbox.max = mesh['bounding_box'][1];
		bbox.center = [(bbox.min[0] + bbox.max[0]) / 2, (bbox.min[1] + bbox.max[1]) / 2, (bbox.min[2] + bbox.max[2]) / 2];
		bbox.size = [(bbox.max[0] - bbox.min[0]), (bbox.max[1] - bbox.min[1]), (bbox.max[2] - bbox.min[2])];
	} else {
		bbox.min    = [-1,-1,-1];
		bbox.max    = [ 1, 1, 1];
		bbox.center = [ 0, 0, 0];
		bbox.size   = [ 2, 2, 2];
	}

    return bbox;
}

/**
 * Expects a byte array where each offset bytes are integers.
 * Faces are stored as [n_0, i_{0,0}, i_{0,2}... , n_1, i{1,0}, i{1,1}...]
 *
 * @param {Object} facesBinaryObject
 * @param {Object} offset // 4 for 4 bytes in integer32
 * @param {boolean} isLittleEndian
 */
function toFaceArray(facesBinaryObject, offset, isLittleEndian) {
    var facesArray = new Array();
    // return variable, array of arrays of face indices
    var byteBuffer = toDataView(facesBinaryObject);

    // You do not know the number of faces up front as each can
    // have a different number of indices (ie triangle, polygon etc).
    var index = 0;
    while (index < facesBinaryObject.position) {
        // true for little Endianness
        var numberOfIndices = byteBuffer.getInt32(index, isLittleEndian);
        var lastFaceIndex = index + (numberOfIndices + 1) * offset;
        var face = new Array();
        for (index += offset; index < lastFaceIndex; index += offset) {
            face.push(byteBuffer.getInt32(index, isLittleEndian));
        }
        facesArray.push(face);
    }
    return facesArray;
}

/**
 * Transforms a byte object of aiVector3D (3 floats) into an array of vectors [x,y,z]
 *
 * @param {Object} binaryObject
 * @param {boolean} isLittleEndian
 * @return {Float32Array}
 */
function toFloat32Array(binaryObject, isLittleEndian) {
    var result = new Float32Array(binaryObject.position / Float32Array.BYTES_PER_ELEMENT);
    // array of floats [x,y,z ...], return variable
    var byteBuffer = toDataView(binaryObject);

    var count = 0,
        floatValue;
    for (var i = 0; i < binaryObject.position; i += Float32Array.BYTES_PER_ELEMENT) {
        floatValue = byteBuffer.getFloat32(i, isLittleEndian);
        result[count++] = floatValue;
    }
    return result;
}

/**
 * Returns an array of arrays of uv channels, where each channel
 * has 2 floats per vertex (there is vertices count pairs)
 *
 * @param {Object} binaryObject
 * @param {number} channelsCount Number of channels, 1 for now
 * @param {boolean} isLittleEndian True or false
 * @return {Array.<Float32Array>}
 */
function toUVChannelsArray(binaryObject, channelsCount, isLittleEndian) {
    var uvChannelsArray = new Array(channelsCount);

    var byteBuffer = toDataView(binaryObject);
    var channelBytesCount = binaryObject.position / channelsCount;

    for (var i = 0; i < channelsCount; ++i) {
        var channel = new Float32Array(channelBytesCount / Float32Array.BYTES_PER_ELEMENT);
        var offset = i * channelBytesCount;
        var count = 0,
            floatValue;
        for (var j = 0; j < channelBytesCount; j += Float32Array.BYTES_PER_ELEMENT) {
            floatValue = byteBuffer.getFloat32(offset + j, isLittleEndian);
            channel[count++] = floatValue;
        }
        uvChannelsArray[i] = channel;
    }
    return uvChannelsArray;
}

/**
 * Returns a DataView out of a given BSON binary object (BinDataGeneral).
 * See also: http://www.html5rocks.com/en/tutorials/webgl/typed_arrays/
 *
 * @param {BinDataGeneral} binary object
 */
function toDataView(binaryObject) {
    return new DataView(toArrayBuffer(binaryObject.buffer));
}

/**
 * Returns an ArrayBuffer from a binary buffer. This can
 * be used to create a DataView from it.
 * See: http://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer
 *
 * @param {Buffer} binary buffer
 */
function toArrayBuffer(binaryBuffer) {
    var arrayBuffer = new ArrayBuffer(binaryBuffer.length);
    var view = new Uint8Array(arrayBuffer);
    for (var i = 0; i < binaryBuffer.length; ++i) {
        view[i] = binaryBuffer[i];
    }
    return arrayBuffer;
}

/*
*/
<commit_msg>MASTER - Replace vertices_count<commit_after>/**
 *  Copyright (C) 2014 3D Repo Ltd
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Corresponds to repoNodeMesh in C++ definition of 3D Repo
var mongodb = require('mongodb');
var assert = require('assert');
var UUID = require('node-uuid');
var C = require('./constants');

exports.decode = function(bson, materials) {
    // There should be always only a single material with the mesh!
    // Takes the very first match if multiple materials attached as children.
    // Children are appended on the fly from other repository components.
    // If a single mesh is being decoded on it's own, it will not have the
	// children array attached!
	if (bson[C.REPO_NODE_LABEL_CHILDREN]) {
		for (var i = 0; i < bson[C.REPO_NODE_LABEL_CHILDREN].length; ++i) {
			var childIDbytes = bson[C.REPO_NODE_LABEL_CHILDREN][i][C.REPO_NODE_LABEL_ID].buffer;
			var childID = UUID.unparse(childIDbytes);
			var material = materials[childID];
			if (material) {
				// TODO: change mMaterialIndex to material
				bson[C.M_MATERIAL_INDEX] = childID;
				break;
			}
		}
	}

    var myUUID = bson["id"];

    if (bson[C.REPO_NODE_LABEL_COMBINED_MAP])
    {
        // TODO: Here we have multiple maps, including ones that
        // are no originally ours, let's hope we never have an example
        // of this.
        var myMap = bson[C.REPO_NODE_LABEL_COMBINED_MAP][myUUID];

        if (myUUID in bson[C.REPO_NODE_LABEL_COMBINED_MAP])
        {
            bson[C.REPO_NODE_LABEL_COMBINED_MAP] = bson[C.REPO_NODE_LABEL_COMBINED_MAP][myUUID];

            for(var i = 0; i < bson[C.REPO_NODE_LABEL_COMBINED_MAP].length; i++)
            {
                bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID] =
                    UUID.unparse(bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID].buffer);

                bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MATERIAL_ID] =
                    UUID.unparse(bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_MATERIAL_ID].buffer);

				bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_OFFSET] =
					bson[C.REPO_NODE_LABEL_COMBINED_MAP][i][C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_FROM];
            }
        }

        delete bson[C.REPO_NODE_LABEL_COMBINED_MAP][myUUID];
    }

    if (bson.vertices && bson.vertices.buffer)
    {
        bson.vertices_count = bson.vertices.buffer.length / 12;
    }

    /*
    if (bson[C.REPO_NODE_LABEL_VERTEX_MAP]) {
        bson[C.REPO_NODE_LABEL_COMBINED_MAP] = {};

        var vertexMapIDs = Object.keys(bson[C.REPO_NODE_LABEL_VERTEX_MAP][myUUID]);

        for (var i = 0; i < vertexMapIDs.length; ++i) {
            var currentVertObj = bson[C.REPO_NODE_LABEL_VERTEX_MAP][myUUID][vertexMapIDs[i]];
            var vertexMeshID = UUID.unparse(currentVertObj[C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID].buffer);

            if (!bson[C.REPO_NODE_LABEL_COMBINED_MAP][vertexMeshID])
                bson[C.REPO_NODE_LABEL_COMBINED_MAP][vertexMeshID] = [];

            var tmpMapObj = {};
            tmpMapObj[C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_FROM] = currentVertObj[C.REPO_NODE_LABEL_MERGE_MAP_FROM];
            tmpMapObj[C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_TO]   = currentVertObj[C.REPO_NODE_LABEL_MERGE_MAP_TO];

            bson[C.REPO_NODE_LABEL_COMBINED_MAP][vertexMeshID].push(tmpMapObj);
        }

        delete bson[C.REPO_NODE_LABEL_VERTEX_MAP];
    }

    if (bson[C.REPO_NODE_LABEL_TRIANGLE_MAP]) {
        var triangleMapIDs = Object.keys(bson[C.REPO_NODE_LABEL_TRIANGLE_MAP][myUUID]);

        for (var i = 0; i < triangleMapIDs.length; ++i) {
            var currentTriObj = bson[C.REPO_NODE_LABEL_TRIANGLE_MAP][myUUID][triangleMapIDs[i]];
            var triangleMeshID = UUID.unparse(currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_MESH_ID].buffer);
            var matchingVertexMap = {};

            if (!bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID])
            {
                console.log("No matching vertex map");
            } else {
                var offset = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_OFFSET];

                var numVertexMaps = bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID].length;
                var foundMatch = false;

                for(var v = 0; v < numVertexMaps; v++)
                {
                    //console.log(bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID]);

                    if (bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID][v][C.REPO_NODE_LABEL_MERGE_MAP_VERTEX_FROM] == offset)
                    {
                        matchingVertexMap = bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID][v];
                        foundMatch = true;
                        break;
                    }
                }

                if (!foundMatch)
                {
                        matchingVertexMap = new Object();
                        bson[C.REPO_NODE_LABEL_COMBINED_MAP][triangleMeshID].push(matchingVertexMap);
                }
            }

            matchingVertexMap[C.REPO_NODE_LABEL_MERGE_MAP_TRIANGLE_FROM] = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_FROM];
            matchingVertexMap[C.REPO_NODE_LABEL_MERGE_MAP_TRIANGLE_TO]   = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_TO];
            matchingVertexMap[C.REPO_NODE_LABEL_MERGE_MAP_OFFSET]        = currentTriObj[C.REPO_NODE_LABEL_MERGE_MAP_OFFSET];
        }

        delete bson[C.REPO_NODE_LABEL_TRIANGLE_MAP];
    }
    */

	return bson;
}

/**
 * Extracts the mesh's bounding box
 *
 * @param {Object} mesh
 */
exports.extractBoundingBox = function(mesh) {
    var bbox = {};

	if (mesh['bounding_box'])
	{
		bbox.min = mesh['bounding_box'][0];
		bbox.max = mesh['bounding_box'][1];
		bbox.center = [(bbox.min[0] + bbox.max[0]) / 2, (bbox.min[1] + bbox.max[1]) / 2, (bbox.min[2] + bbox.max[2]) / 2];
		bbox.size = [(bbox.max[0] - bbox.min[0]), (bbox.max[1] - bbox.min[1]), (bbox.max[2] - bbox.min[2])];
	} else {
		bbox.min    = [-1,-1,-1];
		bbox.max    = [ 1, 1, 1];
		bbox.center = [ 0, 0, 0];
		bbox.size   = [ 2, 2, 2];
	}

    return bbox;
}

/**
 * Expects a byte array where each offset bytes are integers.
 * Faces are stored as [n_0, i_{0,0}, i_{0,2}... , n_1, i{1,0}, i{1,1}...]
 *
 * @param {Object} facesBinaryObject
 * @param {Object} offset // 4 for 4 bytes in integer32
 * @param {boolean} isLittleEndian
 */
function toFaceArray(facesBinaryObject, offset, isLittleEndian) {
    var facesArray = new Array();
    // return variable, array of arrays of face indices
    var byteBuffer = toDataView(facesBinaryObject);

    // You do not know the number of faces up front as each can
    // have a different number of indices (ie triangle, polygon etc).
    var index = 0;
    while (index < facesBinaryObject.position) {
        // true for little Endianness
        var numberOfIndices = byteBuffer.getInt32(index, isLittleEndian);
        var lastFaceIndex = index + (numberOfIndices + 1) * offset;
        var face = new Array();
        for (index += offset; index < lastFaceIndex; index += offset) {
            face.push(byteBuffer.getInt32(index, isLittleEndian));
        }
        facesArray.push(face);
    }
    return facesArray;
}

/**
 * Transforms a byte object of aiVector3D (3 floats) into an array of vectors [x,y,z]
 *
 * @param {Object} binaryObject
 * @param {boolean} isLittleEndian
 * @return {Float32Array}
 */
function toFloat32Array(binaryObject, isLittleEndian) {
    var result = new Float32Array(binaryObject.position / Float32Array.BYTES_PER_ELEMENT);
    // array of floats [x,y,z ...], return variable
    var byteBuffer = toDataView(binaryObject);

    var count = 0,
        floatValue;
    for (var i = 0; i < binaryObject.position; i += Float32Array.BYTES_PER_ELEMENT) {
        floatValue = byteBuffer.getFloat32(i, isLittleEndian);
        result[count++] = floatValue;
    }
    return result;
}

/**
 * Returns an array of arrays of uv channels, where each channel
 * has 2 floats per vertex (there is vertices count pairs)
 *
 * @param {Object} binaryObject
 * @param {number} channelsCount Number of channels, 1 for now
 * @param {boolean} isLittleEndian True or false
 * @return {Array.<Float32Array>}
 */
function toUVChannelsArray(binaryObject, channelsCount, isLittleEndian) {
    var uvChannelsArray = new Array(channelsCount);

    var byteBuffer = toDataView(binaryObject);
    var channelBytesCount = binaryObject.position / channelsCount;

    for (var i = 0; i < channelsCount; ++i) {
        var channel = new Float32Array(channelBytesCount / Float32Array.BYTES_PER_ELEMENT);
        var offset = i * channelBytesCount;
        var count = 0,
            floatValue;
        for (var j = 0; j < channelBytesCount; j += Float32Array.BYTES_PER_ELEMENT) {
            floatValue = byteBuffer.getFloat32(offset + j, isLittleEndian);
            channel[count++] = floatValue;
        }
        uvChannelsArray[i] = channel;
    }
    return uvChannelsArray;
}

/**
 * Returns a DataView out of a given BSON binary object (BinDataGeneral).
 * See also: http://www.html5rocks.com/en/tutorials/webgl/typed_arrays/
 *
 * @param {BinDataGeneral} binary object
 */
function toDataView(binaryObject) {
    return new DataView(toArrayBuffer(binaryObject.buffer));
}

/**
 * Returns an ArrayBuffer from a binary buffer. This can
 * be used to create a DataView from it.
 * See: http://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer
 *
 * @param {Buffer} binary buffer
 */
function toArrayBuffer(binaryBuffer) {
    var arrayBuffer = new ArrayBuffer(binaryBuffer.length);
    var view = new Uint8Array(arrayBuffer);
    for (var i = 0; i < binaryBuffer.length; ++i) {
        view[i] = binaryBuffer[i];
    }
    return arrayBuffer;
}

/*
*/
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const { exec, spawn } = require('child_process');
const { BrowserWindow } = require('electron');

const simulator = root => {
  const WIDTH = 800;
  const HEIGHT = 600;
  //Deserialize project info from projInfo file, contains path to index.html and presence of webpack among other things
  // const projInfo = JSON.parse(fs.readFileSync(path.join(__dirname, '../lib/projInfo.js')));

  console.log('process', process.env)

  let child = spawn(
    // '/Users/jyamamoto/.nvm/versions/node/v8.1.3/bin/npm',
    'npm',
    ['start'],

    {
      cwd: '/Users/jyamamoto/_personal/Fermionjs/app/export_files',
      stdio: 'inherit',
      env: process.env
    }

  )
  console.log('process', process.env)
  setTimeout(()=>{
      let child = new BrowserWindow({
        width: WIDTH,
        height: HEIGHT
      });
      // child.loadURL('http://google.com');
      child.loadURL('http://localhost:8080/');
      child.toggleDevTools();
    }, 5000)

  //Dynamic simulation
  // if (projInfo.hotLoad) {
  console.log('hello')
  // 'npm start'
  //  'touch /Users/jyamamoto/hello_hai',
  // let child = exec(
  //   // 'npm start',
  //   'touch /Users/jyamamoto/hello_hai',
  //   {
  //     cwd: '/Users/jyamamoto/_personal/Fermionjs/app/export_files'
  //     // cwd:projInfo.rootPath
  //   },
  //   (err, stdout, stderr) => {
  //     console.log(err)
  //     console.log(stdout)
  //     console.log(stderr)
  //     let child = new BrowserWindow({
  //       width: WIDTH,
  //       height: HEIGHT
  //     });
  //     // child.loadURL('http://google.com');
  //     child.loadURL('http://localhost:8080/');
  //     child.toggleDevTools();
  //   }

  // );
  //  else if (projInfo.webpack) {
  //   let child = exec(
  //     'webpack',
  //     {
  //       cwd: projInfo.rootPath,
  //       shell: '/bin/bash'
  //     },
  //     (err, stdout, stderr) => {
  //       let child = new BrowserWindow({
  //         width: WIDTH,
  //         height: HEIGHT
  //       });
  //       child.loadURL('file://' + projInfo.htmlPath);
  //       child.toggleDevTools();
  //     }
  //   );
  // } else if (projInfo.htmlPath) {
  //   let child = new BrowserWindow({
  //     width: WIDTH,
  //     height: HEIGHT
  //   });
  //   child.loadURL('file://' + projInfo.htmlPath);
  //   child.toggleDevTools();
  // } else {
  //   console.log('No Index.html found');
  // }
};

module.exports = simulator;
<commit_msg>Remove comments<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const { BrowserWindow } = require('electron');

const simulator = root => {
  const WIDTH = 800;
  const HEIGHT = 600;
  //Deserialize project info from projInfo file, contains path to index.html and presence of webpack among other things
  // const projInfo = JSON.parse(fs.readFileSync(path.join(__dirname, '../lib/projInfo.js')));

  let child = spawn(
    'npm',
    ['start'],
    {
      cwd: '/Users/jyamamoto/_personal/Fermionjs/app/export_files',
      stdio: 'inherit',
      env: process.env
    }
  )
  setTimeout(()=>{
      let child = new BrowserWindow({
        width: WIDTH,
        height: HEIGHT
      });
      child.loadURL('http://localhost:8080/');
      child.toggleDevTools();
    }, 5000)
};

module.exports = simulator;
<|endoftext|>


<commit_before>
var dataset3 = {"DATA":{"OBJSTATUS":[{"OBJID":"100","VALUE":10,"STATUS":"PASSED"},{"OBJID":"101","VALUE":20,"STATUS":"FAILED"},{"OBJID":"102","VALUE":15,"STATUS":"PASSED"}],"OBJDATA":[{"OBJID":"100","OBJNAME":"Module name1","VALUE":10,"UNIT":"HOURS","STATUS":"RANDOM"},{"OBJID":"101","OBJNAME":"Module name2","VALUE":20,"UNIT":"HOURS","STATUS":"RANDOM"},{"OBJID":"102","OBJNAME":"Module name3","VALUE":15,"UNIT":"HOURS","STATUS":"RANDOM"}],"INSTRUCTORDATA":[{"OBJID":"100","VALUE":50},{"OBJID":"101","VALUE":10},{"OBJID":"102","VALUE":60}],"GROUPDATA":[{"OBJID":"100","VALUE":150},{"OBJID":"101","VALUE":100},{"OBJID":"102","VALUE":150}]},"TOTALTIMESPENT":"1000"};

var dataset4 = {"DATA":{"OBJSTATUS":[{"OBJID":"100","VALUE":100,"STATUS":"PASSED"},{"OBJID":"101","VALUE":800,"STATUS":"FAILED"},{"OBJID":"102","VALUE":200,"STATUS":"PASSED"}],"OBJDATA":[{"OBJID":"100","OBJNAME":"Goal name1","VALUE":100,"STATUS":"RANDOM"},{"OBJID":"101","OBJNAME":"Goal name2","VALUE":800,"STATUS":"RANDOM"},{"OBJID":"102","OBJNAME":"Goal name3","VALUE":200,"STATUS":"RANDOM"}],"INSTRUCTORDATA":[{"OBJID":"100","VALUE":150},{"OBJID":"101","VALUE":10},{"OBJID":"102","VALUE":50}],"GROUPDATA":[{"OBJID":"100","VALUE":500},{"OBJID":"101","VALUE":85},{"OBJID":"102","VALUE":258}]},"TOTALTIMESPENT":"1000","UNIT":"HOUR"};

var clicked_arc_color, clicked_arc;
/*The functin that helps to generate multi layered donet chart, onclick of any of the arc will pop up with sub sections */
function generateMultilayerDonet(data, chartID, timesepent, label){
  var dataset = data.DATA;
  var arcSection;
  var width = 500,
  height = 500,
  outerRadius = height / 2,
  innerRadius = height/6;

var maxValue = getMaxValue(dataset);
var status_color = {'PASSED':'#83c446','FAILED':'#ff5722','skipped':'#ffc107','incomplete':'#f26261','complete':'#009900'};
var colors = d3.scale.category20();
var pie = d3.layout.pie()
    .padAngle(.02)
    .value(function(d) { return d.VALUE; })
    .sort(null);

var arc = d3.svg.arc();

var endAngleScale = d3.scale.linear()
          .domain([0, maxValue+230])
          .range([0, 2 * Math.PI]);

var svg = d3.select('#'+chartID).append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(" +  width / 2 + "," + height / 2 + ")")
        .attr("class", "labels");

var gs = svg.selectAll("g")
        .data(d3.values(dataset))
        .enter()
        .append("g")
        .attr("class", function(d,i,j){
          var arcGrpType;
          if(i==0){
            arcGrpType= chartID+'_arc_inner';
          } else if(i == 1){
            arcGrpType= chartID+'_arc_outer';
          }
          return arcGrpType;
        });

var path = gs.selectAll("path")
    .data(function(d) {return pie(d); })
    .enter().append("path")
    .attr("fill", function(d, i) {
      if(d.data.STATUS=='RANDOM'){
        return colors(i);
      } else {
        return status_color[d.data.STATUS];
      }
     })
    .attr("section", function(d,i,j){
      if(j==0){
        return "inner_"+d.data.OBJID;
      } else if(j==1) {
        return "outer_"+d.data.OBJID;
      }
    })
    .attr("arcsection", function(d,i){
      return d.data.OBJID;
    })
    .attr("name", function(d,i,j){
      if(j==1){
        return d.data.OBJNAME;
      }
    })
    .attr("value", function(d,i,j){
      if(j==1){
        return d.data.VALUE;
      }
    })
    .attr("class", function(d,i,j){
      if(j==0){
        return chartID+"_arc_section_"+d.data.OBJID+"_inner";
      }else if(j==1){
        return chartID+"_arc_section_"+d.data.OBJID;
      }
    })
    .attr("d", function(d, i, j) {
      var angle
      if(j==0){
        angle = arc.innerRadius(innerRadius+(10*j)).outerRadius(innerRadius+5+(5*j))(d);
      }else if(j==1) {
        angle = arc.innerRadius(innerRadius+(7*j)).outerRadius(innerRadius+22+(22*j))(d);
      }
      return angle;
    });

// Time spent inner text append
svg.append("text")
      .attr("dy", "-0.95em")
      .style("text-anchor", "middle")
      .attr("class", "arcInnerTitle")
      .text(function(d) { return 'Total Time Spent'; });

// Time inner text append
svg.append("text")
      .attr("dy", ".35em")
      .attr("id", chartID+"TimeSpentText")
      .style("text-anchor", "middle")
      .attr("class", "timeSpent")
      .text(timesepent);
// Day/Hour title append
svg.append("text")
      .attr("dy", "2.0em")
      .style("text-anchor", "middle")
      .attr("class", "timeSpentUnit")
      .text(function(d) { return 'DAYS HOUR'; });
// Course name/Module name arc inner text
svg.append("text")
      .attr("dy", "3em")
      .attr('id',chartID+'InnerText')
      .style("text-anchor", "middle")
      .attr("class", "arcLabel")
      .text(label);

// On click of any portion of the arc to append arc with two layer outer arc
    path.on('click',function(d){
      var sAngle = d.startAngle, eAngle = d.endAngle, outer_arc2, outer_arc3;
      outer_arc2 = getOuterArcValue(dataset.INSTRUCTORDATA, $(this).attr('arcsection'));
      outer_arc3 = getOuterArcValue(dataset.GROUPDATA, $(this).attr('arcsection'));
      clicked_arc_color = $(this).attr('fill');
      clicked_arc = $(this).attr('class');
      var timeSpentValue = $(this).attr('value');
      var arcName= $(this).attr('name');
      var classType = $(this).attr('class');
      $(this).attr('fill','#f26261');
      if(chartID == 'moduleLevel_Donet'){
        $('.moduleLevel_Donet_arc_inner').children().not('.'+classType+"_inner").css('opacity','0.2');
        $('.moduleLevel_Donet_arc_outer').children().not('.'+classType).css('opacity','0.2');
        gs.append("path")
          .attr("fill", function(d) { return "#fed006";})
          .attr("class",chartID+"_arcPath_outer1")
          .attr("d", function(d) {
          var arcHover = d3.svg.arc()
            .innerRadius(innerRadius+(23*2))
            .outerRadius(innerRadius+25+(25*2))
            .startAngle(sAngle)
            .endAngle(sAngle+endAngleScale(outer_arc2))
            return arcHover();
          });

        gs.append("path")
          .attr("fill", function(d) { return "#41bdc0";})
          .attr("class",chartID+"_arcPath_outer1")
          .attr("d", function(d) {
          var arcHover = d3.svg.arc()
            .innerRadius(innerRadius+(37*2))
            .outerRadius(innerRadius+35+(35*2))
            .startAngle(sAngle)
            .endAngle(sAngle+endAngleScale(outer_arc3))
            return arcHover();
        });
        $('#goalLevel_Donet').empty();
        $('#moduleLevel_DonetInnerText').html(arcName);
        $('#moduleLevel_DonetTimeSpentText').html(timeSpentValue);
      }
      })
  }
generateMultilayerDonet(dataset4,'moduleLevel_Donet','00 00','Welcome Text');

// To get outer arc value based on section
function getOuterArcValue(dataItem, itemForCheck){
  var arcVal = 0;
  dataItem.forEach(function(d){if(d.OBJID == itemForCheck){ arcVal = d.VALUE;}});
  return arcVal;
}
// To get higest value from the given data
function getMaxValue(dataset){
  var maxValueArray = new Array();
  maxValueArray.push(Math.max.apply(Math, dataset.OBJSTATUS.map(function(o){return o.VALUE;})));
  maxValueArray.push(Math.max.apply(Math, dataset.OBJDATA.map(function(o){return o.VALUE;})));
  maxValueArray.push(Math.max.apply(Math, dataset.INSTRUCTORDATA.map(function(o){return o.VALUE;})));
  maxValueArray.push(Math.max.apply(Math, dataset.GROUPDATA.map(function(o){return o.VALUE;})));
  maxValue=Math.max.apply(Math, maxValueArray.map(function(o){return o;}))
  return maxValue;
}
// to deselect the item on outside of the chart using mouse up event
$('body').mouseup(function(e) {
  $('.'+clicked_arc).attr('fill', clicked_arc_color);
  $('path').css('opacity','1')
  $('.moduleLevel_Donet_arcPath_outer1').css('visibility','hidden');
  $('.goalLevel_Donet_arcPath_outer1').css('visibility','hidden');
})
<commit_msg>transition effect added<commit_after>
var dataset3 = {"DATA":{"OBJSTATUS":[{"OBJID":"100","VALUE":10,"STATUS":"PASSED"},{"OBJID":"101","VALUE":20,"STATUS":"FAILED"},{"OBJID":"102","VALUE":15,"STATUS":"PASSED"}],"OBJDATA":[{"OBJID":"100","OBJNAME":"Module name1","VALUE":10,"UNIT":"HOURS","STATUS":"RANDOM"},{"OBJID":"101","OBJNAME":"Module name2","VALUE":20,"UNIT":"HOURS","STATUS":"RANDOM"},{"OBJID":"102","OBJNAME":"Module name3","VALUE":15,"UNIT":"HOURS","STATUS":"RANDOM"}],"INSTRUCTORDATA":[{"OBJID":"100","VALUE":50},{"OBJID":"101","VALUE":10},{"OBJID":"102","VALUE":60}],"GROUPDATA":[{"OBJID":"100","VALUE":150},{"OBJID":"101","VALUE":100},{"OBJID":"102","VALUE":150}]},"TOTALTIMESPENT":"1000"};

var dataset4 = {"DATA":{"OBJSTATUS":[{"OBJID":"100","VALUE":100,"STATUS":"PASSED"},{"OBJID":"101","VALUE":800,"STATUS":"FAILED"},{"OBJID":"102","VALUE":200,"STATUS":"PASSED"}],"OBJDATA":[{"OBJID":"100","OBJNAME":"Goal name1","VALUE":100,"STATUS":"RANDOM"},{"OBJID":"101","OBJNAME":"Goal name2","VALUE":800,"STATUS":"RANDOM"},{"OBJID":"102","OBJNAME":"Goal name3","VALUE":200,"STATUS":"RANDOM"}],"INSTRUCTORDATA":[{"OBJID":"100","VALUE":150},{"OBJID":"101","VALUE":10},{"OBJID":"102","VALUE":50}],"GROUPDATA":[{"OBJID":"100","VALUE":500},{"OBJID":"101","VALUE":85},{"OBJID":"102","VALUE":258}]},"TOTALTIMESPENT":"1000","UNIT":"HOUR"};

var clicked_arc_color, clicked_arc;
/*The functin that helps to generate multi layered donet chart, onclick of any of the arc will pop up with sub sections */
function generateMultilayerDonet(data, chartID, timesepent, label){
  var dataset = data.DATA;
  var arcSection;
  var width = 500,
  height = 500,
  outerRadius = height / 2,
  innerRadius = height/6;

var maxValue = getMaxValue(dataset);
var status_color = {'PASSED':'#83c446','FAILED':'#ff5722','skipped':'#ffc107','incomplete':'#f26261','complete':'#009900'};
var colors = d3.scale.category20();
var pie = d3.layout.pie()
    .padAngle(.02)
    .value(function(d) { return d.VALUE; })
    .sort(null);

var arc = d3.svg.arc();

var endAngleScale = d3.scale.linear()
          .domain([0, maxValue+230])
          .range([0, 2 * Math.PI]);

var svg = d3.select('#'+chartID).append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(" +  width / 2 + "," + height / 2 + ")")
        .attr("class", "labels");

var gs = svg.selectAll("g")
        .data(d3.values(dataset))
        .enter()
        .append("g")
        .attr("class", function(d,i,j){
          var arcGrpType;
          if(i==0){
            arcGrpType= chartID+'_arc_inner';
          } else if(i == 1){
            arcGrpType= chartID+'_arc_outer';
          }
          return arcGrpType;
        });

var jV=0;
var path = gs.selectAll("path")
    .data(function(d) {return pie(d); })
    .enter().append("path")
    .attr("fill", function(d, i) {
      if(d.data.STATUS=='RANDOM'){
        return colors(i);
      } else {
        return status_color[d.data.STATUS];
      }
     })
    .attr("section", function(d,i,j){
      if(j==0){
        return "inner_"+d.data.OBJID;
      } else if(j==1) {
        return "outer_"+d.data.OBJID;
      }
    })
    .attr("arcsection", function(d,i){
      return d.data.OBJID;
    })
    .attr("name", function(d,i,j){
      if(j==1){
        return d.data.OBJNAME;
      }
    })
    .attr("value", function(d,i,j){
      if(j==1){
        return d.data.VALUE;
      }
    })
    .attr("class", function(d,i,j){
      if(j==0){
        return chartID+"_arc_section_"+d.data.OBJID+"_inner";
      }else if(j==1){
        return chartID+"_arc_section_"+d.data.OBJID;
      }
    })
/*    .attr("d", function(d, i, j) {
      var angle
      if(j==0){
        angle = arc.innerRadius(innerRadius+(10*j)).outerRadius(innerRadius+5+(5*j))(d);
      }else if(j==1) {
        angle = arc.innerRadius(innerRadius+(7*j)).outerRadius(innerRadius+22+(22*j))(d);
      }
      return angle;
    });*/
    .transition()
    .duration(1000)
    .attrTween("d", function(d, i, j){
      if(i==0){
        jV = jV+1;
      }
      var start = {startAngle: 0,endAngle: 0};
      var ip = d3.interpolate(start, d);
      if((jV-1)==0){
        return function(d) { return arc.innerRadius(innerRadius+(5*(jV-1))).outerRadius(innerRadius+5+(5*(jV-1)))(ip(d)) };
      }else if((jV-1)==1) {
        return function(d) { return arc.innerRadius(innerRadius+(7*(jV-1))).outerRadius(innerRadius+15+(15*(jV-1)))(ip(d)); };
      }
    })

// Time spent inner text append
svg.append("text")
      .attr("dy", "-0.95em")
      .style("text-anchor", "middle")
      .attr("class", "arcInnerTitle")
      .text(function(d) { return 'Total Time Spent'; });

// Time inner text append
svg.append("text")
      .attr("dy", ".35em")
      .attr("id", chartID+"TimeSpentText")
      .style("text-anchor", "middle")
      .attr("class", "timeSpent")
      .text(timesepent);
// Day/Hour title append
svg.append("text")
      .attr("dy", "2.0em")
      .style("text-anchor", "middle")
      .attr("class", "timeSpentUnit")
      .text(function(d) { return 'DAYS HOUR'; });
// Course name/Module name arc inner text
svg.append("text")
      .attr("dy", "3em")
      .attr('id',chartID+'InnerText')
      .style("text-anchor", "middle")
      .attr("class", "arcLabel")
      .text(label);

// On click of any portion of the arc to append arc with two layer outer arc
    path.on('click',function(d){
      var sAngle = d.startAngle, eAngle = d.endAngle, outer_arc2, outer_arc3;
      outer_arc2 = getOuterArcValue(dataset.INSTRUCTORDATA, $(this).attr('arcsection'));
      outer_arc3 = getOuterArcValue(dataset.GROUPDATA, $(this).attr('arcsection'));
      clicked_arc_color = $(this).attr('fill');
      clicked_arc = $(this).attr('class');
      var timeSpentValue = $(this).attr('value');
      var arcName= $(this).attr('name');
      var classType = $(this).attr('class');
      $(this).attr('fill','#f26261');
      if(chartID == 'moduleLevel_Donet'){
        $('.moduleLevel_Donet_arc_inner').children().not('.'+classType+"_inner").css('opacity','0.2');
        $('.moduleLevel_Donet_arc_outer').children().not('.'+classType).css('opacity','0.2');
        gs.append("path")
          .attr("fill", function(d) { return "#fed006";})
          .attr("class",chartID+"_arcPath_outer1")
          .attr("d", function(d) {
          var arcHover = d3.svg.arc()
            .innerRadius(innerRadius+(23*2))
            .outerRadius(innerRadius+25+(25*2))
            .startAngle(sAngle)
            .endAngle(sAngle+endAngleScale(outer_arc2))
            return arcHover();
          });

        gs.append("path")
          .attr("fill", function(d) { return "#41bdc0";})
          .attr("class",chartID+"_arcPath_outer1")
          .attr("d", function(d) {
          var arcHover = d3.svg.arc()
            .innerRadius(innerRadius+(37*2))
            .outerRadius(innerRadius+35+(35*2))
            .startAngle(sAngle)
            .endAngle(sAngle+endAngleScale(outer_arc3))
            return arcHover();
        });
        $('#goalLevel_Donet').empty();
        $('#moduleLevel_DonetInnerText').html(arcName);
        $('#moduleLevel_DonetTimeSpentText').html(timeSpentValue);
      }
      })
  }
generateMultilayerDonet(dataset4,'moduleLevel_Donet','00 00','Welcome Text');

// To get outer arc value based on section
function getOuterArcValue(dataItem, itemForCheck){
  var arcVal = 0;
  dataItem.forEach(function(d){if(d.OBJID == itemForCheck){ arcVal = d.VALUE;}});
  return arcVal;
}
// To get higest value from the given data
function getMaxValue(dataset){
  var maxValueArray = new Array();
  maxValueArray.push(Math.max.apply(Math, dataset.OBJSTATUS.map(function(o){return o.VALUE;})));
  maxValueArray.push(Math.max.apply(Math, dataset.OBJDATA.map(function(o){return o.VALUE;})));
  maxValueArray.push(Math.max.apply(Math, dataset.INSTRUCTORDATA.map(function(o){return o.VALUE;})));
  maxValueArray.push(Math.max.apply(Math, dataset.GROUPDATA.map(function(o){return o.VALUE;})));
  maxValue=Math.max.apply(Math, maxValueArray.map(function(o){return o;}))
  return maxValue;
}
// to deselect the item on outside of the chart using mouse up event
$('body').mouseup(function(e) {
  $('.'+clicked_arc).attr('fill', clicked_arc_color);
  $('path').css('opacity','1')
  $('.moduleLevel_Donet_arcPath_outer1').css('visibility','hidden');
  $('.goalLevel_Donet_arcPath_outer1').css('visibility','hidden');
})
<|endoftext|>


<commit_before>// Инициализация класса
var Rtc = function(i2c) {
  this._time = undefined;
  this._i2c = i2c || PrimaryI2C;
  this._address = 0x68;
  this.start();
};

// Метод записывает данные data в регистр reg
Rtc.prototype.write = function(reg, data) {
  this._i2c.writeTo(this._address, [reg, data]);
};

// Метод производит чтение из регистра reg количестов байт count
Rtc.prototype.read = function(reg, count) {
  if (count === undefined) {
    count = 1;
  }
  this._i2c.writeTo(this._address, reg);
  return this._i2c.readFrom(this._address, count);
};

Rtc.prototype._decToBcd = function(val) {
  return Math.floor(val / 10) * 16 + (val % 10);
};

Rtc.prototype._bcdToDec = function(val) {
  return Math.floor(val / 16) * 10 + (val % 16);
};

Rtc.prototype._leadZero = function(val) {
  if (val < 10) {
    return '0'+val;
  } else {
    return ''+val;
  }
};

Rtc.prototype.setTime = function(time) {
  if (time instanceof Date) {
    this._time = time;
  } else if (time instanceof Object){
    this._time = new Date(
      time.year,
      time.month,
      time.day,
      time.hour,
      time.minute,
      time.second
    );
  } else if (typeof time === 'number') {
    this._time = new Date(time * 1000);
  } else if (typeof time === 'string') {
    this._time = new Date(Date.parse(time));
  } else {
    this._time = new Date(getTime()*1000);
  }

  var halt = this.read(0x00, 1)[0] >> 7;
  this.write(0x00, [
    this._decToBcd(this._time.getSeconds()) | (halt << 7),
    this._decToBcd(this._time.getMinutes()),
    this._decToBcd(this._time.getHours()),
    this._decToBcd(this._time.getDay() + 1),
    this._decToBcd(this._time.getDate()),
    this._decToBcd(this._time.getMonth() + 1),
    this._decToBcd(this._time.getFullYear() - 2000)
  ]);
};

Rtc.prototype.getTime = function(unit) {
  var time = this.read(0x00, 7);
  this._time = new Date(
    this._bcdToDec(time[6]) + 2000,
    this._bcdToDec(time[5]) - 1,
    this._bcdToDec(time[4]),
    this._bcdToDec(time[2] & 0x3f),
    this._bcdToDec(time[1]),
    this._bcdToDec(time[0] & 0x7f)
  );

  var res = this._time;
  switch (unit) {
    case 'unixtime':
      res = Math.ceil(res.getTime() / 1000);
      break;
    case 'iso':
      res = res.getFullYear() + '-' + this._leadZero(res.getMonth() + 1) +
         '-' + this._leadZero(res.getDate()) + 'T' + this._leadZero(res.getHours()) +
         ':' + this._leadZero(res.getMinutes()) + ':' + this._leadZero(res.getSeconds());
      break;
    default: break;
  }
  return res;
};

Rtc.prototype.start = function() {
  var byte = this.read(0x00, 1)[0];
  if (byte >> 7) {
    this.write(0x00, byte ^ 0x80);
  }
};

Rtc.prototype.stop = function() {
  var byte = this.read(0x00, 1)[0];
  if (byte >> 7 === 0) {
    this.write(0x00, byte ^ 0x80);
  }
};

// Экспортируем класс
exports.connect = function(i2c) {
  return new Rtc(i2c);
};
<commit_msg>object to Date fix<commit_after>// Инициализация класса
var Rtc = function(i2c) {
  this._time = undefined;
  this._i2c = i2c || PrimaryI2C;
  this._address = 0x68;
  this.start();
};

// Метод записывает данные data в регистр reg
Rtc.prototype.write = function(reg, data) {
  this._i2c.writeTo(this._address, [reg, data]);
};

// Метод производит чтение из регистра reg количестов байт count
Rtc.prototype.read = function(reg, count) {
  if (count === undefined) {
    count = 1;
  }
  this._i2c.writeTo(this._address, reg);
  return this._i2c.readFrom(this._address, count);
};

Rtc.prototype._decToBcd = function(val) {
  return Math.floor(val / 10) * 16 + (val % 10);
};

Rtc.prototype._bcdToDec = function(val) {
  return Math.floor(val / 16) * 10 + (val % 16);
};

Rtc.prototype._leadZero = function(val) {
  if (val < 10) {
    return '0'+val;
  } else {
    return ''+val;
  }
};

Rtc.prototype.setTime = function(time) {
  if (time instanceof Date) {
    this._time = time;
  } else if (time instanceof Object){
    this._time = new Date(
      time.year,
      time.month-1,
      time.day,
      time.hour,
      time.minute,
      time.second
    );
  } else if (typeof time === 'number') {
    this._time = new Date(time * 1000);
  } else if (typeof time === 'string') {
    this._time = new Date(Date.parse(time));
  } else {
    this._time = new Date(getTime()*1000);
  }

  var halt = this.read(0x00, 1)[0] >> 7;
  this.write(0x00, [
    this._decToBcd(this._time.getSeconds()) | (halt << 7),
    this._decToBcd(this._time.getMinutes()),
    this._decToBcd(this._time.getHours()),
    this._decToBcd(this._time.getDay() + 1),
    this._decToBcd(this._time.getDate()),
    this._decToBcd(this._time.getMonth() + 1),
    this._decToBcd(this._time.getFullYear() - 2000)
  ]);
};

Rtc.prototype.getTime = function(unit) {
  var time = this.read(0x00, 7);
  this._time = new Date(
    this._bcdToDec(time[6]) + 2000,
    this._bcdToDec(time[5]) - 1,
    this._bcdToDec(time[4]),
    this._bcdToDec(time[2] & 0x3f),
    this._bcdToDec(time[1]),
    this._bcdToDec(time[0] & 0x7f)
  );

  var res = this._time;
  switch (unit) {
    case 'unixtime':
      res = Math.ceil(res.getTime() / 1000);
      break;
    case 'iso':
      res = res.getFullYear() + '-' + this._leadZero(res.getMonth() + 1) +
         '-' + this._leadZero(res.getDate()) + 'T' + this._leadZero(res.getHours()) +
         ':' + this._leadZero(res.getMinutes()) + ':' + this._leadZero(res.getSeconds());
      break;
    default: break;
  }
  return res;
};

Rtc.prototype.start = function() {
  var byte = this.read(0x00, 1)[0];
  if (byte >> 7) {
    this.write(0x00, byte ^ 0x80);
  }
};

Rtc.prototype.stop = function() {
  var byte = this.read(0x00, 1)[0];
  if (byte >> 7 === 0) {
    this.write(0x00, byte ^ 0x80);
  }
};

// Экспортируем класс
exports.connect = function(i2c) {
  return new Rtc(i2c);
};
<|endoftext|>