<commit_before>/**
 * @license
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * https://developers.google.com/blockly/
 *
 * 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.
 */

/**
 * @fileoverview Helper functions for generating Kiwifroot plugins for blocks.
 * @author rani_sputnik@hotmail.com (Ryan Loader)
 */
'use strict';

goog.provide('Blockly.Kiwifroot');

goog.require('Blockly.JavaScript');
goog.require('Blockly.JavaScript.colour');
goog.require('Blockly.JavaScript.lists');
goog.require('Blockly.JavaScript.logic');
goog.require('Blockly.JavaScript.loops');
goog.require('Blockly.JavaScript.math');
goog.require('Blockly.JavaScript.procedures');
goog.require('Blockly.JavaScript.text');
goog.require('Blockly.JavaScript.variables');

/**
 * Kiwifroot code generator.
 * @type !Blockly.Generator
 */
Blockly.Kiwifroot = Blockly.JavaScript;

/**
 * The indent symbol used in code generation - we use tabs
 * @type {string}
 */
Blockly.Kiwifroot.INDENT = '\t';

/**
 * The default template to use when compiling for Kiwifroot
 * @const
 * @type {string}
 */
Blockly.Kiwifroot.defaultTemplate =
  // Define all the settings for the plugin (each new script is treated a component)
  'Kiwi.Plugins.[[PLUGIN_NAME]] = {\n'+
  '\tname:\'[[PLUGIN_NAME]]\',\n'+
  '\tversion:\'[[PLUGIN_VERSION]]\',\n'+
  '\tminimumKiwiVersion:\'[[MIN_KIWI_VERSION]]\',\n'+
  '\tkiwifrootPlugins:[[KIWIFROOT_PLUGINS]]\n'+
  '};\n\n'+
  // Register the plugin with Kiwi.js
  'Kiwi.PluginManager.register(Kiwi.Plugins.[[PLUGIN_NAME]]);\n\n'+

  // Here we define the constructor for the plugin
  'Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]] = function(gameObject){\n'+
  // Call the base component constructor
  '\tKiwi.Component.call(this, gameObject, \'[[PLUGIN_NAME]]\');\n\n'+
  // Set this components state property
  '\tthis.state = this.owner.state;\n\n'+
  // This is where the constructor additions will be made
  '{{\t,CONSTRUCTOR,\n}}\n'+
  '}\n\n' +
  // Extend GameObject
  'Kiwi.extend(Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]], Kiwi.Component);\n\n'+
  // Supply an add method for the plugin
  'Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]].add = function(state, gameObject, params){\n'+
  '\tgameObject.components.add(new Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]](gameObject));\n'+
  // TODO provide an 'on added' section
  '}\n\n'+
  // Add all the definitions here, they will all be prefixed with the namespace and
  // will include two newline breaks after each definition.
  '{{Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]].prototype.,DEFINITIONS,\n\n}}'+

  // Add the component to the list of plugins
  'Kiwi.Plugins.[[PLUGIN_NAME]].kiwifrootPlugins.push({\n'+
    '\ttype: Kiwifroot.Plugins.COMPONENT,\n'+
    '\tname: \'[[PLUGIN_NAME]]\',\n'+
    '\tnamespace: Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]]\n'+
  '});\n\n';

/**
 * The default macro properties to use when compiling for Kiwifroot
 * @const
 * @type {object}
 */
Blockly.Kiwifroot.defaultMacros = {
  'PLUGIN_NAME':'MyScript',
  'CLASS_NAME':'Component',
  'PLUGIN_VERSION':'0.5.0',
  'MIN_KIWI_VERSION':'1.1.1',
  'KIWIFROOT_PLUGINS':'[]'
};

/**
 * The constructor section of the template
 * @const
 * @type {string}
 */
Blockly.Kiwifroot.CONSTRUCTOR = 'CONSTRUCTOR';

/**
 * The definitions section of the template
 * @const
 * @type {string}
 */
Blockly.Kiwifroot.DEFINITIONS = 'DEFINITIONS';

/**
 * The array of sounds, contains tuples of names and ids
 * @type {array}
 */
Blockly.Kiwifroot.sounds_ = [
  ["Ammo","5"],
  ['Machine Gun',"11"]
];

Blockly.Kiwifroot.addReservedWords();

/**
 * Adds a new addition to the given section (spectified in the template)
 * @param {string} section The section to add the code to
 * @param {string} code The javascript to insert into the section
 */
Blockly.Kiwifroot.provideAddition = function(section,code){
  if (!Blockly.Kiwifroot.sections_[section]) {
    Blockly.Kiwifroot.sections_[section] = [];
  }
  Blockly.Kiwifroot.sections_[section].push(code);
};

/**
 * Adds a new addition provided an addition with the given uniqueId has not
 * already been added to the given section
 * @param {string} uniqueId The id that must be unique in order to make the addition
 * @param {string} section The section to add the code to
 * @param {string} code The javascript to insert into the section
 */
Blockly.Kiwifroot.provideAdditionOnce = function(uniqueId, section, code){
  if (!Blockly.Kiwifroot.sectionIds_[section]) {
    Blockly.Kiwifroot.sectionIds_[section] = [];
  }
  var arr = Blockly.Kiwifroot.sectionIds_[section];
  if (arr.indexOf(uniqueId) < 0) {
    arr.push(uniqueId);
    Blockly.Kiwifroot.provideAddition(section,code);
  }
};

/**
 * Sets the macros object that will be applied to the template
 * (Would prefer to send arguments to init but that would mean changing blockly.Generator)
 * @param {Object} macros The new macros object containing all the symbols to be applied to the template
 */
Blockly.Kiwifroot.setMacros = function(macros){
  Blockly.Kiwifroot.macros = macros;
};

/**
 * Sets the template to use when generating code
 * (Would prefer to send arguments to init but that would mean changing blockly.Generator)
 * @param {String} template The template to use, see Blockly.Kiwifroot.defaultTemplate for an example
 */
Blockly.Kiwifroot.setTemplate = function(template){
  Blockly.Kiwifroot.template = template;
};

/**
 * Initialise the database of variable names.
 * @param {!Blockly.Workspace} workspace Workspace to generate code from.
 */
Blockly.Kiwifroot.init = function(workspace) {
  // Create a dictionary of definitions to be printed before the code. (TODO remove)
  Blockly.Kiwifroot.definitions_ = Object.create(null);
  // Create a dictionary mapping desired function names in definitions_
  // to actual function names (to avoid collisions with user functions).
  Blockly.Kiwifroot.functionNames_ = Object.create(null);

  // The template to use to generate the code
  Blockly.Kiwifroot.template_ = Blockly.Kiwifroot.template || Blockly.Kiwifroot.defaultTemplate;
  // The macros to replace in the template
  Blockly.Kiwifroot.macros_ = Blockly.Kiwifroot.macros || Blockly.Kiwifroot.defaultMacros;
  // An object containing all the sections of code to insert into the template
  Blockly.Kiwifroot.sections_ = {};
  // An object containing all the sections of code and the unique ids that have been added to them
  Blockly.Kiwifroot.sectionIds_ = {};
  // The special symbols to interpret from the template
  Blockly.Kiwifroot.openMacroDelimeter_ = '[[';
  Blockly.Kiwifroot.closeMacroDelimeter_ = ']]';
  Blockly.Kiwifroot.openSectionDelimeter_ = '{{';
  Blockly.Kiwifroot.closeSectionDelimeter_ = '}}';

  Blockly.Kiwifroot.defs_ = Object.create(null);

  // Create the database of names
  if (!Blockly.Kiwifroot.variableDB_) {
    Blockly.Kiwifroot.variableDB_ =
        new Blockly.Names(Blockly.Kiwifroot.RESERVED_WORDS_);
  } else {
    Blockly.Kiwifroot.variableDB_.reset();
  }

  // Provide all the custom variables
  var variables = Blockly.Variables.allVariables(workspace);
  for (var x = 0; x < variables.length; x++) {
    var code = Blockly.Kiwifroot.variableDB_.getName(variables[x],
        Blockly.Variables.NAME_TYPE) + ';';
    Blockly.Kiwifroot.provideAddition(Blockly.Kiwifroot.DEFINITIONS,code);
  }
};

/**
 * Prepend the generated code with the definitions required for plugin
 * @param {string} code Generated code.
 * @return {string} Completed code.
 */
Blockly.Kiwifroot.finish = function(code) {
  //
  for (var name in Blockly.Kiwifroot.defs_) {
    var def = Blockly.Kiwifroot.defs_[name];
    var code = '';
    for (var i = 0, n = def.code.length; i < n; i++) {
      code += def.prefix + def.code[i] + def.suffix;
    }
    var fullCode = def.name + ' = function(' + def.args + '){\n'+def.head + code + def.foot + '}';
    Blockly.Kiwifroot.definitions_[def.name] = fullCode;
  }
  // Support the old definitions way of doing things
  for (var name in Blockly.Kiwifroot.definitions_) {

    Blockly.Kiwifroot.provideAddition(
        Blockly.Kiwifroot.DEFINITIONS,
        Blockly.Kiwifroot.definitions_[name]+'\n\n');
  }
  // Generate everything from the template we were provided
  var code = Blockly.Kiwifroot.generateFromTemplate_();
  return code;
};

/**
 * Generates the final code output from the template/sections/macros provided
 * @return {string} The code generated
 */
Blockly.Kiwifroot.generateFromTemplate_ = function(){
  var str = Blockly.Kiwifroot.template_;
  // Gather the identifiers used in the template
  var symbols = Blockly.Kiwifroot.macros_;
  var macroStart = Blockly.Kiwifroot.openMacroDelimeter_;
  var macroEnd = Blockly.Kiwifroot.closeMacroDelimeter_;
  var sectionStart = Blockly.Kiwifroot.openSectionDelimeter_;
  var sectionEnd = Blockly.Kiwifroot.closeSectionDelimeter_;
  // Prepare the delimeters for use in regexp
  var safeMacroStart = regexpQuote(macroStart);
  var safeMacroEnd = regexpQuote(macroEnd);
  var safeSectionStart = regexpQuote(sectionStart);
  var safeSectionEnd = regexpQuote(sectionEnd);

  // Find all the macros in the template
  var MACRO_RE = safeMacroStart+".*?"+safeMacroEnd;
  var macrosInTemplate = str.match(new RegExp(MACRO_RE,'g'));
  if (macrosInTemplate) {
    for (var i = 0, n = macrosInTemplate.length; i < n; i++){
      var macroNameWithSymbols = macrosInTemplate[i];
      var macroName = macroNameWithSymbols.slice(
          macroStart.length,macroNameWithSymbols.length-macroEnd.length);
      // TODO if = is present, set the symbol to a new value
      if (!symbols.hasOwnProperty(macroName)) throw 'No macro provided with the name: '+macroName;
      str = str.replace(new RegExp(safeMacroStart+macroName+safeMacroEnd),
          symbols[macroName]);
    }
  }

  // Find all the sections in the template
  var SECTION_RE = safeSectionStart+"(.|\n)*?"+safeSectionEnd;
  var i = 0;
  var sectionsInTemplate = str.match(new RegExp(SECTION_RE,'g'));
  while (sectionsInTemplate && sectionsInTemplate.length > 0 && i++ < 1000) {
    var sectionNameWithSymbols = sectionsInTemplate[0];
    var sectionNameWithArgs = sectionNameWithSymbols.slice(
        sectionStart.length,sectionNameWithSymbols.length-sectionEnd.length);
    // Find any prefix/suffix args + the name of the section
    var sectionName = sectionNameWithArgs;
    var prefix = '';
    var suffix = '';
    var args = sectionName.split(',');
    if (args.length > 1) {
      prefix = args[0];
      sectionName = args[1];
      if (args.length > 2) {
          suffix = args[2];
          if (args.length > 3) throw 'Too many arguments provided in section: '+sectionName;
      }
    }
    // Generate the code for this section
    var code = Blockly.Kiwifroot.generateSection_(sectionName,prefix,suffix);
    var re = safeSectionStart+regexpQuote(sectionNameWithArgs)+safeSectionEnd;
    str = str.replace(new RegExp(re),code);
    sectionsInTemplate = str.match(new RegExp(SECTION_RE,'g'));
  }
  return str;
};

/**
 * Generates a section of code
 * @param {string} section The name of the section to generate
 * @return The section of the code
 */
Blockly.Kiwifroot.generateSection_ = function(section,prefix,suffix){
  var code = '';
  var arr = Blockly.Kiwifroot.sections_[section];
  if (arr) {
    for (var i=0, n=arr.length; i < n; i++){
      code += prefix + arr[i];
      if (i < n - 1) code += suffix;
    }
  }
  return code;
};

/**
 * Generates the constructor code for this entity
 * @private
 * @return {string} The constructor code
 */
Blockly.Kiwifroot.generateConstructor_ = function(){
  var className = 'TestEntity'
  var code = '';
  for (var i=0, n=Blockly.Kiwifroot.constructorAdditions_.length; i < n; i++){
    code += '\t' + Blockly.Kiwifroot.constructorAdditions_[i];
  }
  return 'function ' + className + '() {\n' + code + '}';
}
/**
 * Helper function that automatically escapes all characters in the string
 * that have a special meaning in a regexp expression
 * @param {string} str The string to escape
 * @return {string} The escaped string
 */
var regexpQuote = function(str) {
  return str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
};
<commit_msg>Now supports nested sections and macros<commit_after>/**
 * @license
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * https://developers.google.com/blockly/
 *
 * 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.
 */

/**
 * @fileoverview Helper functions for generating Kiwifroot plugins for blocks.
 * @author rani_sputnik@hotmail.com (Ryan Loader)
 */
'use strict';

goog.provide('Blockly.Kiwifroot');

goog.require('Blockly.JavaScript');
goog.require('Blockly.JavaScript.colour');
goog.require('Blockly.JavaScript.lists');
goog.require('Blockly.JavaScript.logic');
goog.require('Blockly.JavaScript.loops');
goog.require('Blockly.JavaScript.math');
goog.require('Blockly.JavaScript.procedures');
goog.require('Blockly.JavaScript.text');
goog.require('Blockly.JavaScript.variables');

/**
 * Kiwifroot code generator.
 * @type !Blockly.Generator
 */
Blockly.Kiwifroot = Blockly.JavaScript;

/**
 * The indent symbol used in code generation - we use tabs
 * @type {string}
 */
Blockly.Kiwifroot.INDENT = '\t';

/**
 * The default template to use when compiling for Kiwifroot
 * @const
 * @type {string}
 */
Blockly.Kiwifroot.defaultTemplate =
  // Define all the settings for the plugin (each new script is treated a component)
  'Kiwi.Plugins.[[PLUGIN_NAME]] = {\n'+
  '\tname:\'[[PLUGIN_NAME]]\',\n'+
  '\tversion:\'[[PLUGIN_VERSION]]\',\n'+
  '\tminimumKiwiVersion:\'[[MIN_KIWI_VERSION]]\',\n'+
  '\tkiwifrootPlugins:[[KIWIFROOT_PLUGINS]]\n'+
  '};\n\n'+
  // Register the plugin with Kiwi.js
  'Kiwi.PluginManager.register(Kiwi.Plugins.[[PLUGIN_NAME]]);\n\n'+

  // Here we define the constructor for the plugin
  'Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]] = function(gameObject){\n'+
  // Call the base component constructor
  '\tKiwi.Component.call(this, gameObject, \'[[PLUGIN_NAME]]\');\n\n'+
  // Set this components state property
  '\tthis.state = this.owner.state;\n\n'+
  // This is where the constructor additions will be made
  '{{\t,CONSTRUCTOR,\n}}\n'+
  '}\n\n' +
  // Extend GameObject
  'Kiwi.extend(Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]], Kiwi.Component);\n\n'+
  // Supply an add method for the plugin
  'Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]].add = function(state, gameObject, params){\n'+
  '\tgameObject.components.add(new Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]](gameObject));\n'+
  // TODO provide an 'on added' section
  '}\n\n'+
  // Add all the definitions here, they will all be prefixed with the namespace and
  // will include two newline breaks after each definition.
  '{{Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]].prototype.,DEFINITIONS,\n\n}}'+

  // Add the component to the list of plugins
  'Kiwi.Plugins.[[PLUGIN_NAME]].kiwifrootPlugins.push({\n'+
    '\ttype: Kiwifroot.Plugins.COMPONENT,\n'+
    '\tname: \'[[PLUGIN_NAME]]\',\n'+
    '\tnamespace: Kiwi.Plugins.[[PLUGIN_NAME]].[[CLASS_NAME]]\n'+
  '});\n\n';

/**
 * The default macro properties to use when compiling for Kiwifroot
 * @const
 * @type {object}
 */
Blockly.Kiwifroot.defaultMacros = {
  'PLUGIN_NAME':'MyScript',
  'CLASS_NAME':'Component',
  'PLUGIN_VERSION':'0.5.0',
  'MIN_KIWI_VERSION':'1.1.1',
  'KIWIFROOT_PLUGINS':'[]'
};

/**
 * The constructor section of the template
 * @const
 * @type {string}
 */
Blockly.Kiwifroot.CONSTRUCTOR = 'CONSTRUCTOR';

/**
 * The definitions section of the template
 * @const
 * @type {string}
 */
Blockly.Kiwifroot.DEFINITIONS = 'DEFINITIONS';

/**
 * The array of sounds, contains tuples of names and ids
 * @type {array}
 */
Blockly.Kiwifroot.sounds_ = [
  ["Ammo","5"],
  ['Machine Gun',"11"]
];

Blockly.Kiwifroot.addReservedWords();

/**
 * Adds a new addition to the given section (spectified in the template)
 * @param {string} section The section to add the code to
 * @param {string} code The javascript to insert into the section
 */
Blockly.Kiwifroot.provideAddition = function(section,code){
  if (!Blockly.Kiwifroot.sections_[section]) {
    Blockly.Kiwifroot.sections_[section] = [];
  }
  Blockly.Kiwifroot.sections_[section].push(code);
};

/**
 * Adds a new addition provided an addition with the given uniqueId has not
 * already been added to the given section
 * @param {string} uniqueId The id that must be unique in order to make the addition
 * @param {string} section The section to add the code to
 * @param {string} code The javascript to insert into the section
 */
Blockly.Kiwifroot.provideAdditionOnce = function(uniqueId, section, code){
  if (!Blockly.Kiwifroot.sectionIds_[section]) {
    Blockly.Kiwifroot.sectionIds_[section] = [];
  }
  var arr = Blockly.Kiwifroot.sectionIds_[section];
  if (arr.indexOf(uniqueId) < 0) {
    arr.push(uniqueId);
    Blockly.Kiwifroot.provideAddition(section,code);
  }
};

/**
 * Sets the macros object that will be applied to the template
 * (Would prefer to send arguments to init but that would mean changing blockly.Generator)
 * @param {Object} macros The new macros object containing all the symbols to be applied to the template
 */
Blockly.Kiwifroot.setMacros = function(macros){
  Blockly.Kiwifroot.macros = macros;
};

/**
 * Sets the template to use when generating code
 * (Would prefer to send arguments to init but that would mean changing blockly.Generator)
 * @param {String} template The template to use, see Blockly.Kiwifroot.defaultTemplate for an example
 */
Blockly.Kiwifroot.setTemplate = function(template){
  Blockly.Kiwifroot.template = template;
};

/**
 * Initialise the database of variable names.
 * @param {!Blockly.Workspace} workspace Workspace to generate code from.
 */
Blockly.Kiwifroot.init = function(workspace) {
  // Create a dictionary of definitions to be printed before the code. (TODO remove)
  Blockly.Kiwifroot.definitions_ = Object.create(null);
  // Create a dictionary mapping desired function names in definitions_
  // to actual function names (to avoid collisions with user functions).
  Blockly.Kiwifroot.functionNames_ = Object.create(null);

  // The template to use to generate the code
  Blockly.Kiwifroot.template_ = Blockly.Kiwifroot.template || Blockly.Kiwifroot.defaultTemplate;
  // The macros to replace in the template
  Blockly.Kiwifroot.macros_ = Blockly.Kiwifroot.macros || Blockly.Kiwifroot.defaultMacros;
  // An object containing all the sections of code to insert into the template
  Blockly.Kiwifroot.sections_ = {};
  // An object containing all the sections of code and the unique ids that have been added to them
  Blockly.Kiwifroot.sectionIds_ = {};
  // The special symbols to interpret from the template
  Blockly.Kiwifroot.openMacroDelimeter_ = '[[';
  Blockly.Kiwifroot.closeMacroDelimeter_ = ']]';
  Blockly.Kiwifroot.openSectionDelimeter_ = '{{';
  Blockly.Kiwifroot.closeSectionDelimeter_ = '}}';

  Blockly.Kiwifroot.defs_ = Object.create(null);

  // Create the database of names
  if (!Blockly.Kiwifroot.variableDB_) {
    Blockly.Kiwifroot.variableDB_ =
        new Blockly.Names(Blockly.Kiwifroot.RESERVED_WORDS_);
  } else {
    Blockly.Kiwifroot.variableDB_.reset();
  }

  // Provide all the custom variables
  var variables = Blockly.Variables.allVariables(workspace);
  for (var x = 0; x < variables.length; x++) {
    var code = Blockly.Kiwifroot.variableDB_.getName(variables[x],
        Blockly.Variables.NAME_TYPE) + ';';
    Blockly.Kiwifroot.provideAddition(Blockly.Kiwifroot.DEFINITIONS,code);
  }
};

/**
 * Prepend the generated code with the definitions required for plugin
 * @param {string} code Generated code.
 * @return {string} Completed code.
 */
Blockly.Kiwifroot.finish = function(code) {
  //
  for (var name in Blockly.Kiwifroot.defs_) {
    var def = Blockly.Kiwifroot.defs_[name];
    var code = '';
    for (var i = 0, n = def.code.length; i < n; i++) {
      code += def.prefix + def.code[i] + def.suffix;
    }
    var fullCode = def.name + ' = function(' + def.args + '){\n'+def.head + code + def.foot + '}';
    Blockly.Kiwifroot.definitions_[def.name] = fullCode;
  }
  // Support the old definitions way of doing things
  for (var name in Blockly.Kiwifroot.definitions_) {

    Blockly.Kiwifroot.provideAddition(
        Blockly.Kiwifroot.DEFINITIONS,
        Blockly.Kiwifroot.definitions_[name]+'\n\n');
  }
  // Generate everything from the template we were provided
  var code = Blockly.Kiwifroot.generateFromTemplate_();
  return code;
};

/**
 * Generates the final code output from the template/sections/macros provided
 * @return {string} The code generated
 */
Blockly.Kiwifroot.generateFromTemplate_ = function(){
  var str = Blockly.Kiwifroot.template_;
  // Gather the identifiers used in the template
  var symbols = Blockly.Kiwifroot.macros_;
  var macroStart = Blockly.Kiwifroot.openMacroDelimeter_;
  var macroEnd = Blockly.Kiwifroot.closeMacroDelimeter_;
  var sectionStart = Blockly.Kiwifroot.openSectionDelimeter_;
  var sectionEnd = Blockly.Kiwifroot.closeSectionDelimeter_;
  // Prepare the delimeters for use in regexp
  var safeMacroStart = regexpQuote(macroStart);
  var safeMacroEnd = regexpQuote(macroEnd);
  var safeSectionStart = regexpQuote(sectionStart);
  var safeSectionEnd = regexpQuote(sectionEnd);

  var MACRO_RE = safeMacroStart+".*?"+safeMacroEnd;
  var macrosInTemplate = str.match(new RegExp(MACRO_RE,'g'));
  var SECTION_RE = safeSectionStart+"(.|\n)*?"+safeSectionEnd;
  var sectionsInTemplate = str.match(new RegExp(SECTION_RE,'g'));
  var k = 0;
  var MAX_NESTING = 100;

  // While there are still symbols in the template, find and replace them
  while (((macrosInTemplate && macrosInTemplate.length > 0)
    || (sectionsInTemplate && sectionsInTemplate.length > 0))
    && k++ < MAX_NESTING) {
    // Replace the macros in the template
    if (macrosInTemplate) {
      for (var i = 0, n = macrosInTemplate.length; i < n; i++){
        var macroNameWithSymbols = macrosInTemplate[0];
        var macroName = macroNameWithSymbols.slice(
            macroStart.length,macroNameWithSymbols.length-macroEnd.length);
        // TODO if = is present, set the symbol to a new value
        if (!symbols.hasOwnProperty(macroName)) throw 'No macro provided with the name: '+macroName;
        str = str.replace(new RegExp(safeMacroStart+macroName+safeMacroEnd),
            symbols[macroName]);
      }
    }
    // Replace the sections in the template
    if (sectionsInTemplate) {
      for (var i = 0, n = sectionsInTemplate.length; i < n; i++) {
        var sectionNameWithSymbols = sectionsInTemplate[i];
        var sectionNameWithArgs = sectionNameWithSymbols.slice(
            sectionStart.length,sectionNameWithSymbols.length-sectionEnd.length);
        // Find any prefix/suffix args + the name of the section
        var sectionName = sectionNameWithArgs;
        var prefix = '';
        var suffix = '';
        var args = sectionName.split(',');
        if (args.length > 1) {
          prefix = args[0];
          sectionName = args[1];
          if (args.length > 2) {
              suffix = args[2];
              if (args.length > 3) throw 'Too many arguments provided in section: '+sectionName;
          }
        }
        // Generate the code for this section
        var code = Blockly.Kiwifroot.generateSection_(sectionName,prefix,suffix);
        var re = safeSectionStart+regexpQuote(sectionNameWithArgs)+safeSectionEnd;
        str = str.replace(new RegExp(re),code);
      }
    }
    // If then new sections added any new macros/templates, then we need to make
    // sure that we replace those too
    macrosInTemplate = str.match(new RegExp(MACRO_RE,'g'));
    sectionsInTemplate = str.match(new RegExp(SECTION_RE,'g'));
  }

  return str;
};

/**
 * Generates a section of code
 * @param {string} section The name of the section to generate
 * @return The section of the code
 */
Blockly.Kiwifroot.generateSection_ = function(section,prefix,suffix){
  var code = '';
  var arr = Blockly.Kiwifroot.sections_[section];
  if (arr) {
    for (var i=0, n=arr.length; i < n; i++){
      code += prefix + arr[i];
      if (i < n - 1) code += suffix;
    }
  }
  return code;
};

/**
 * Generates the constructor code for this entity
 * @private
 * @return {string} The constructor code
 */
Blockly.Kiwifroot.generateConstructor_ = function(){
  var className = 'TestEntity'
  var code = '';
  for (var i=0, n=Blockly.Kiwifroot.constructorAdditions_.length; i < n; i++){
    code += '\t' + Blockly.Kiwifroot.constructorAdditions_[i];
  }
  return 'function ' + className + '() {\n' + code + '}';
}
/**
 * Helper function that automatically escapes all characters in the string
 * that have a special meaning in a regexp expression
 * @param {string} str The string to escape
 * @return {string} The escaped string
 */
var regexpQuote = function(str) {
  return str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
};
<|endoftext|>


<commit_before><commit_msg>get metadata for tagguids<commit_after><|endoftext|>


<commit_before><commit_msg>Allow Player to have an Init function<commit_after><|endoftext|>


<commit_before>import React, {useContext} from "react";
import shp from "shpjs";

import {formatNumberWithCommas, readFileAsArrayBuffer, readFileAsBase64Url} from "../utils/generalUtils";
import {ProjectContext, plotLimit} from "./constants";
import {mercator} from "../utils/mercator";

export class PlotDesign extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            lonMin: "",
            latMin: "",
            lonMax: "",
            latMax: ""
        };
    }

    componentDidMount() {
        this.setCoordsFromBoundary();
    }

    componentDidUpdate(prevProps) {
        if (this.props.aoiFeatures && prevProps.aoiFeatures !== this.props.aoiFeatures) {
            this.setCoordsFromBoundary();
        }
    }

    setCoordsFromBoundary = () => {
        const {aoiFeatures} = this.props;
        if (aoiFeatures?.length === 1) {
            const boundaryExtent = mercator.parseGeoJson(aoiFeatures[0], false).getExtent();
            this.setState({
                lonMin: boundaryExtent[0],
                latMin: boundaryExtent[1],
                lonMax: boundaryExtent[2],
                latMax: boundaryExtent[3]
            });
        } else {
            this.setState({
                lonMin: "",
                latMin: "",
                lonMax: "",
                latMax: ""
            });
        }
    };

    updateBoundaryFromCoords = newCoord => {
        this.setState(
            newCoord,
            () => {
                const {latMin, latMax, lonMin, lonMax} = this.state;
                this.setPlotDetails({
                    aoiFeatures: [mercator.generateGeoJSON(latMin, latMax, lonMin, lonMax)]
                });
            }
        );
    };

    setPlotDetails = newDetail => {
        const resetAOI = ["csv", "shp"].includes(newDetail.plotDistribution);
        if (resetAOI) {
            this.setState({
                lonMin: "",
                latMin: "",
                lonMax: "",
                latMax: ""
            });
        }
        this.context.setProjectDetails(Object.assign(
            newDetail,
            {plots: []},
            resetAOI ? {aoiFeatures: [], aoiFileName: ""} : {}
        ));
    };

    /// Render Functions

    renderLabeledInput = (label, property) => (

            {label}
            <input
                className="form-control form-control-sm"
                id={property}
                min="0"
                onChange={e => this.setPlotDetails({[property]: Number(e.target.value)})}
                step="1"
                type="number"
                value={this.context[property] || ""}
            />

    );

    renderPlotShape = () => {
        const {plotShape} = this.context;
        return (

                Plot Shape

                        <input
                            checked={plotShape === "circle"}
                            className="form-check-input"
                            id="plot-shape-circle"
                            onChange={() => this.setPlotDetails({plotShape: "circle"})}
                            type="radio"
                        />

                            Circle

                        <input
                            checked={plotShape === "square"}
                            className="form-check-input"
                            id="plot-shape-square"
                            onChange={() => this.setPlotDetails({plotShape: "square"})}
                            type="radio"
                        />

                            Square

        );
    };

    renderAOICoords = () => {
        const {latMax, lonMin, lonMax, latMin} = this.state;
        return (

                Boundary Coordinates

                            <input
                                className="form-control form-control-sm"
                                max="90.0"
                                min="-90.0"
                                onChange={e => this.updateBoundaryFromCoords({latMax: parseFloat(e.target.value)})}
                                placeholder="North"
                                step="any"
                                type="number"
                                value={latMax}
                            />

                            <input
                                className="form-control form-control-sm"
                                max="180.0"
                                min="-180.0"
                                onChange={e => this.updateBoundaryFromCoords({lonMin: parseFloat(e.target.value)})}
                                placeholder="West"
                                step="any"
                                type="number"
                                value={lonMin}
                            />

                            <input
                                className="form-control form-control-sm"
                                max="180.0"
                                min="-180.0"
                                onChange={e => this.updateBoundaryFromCoords({lonMax: parseFloat(e.target.value)})}
                                placeholder="East"
                                step="any"
                                type="number"
                                value={lonMax}
                            />

                            <input
                                className="form-control form-control-sm"
                                max="90.0"
                                min="-90.0"
                                onChange={e => this.updateBoundaryFromCoords({latMin: parseFloat(e.target.value)})}
                                placeholder="South"
                                step="any"
                                type="number"
                                value={latMin}
                            />

        );
    };

    loadGeoJson = shpFile => {
        try {
            shp(shpFile).then(g => {
                this.context.setProjectDetails({
                    aoiFeatures: g.features.map(f => f.geometry),
                    aoiFileName: g.fileName
                });
            });
        } catch {
            alert("Unknown error loading shape file.");
        }
    };

    renderBoundaryFileInput = () => (

                    Upload project boundary
                <input
                    accept="application/zip"
                    defaultValue=""
                    id="project-boundary-file"
                    onChange={e => {
                        const file = e.target.files[0];
                        readFileAsArrayBuffer(file, this.loadGeoJson);
                    }}
                    style={{display: "none"}}
                    type="file"
                />

                    File: {this.context.aoiFileName}

    );

    renderAOISelector = () => (

            {this.renderAOICoords()}
            {this.renderBoundaryFileInput()}

    );

    renderFileInput = fileType => (

                    Upload plot file
                    <input
                        accept={fileType === "csv" ? "text/csv" : "application/zip"}
                        defaultValue=""
                        id="plot-distribution-file"
                        onChange={e => {
                            const file = e.target.files[0];
                            readFileAsBase64Url(file, base64 => this.setPlotDetails({
                                plotFileName: file.name,
                                plotFileBase64: base64
                            }));
                        }}
                        style={{display: "none"}}
                        type="file"
                    />

                    File: {this.context.plotFileName || (this.context.projectId > 0 ? "Use existing data" : "None")}

                Download example plot {fileType === "csv" ? "csv" : "shape"} file

    );

    renderCSV = plotUnits => (

            {this.renderFileInput("csv")}

                {this.renderPlotShape()}
                {this.renderLabeledInput(plotUnits, "plotSize")}

    );

    render() {
        const {plotDistribution, plotShape} = this.context;
        const {totalPlots} = this.props;
        const plotUnits = plotShape === "circle" ? "Plot diameter (m)" : "Plot width (m)";

        const plotOptions = {
            random: {
                display: "Random",
                description: "Plot centers will be randomly distributed within the project boundary.",
                inputs: [() => this.renderLabeledInput("Number of plots", "numPlots"),
                         this.renderPlotShape,
                         () => this.renderLabeledInput(plotUnits, "plotSize")],
                showAOI: true
            },
            gridded: {
                display: "Gridded",
                description: "Plot centers will be arranged on a grid within the AOI using the plot spacing selected below.",
                inputs: [() => this.renderLabeledInput("Plot spacing (m)", "plotSpacing"),
                         this.renderPlotShape,
                         () => this.renderLabeledInput(plotUnits, "plotSize")],
                showAOI: true
            },
            csv: {
                display: "CSV File",
                description: "Specify your own plot centers by uploading a CSV with these fields: LON,LAT,PLOTID.",
                inputs: [() => this.renderCSV(plotUnits)],
                showAOI: false
            },
            shp: {
                display: "SHP File",
                description: "Specify your own plot boundaries by uploading a zipped Shapefile (containing SHP, SHX, DBF, and PRJ files) of polygon features. Each feature must have a unique PLOTID field.",
                inputs: [() => this.renderFileInput("shp")],
                showAOI: false
            }
        };

        return (

Plot Generation

                            Spatial Distribution
                            <select
                                className="form-control form-control-sm"
                                onChange={e => this.setPlotDetails({plotDistribution: e.target.value})}
                                value={plotDistribution}
                            >
                                {Object.entries(plotOptions).map(([key, options]) =>
                                    <option key={key} value={key}>{options.display}</option>)}
                            </select>

{`- ${plotOptions[plotDistribution].description}`}

                            {plotOptions[plotDistribution].inputs.map((i, idx) => (
                            // eslint-disable-next-line react/no-array-index-key

                                    {i()}

                            ))}

                        {plotOptions[plotDistribution].showAOI && this.renderAOISelector()}

 plotLimit ? "#8B0000" : "#006400",
                            fontSize: "1rem",
                            whiteSpace: "pre-line"
                        }}
                    >
                        {totalPlots > 0 && `This project will contain around ${formatNumberWithCommas(totalPlots)} plots.`}
                        {totalPlots > 0 && totalPlots > plotLimit
                        && `\n* The maximum allowed number for the selected plot distribution is ${formatNumberWithCommas(plotLimit)}.`}

        );
    }
}
PlotDesign.contextType = ProjectContext;

export function PlotDesignReview() {
    return (

                <PlotReview/>

                <AOIReview/>

    );
}

export function PlotReview() {
    const {
        numPlots,
        plotDistribution,
        plotFileName,
        plotShape,
        plotSize,
        plotSpacing,
        useTemplatePlots
    } = useContext(ProjectContext);
    return (

            {useTemplatePlots &&
Plots will be copied from template project
}

                                Spatial distribution

                                    {plotDistribution}

                                Number of plots

                                    {numPlots} plots

                            {plotDistribution === "gridded" && (

                                    Plot spacing

                                        {plotSpacing} m

                            )}
                            {plotDistribution !== "shp" && (
                                <>

                                        Plot shape

                                            {plotShape}

                                        Plot size

                                            {plotSize} m

                                </>
                            )}
                            {["shp", "csv"].includes(plotDistribution) && (

                                    Plot file

                                            {plotFileName
                                                ? plotFileName.length > 13 ? `${plotFileName.substring(0, 13)}...` : plotFileName
                                                : "null"}
                                            {plotFileName &&
{plotFileName}
}

                            )}

    );
}

export function AOIReview() {
    const {aoiFeatures, aoiFileName} = useContext(ProjectContext);
    const boundaryExtent = mercator.parseGeoJson(aoiFeatures[0], false).getExtent();
    return (

            {aoiFileName.length
                ?
Boundary will be calculated from {aoiFileName}

                : (
                    <>

Boundary Coordinates

                                    North: {boundaryExtent[3]}

                                    West: {boundaryExtent[0]}

                                    East: {boundaryExtent[2]}

                                    South: {boundaryExtent[1]}

                    </>
                )}

    );
}
<commit_msg>small ui fix<commit_after>import React, {useContext} from "react";
import shp from "shpjs";

import {formatNumberWithCommas, readFileAsArrayBuffer, readFileAsBase64Url} from "../utils/generalUtils";
import {ProjectContext, plotLimit} from "./constants";
import {mercator} from "../utils/mercator";

export class PlotDesign extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            lonMin: "",
            latMin: "",
            lonMax: "",
            latMax: ""
        };
    }

    componentDidMount() {
        this.setCoordsFromBoundary();
    }

    componentDidUpdate(prevProps) {
        if (this.props.aoiFeatures && prevProps.aoiFeatures !== this.props.aoiFeatures) {
            this.setCoordsFromBoundary();
        }
    }

    setCoordsFromBoundary = () => {
        const {aoiFeatures} = this.props;
        if (aoiFeatures?.length === 1) {
            const boundaryExtent = mercator.parseGeoJson(aoiFeatures[0], false).getExtent();
            this.setState({
                lonMin: boundaryExtent[0],
                latMin: boundaryExtent[1],
                lonMax: boundaryExtent[2],
                latMax: boundaryExtent[3]
            });
        } else {
            this.setState({
                lonMin: "",
                latMin: "",
                lonMax: "",
                latMax: ""
            });
        }
    };

    updateBoundaryFromCoords = newCoord => {
        this.setState(
            newCoord,
            () => {
                const {latMin, latMax, lonMin, lonMax} = this.state;
                this.setPlotDetails({
                    aoiFeatures: [mercator.generateGeoJSON(latMin, latMax, lonMin, lonMax)]
                });
            }
        );
    };

    setPlotDetails = newDetail => {
        const resetAOI = ["csv", "shp"].includes(newDetail.plotDistribution);
        if (resetAOI) {
            this.setState({
                lonMin: "",
                latMin: "",
                lonMax: "",
                latMax: ""
            });
        }
        this.context.setProjectDetails(Object.assign(
            newDetail,
            {plots: []},
            resetAOI ? {aoiFeatures: [], aoiFileName: ""} : {}
        ));
    };

    /// Render Functions

    renderLabeledInput = (label, property) => (

            {label}
            <input
                className="form-control form-control-sm"
                id={property}
                min="0"
                onChange={e => this.setPlotDetails({[property]: Number(e.target.value)})}
                step="1"
                type="number"
                value={this.context[property] || ""}
            />

    );

    renderPlotShape = () => {
        const {plotShape} = this.context;
        return (

                Plot Shape

                        <input
                            checked={plotShape === "circle"}
                            className="form-check-input"
                            id="plot-shape-circle"
                            onChange={() => this.setPlotDetails({plotShape: "circle"})}
                            type="radio"
                        />

                            Circle

                        <input
                            checked={plotShape === "square"}
                            className="form-check-input"
                            id="plot-shape-square"
                            onChange={() => this.setPlotDetails({plotShape: "square"})}
                            type="radio"
                        />

                            Square

        );
    };

    renderAOICoords = () => {
        const {latMax, lonMin, lonMax, latMin} = this.state;
        return (

                Boundary Coordinates

                            <input
                                className="form-control form-control-sm"
                                max="90.0"
                                min="-90.0"
                                onChange={e => this.updateBoundaryFromCoords({latMax: parseFloat(e.target.value)})}
                                placeholder="North"
                                step="any"
                                type="number"
                                value={latMax}
                            />

                            <input
                                className="form-control form-control-sm"
                                max="180.0"
                                min="-180.0"
                                onChange={e => this.updateBoundaryFromCoords({lonMin: parseFloat(e.target.value)})}
                                placeholder="West"
                                step="any"
                                type="number"
                                value={lonMin}
                            />

                            <input
                                className="form-control form-control-sm"
                                max="180.0"
                                min="-180.0"
                                onChange={e => this.updateBoundaryFromCoords({lonMax: parseFloat(e.target.value)})}
                                placeholder="East"
                                step="any"
                                type="number"
                                value={lonMax}
                            />

                            <input
                                className="form-control form-control-sm"
                                max="90.0"
                                min="-90.0"
                                onChange={e => this.updateBoundaryFromCoords({latMin: parseFloat(e.target.value)})}
                                placeholder="South"
                                step="any"
                                type="number"
                                value={latMin}
                            />

        );
    };

    loadGeoJson = shpFile => {
        try {
            shp(shpFile).then(g => {
                this.context.setProjectDetails({
                    aoiFeatures: g.features.map(f => f.geometry),
                    aoiFileName: g.fileName
                });
            });
        } catch {
            alert("Unknown error loading shape file.");
        }
    };

    renderBoundaryFileInput = () => (

                    Upload project boundary
                <input
                    accept="application/zip"
                    defaultValue=""
                    id="project-boundary-file"
                    onChange={e => {
                        const file = e.target.files[0];
                        readFileAsArrayBuffer(file, this.loadGeoJson);
                    }}
                    style={{display: "none"}}
                    type="file"
                />

                    File: {this.context.aoiFileName}

    );

    renderAOISelector = () => (

            {this.renderAOICoords()}
            {this.renderBoundaryFileInput()}

    );

    renderFileInput = fileType => (

                    Upload plot file
                    <input
                        accept={fileType === "csv" ? "text/csv" : "application/zip"}
                        defaultValue=""
                        id="plot-distribution-file"
                        onChange={e => {
                            const file = e.target.files[0];
                            readFileAsBase64Url(file, base64 => this.setPlotDetails({
                                plotFileName: file.name,
                                plotFileBase64: base64
                            }));
                        }}
                        style={{display: "none"}}
                        type="file"
                    />

                    File: {this.context.plotFileName || (this.context.projectId > 0 ? "Use existing data" : "None")}

                Download example plot {fileType === "csv" ? "csv" : "shape"} file

    );

    renderCSV = plotUnits => (

            {this.renderFileInput("csv")}

                {this.renderPlotShape()}
                {this.renderLabeledInput(plotUnits, "plotSize")}

    );

    render() {
        const {plotDistribution, plotShape} = this.context;
        const {totalPlots} = this.props;
        const plotUnits = plotShape === "circle" ? "Plot diameter (m)" : "Plot width (m)";

        const plotOptions = {
            random: {
                display: "Random",
                description: "Plot centers will be randomly distributed within the project boundary.",
                inputs: [() => this.renderLabeledInput("Number of plots", "numPlots"),
                         this.renderPlotShape,
                         () => this.renderLabeledInput(plotUnits, "plotSize")],
                showAOI: true
            },
            gridded: {
                display: "Gridded",
                description: "Plot centers will be arranged on a grid within the AOI using the plot spacing selected below.",
                inputs: [() => this.renderLabeledInput("Plot spacing (m)", "plotSpacing"),
                         this.renderPlotShape,
                         () => this.renderLabeledInput(plotUnits, "plotSize")],
                showAOI: true
            },
            csv: {
                display: "CSV File",
                description: "Specify your own plot centers by uploading a CSV with these fields: LON,LAT,PLOTID.",
                inputs: [() => this.renderCSV(plotUnits)],
                showAOI: false
            },
            shp: {
                display: "SHP File",
                description: "Specify your own plot boundaries by uploading a zipped Shapefile (containing SHP, SHX, DBF, and PRJ files) of polygon features. Each feature must have a unique PLOTID field.",
                inputs: [() => this.renderFileInput("shp")],
                showAOI: false
            }
        };

        return (

Plot Generation

                            Spatial Distribution
                            <select
                                className="form-control form-control-sm"
                                onChange={e => this.setPlotDetails({plotDistribution: e.target.value})}
                                value={plotDistribution}
                            >
                                {Object.entries(plotOptions).map(([key, options]) =>
                                    <option key={key} value={key}>{options.display}</option>)}
                            </select>

{`- ${plotOptions[plotDistribution].description}`}

                            {plotOptions[plotDistribution].inputs.map((i, idx) => (
                            // eslint-disable-next-line react/no-array-index-key

                                    {i()}

                            ))}

                        {plotOptions[plotDistribution].showAOI && this.renderAOISelector()}

 plotLimit ? "#8B0000" : "#006400",
                            fontSize: "1rem",
                            whiteSpace: "pre-line"
                        }}
                    >
                        {totalPlots > 0 && `This project will contain around ${formatNumberWithCommas(totalPlots)} plots.`}
                        {totalPlots > 0 && totalPlots > plotLimit
                        && `\n* The maximum allowed number for the selected plot distribution is ${formatNumberWithCommas(plotLimit)}.`}

        );
    }
}
PlotDesign.contextType = ProjectContext;

export function PlotDesignReview() {
    return (

                <PlotReview/>

                <AOIReview/>

    );
}

export function PlotReview() {
    const {
        numPlots,
        plotDistribution,
        plotFileName,
        plotShape,
        plotSize,
        plotSpacing,
        useTemplatePlots
    } = useContext(ProjectContext);
    return (

            {useTemplatePlots &&
Plots will be copied from template project
}

                                Spatial distribution

                                    {plotDistribution}

                                Number of plots

                                    {numPlots} plots

                            {plotDistribution === "gridded" && (

                                    Plot spacing

                                        {plotSpacing} m

                            )}
                            {plotDistribution !== "shp" && (
                                <>

                                        Plot shape

                                            {plotShape}

                                        Plot size

                                            {plotSize} m

                                </>
                            )}
                            {["shp", "csv"].includes(plotDistribution) && (

                                    Plot file

                                            {plotFileName
                                                ? plotFileName.length > 13 ? `${plotFileName.substring(0, 13)}...` : plotFileName
                                                : "null"}
                                            {plotFileName &&
{plotFileName}
}

                            )}

    );
}

export function AOIReview() {
    const {aoiFeatures, aoiFileName} = useContext(ProjectContext);
    const boundaryExtent = mercator.parseGeoJson(aoiFeatures[0], false).getExtent();
    return (

            {aoiFileName.length
                ? Boundary will be calculated from {aoiFileName}
                : (
                    <>
                        Boundary Coordinates

                                    North: {boundaryExtent[3]}

                                    West: {boundaryExtent[0]}

                                    East: {boundaryExtent[2]}

                                    South: {boundaryExtent[1]}

                    </>
                )}

    );
}
<|endoftext|>


<commit_before>import React from 'react';
import Header from '../components/Header';
import ImageDivider from '../components/ImageDivider';
import HeaderImg from '../assets/images/cover.jpg';
// import Stories from '../components/Home_Stories';
import PreFooter from '../components/Home_PreFooter';
<<<<<<>>>>>> 34f68679d334c7a7b307331a111e6e1bd5d95f80
import one from '../assets/images/gallery/1.jpg';
import two from '../assets/images/gallery/2.jpg';
import three from '../assets/images/gallery/3.jpg';
import four from '../assets/images/gallery/4.jpg';
import five from '../assets/images/gallery/5.jpg';
import six from '../assets/images/gallery/6.jpg';
import seven from '../assets/images/gallery/7.jpg';
import eight from '../assets/images/gallery/8.jpg';

const Home = () => (

Forge The Future

36 Hours of Hacking at Purdue University

Create, Meet, Learn, & Build

          For the past five years, we've brought in 500 students from across the
          the country to create and collaborate on amazing ideas. This is an event
          for people who live and love hacking. Everything we do at BoilerMake
          is for you.

    <ImageDivider images={[one, two, three, four]} />

BoilerMake is here to help you grow

          {/*

 */}

Create awesome projects

              Be surrounded with hundreds of students and sponsors who are all
              incredibly passionate about building fun, new, or innovative projects.

Learn new things

              Not only does BoilerMake encourage building awesome projects, we
              love being able to provide an atmosphere where you can learn new
              things.

    <ImageDivider images={[five, six, seven, eight]} style={{marginTop: '-120px'}}/>

So what else?

          BoilerMake offers a number of perks to make an amazing weekend. To get
          the weekend started, we provide busses to a number of schools to make
          travelling a no-brainer. In the past, we’ve sent busses to UIUC, UMich,
          and others.

          When you arrive, you will be given a swag bag that usually includes a
          t-shirt, a watter bottle, and stickers. Each year we have some special
          swag. BoilerMake 5 saw a fidget spinner. BoilerMake 2 saw a custom
          designed dev board.

          Throughout the weekend, we provide amazing catered meals for breakfast,
          lunch, and dinner. We also have an all you can drink coffee, latte, etc.
          bar and snacks passed out during the event.

          At the end we have an awards ceremony where over $10,000 in prizes are
          given out. Last year winning teams received DJI Phantoms or Nintendo
          Switches. In addition to BoilerMake prizes, sponsors also usually have
          prizes for their categories.

    {/* <Stories/> */}
    <PreFooter/>

);

export default Home;
<commit_msg>Actually bug fix<commit_after>import React from 'react';
import Header from '../components/Header';
import ImageDivider from '../components/ImageDivider';
import HeaderImg from '../assets/images/cover.jpg';
// import Stories from '../components/Home_Stories';
import PreFooter from '../components/Home_PreFooter';
// import BigB from '../assets/images/b.svg';
import one from '../assets/images/gallery/1.jpg';
import two from '../assets/images/gallery/2.jpg';
import three from '../assets/images/gallery/3.jpg';
import four from '../assets/images/gallery/4.jpg';
import five from '../assets/images/gallery/5.jpg';
import six from '../assets/images/gallery/6.jpg';
import seven from '../assets/images/gallery/7.jpg';
import eight from '../assets/images/gallery/8.jpg';

const Home = () => (

Forge The Future

36 Hours of Hacking at Purdue University

Create, Meet, Learn, & Build

          For the past five years, we've brought in 500 students from across the
          the country to create and collaborate on amazing ideas. This is an event
          for people who live and love hacking. Everything we do at BoilerMake
          is for you.

    <ImageDivider images={[one, two, three, four]} />

BoilerMake is here to help you grow

          {/*

 */}

Create awesome projects

              Be surrounded with hundreds of students and sponsors who are all
              incredibly passionate about building fun, new, or innovative projects.

Learn new things

              Not only does BoilerMake encourage building awesome projects, we
              love being able to provide an atmosphere where you can learn new
              things.

    <ImageDivider images={[five, six, seven, eight]} style={{marginTop: '-120px'}}/>

So what else?

          BoilerMake offers a number of perks to make an amazing weekend. To get
          the weekend started, we provide busses to a number of schools to make
          travelling a no-brainer. In the past, we’ve sent busses to UIUC, UMich,
          and others.

          When you arrive, you will be given a swag bag that usually includes a
          t-shirt, a watter bottle, and stickers. Each year we have some special
          swag. BoilerMake 5 saw a fidget spinner. BoilerMake 2 saw a custom
          designed dev board.

          Throughout the weekend, we provide amazing catered meals for breakfast,
          lunch, and dinner. We also have an all you can drink coffee, latte, etc.
          bar and snacks passed out during the event.

          At the end we have an awards ceremony where over $10,000 in prizes are
          given out. Last year winning teams received DJI Phantoms or Nintendo
          Switches. In addition to BoilerMake prizes, sponsors also usually have
          prizes for their categories.

    {/* <Stories/> */}
    <PreFooter/>

);

export default Home;
<|endoftext|>


<commit_before>describe('Simple Agent', function() {
    it('should exist', function() {
	expect(SimpleAgent).toBeDefined();
    });
    it('should be instantiated', function() {
	expect(new SimpleAgent()).toBeDefined();
    });

    it('should be able to ask a problemSystem for possibilities in that systems world', function() {
	var problemMock = {};
	    problemMock.getPossibleActions = function() {
		return [{state: {x: 0}, action: "left"},
			{state: {x: 2}, action: "right"}
		       ];
	    }

	var a = new SimpleAgent(problemMock);
	expect(a.getPossibleActions()).toEqual(problemMock.getPossibleActions());
    });

     describe('should choose an action from possible states using some solver', function() {
	 it('case1: mock returns first state', function() {
	     var problemMock = {};
	     problemMock.getPossibleActions = function() {
		 return [{state: {x: 0}, action: "left"},
			 {state: {x: 2}, action: "right"}

			];
	     }

	     var solverMock = {};
	     solverMock.evaluate = function(states) {
		 return states[0];
	     }
	     var a = new SimpleAgent(problemMock, solverMock);
	     expect(a.chooseAction()).toEqual({state: {x: 0}, action: "left"});
	 });

	 it('case2: mock returns second state', function() {
	     var problemMock = {};
	     problemMock.getPossibleActions = function() {
		 return [{state: {x: 0}, action: "left"},
			 {state: {x: 2}, action: "right"}

			];
	     }

	     var solverMock = {};
	     solverMock.evaluate = function(states) {
		 return states[1];
	     }
	     var a = new SimpleAgent(problemMock, solverMock);
	     expect(a.chooseAction()).toEqual({state: {x: 2}, action: "right"});
	 });
	 it('case3: using an actual instantiation of a function approximator', function() {
	     var problemMock = {};
	     problemMock.getPossibleActions = function() {
		 return [{state: {x: 0}, action: "left"},
			 {state: {x: 2}, action: "right"}

			];
	     }

	     var nonexplorerfa = new FunctionApproximator(null,null,0,null);
	     nonexplorerfa.addValueFunction(
		 nonexplorerfa.createValueFunction(function(s) { return s.x; } )
	     );

	     var a = new SimpleAgent(problemMock, nonexplorerfa);
	     expect(a.chooseAction()).toEqual({state: {x: 2}, action: "right"});
	 });
     });
    it('should be instantiated with a tick of 0, meaning it hasnt done anything to manipulate the problem', function() {
	var sa = new SimpleAgent();
	expect(sa.getTicked()).toBe(0);
    });

    it('should ticked++ when an action is performed', function() {
	 var problemMock = {};
	     problemMock.tick = function() {}
	     problemMock.currentState = function() {return 0;}

	var sa = new SimpleAgent(problemMock);
	expect(sa.getTicked()).toBe(0);
	sa.performAction("left");
	expect(sa.getTicked()).toBe(1);

    })

    it('should know how many actions it performed', function() {
	 var problemMock = {
	     i: 0
	 };
	     problemMock.tick = function() {
		 this.i++;
	     }
	     problemMock.currentState = function() {
		 return {x: this.i};
	     }

	var sa = new SimpleAgent(problemMock);

	sa.performAction("right");
	expect(problemMock.i).toBe(1);
	expect(problemMock.currentState()).toEqual({x: 1});

	sa.performAction("right");
	expect(problemMock.i).toBe(2);
 	expect(problemMock.currentState()).toEqual({x: 2});

    })

    it('should keep a history of all its transitioned states', function() {
	 var problemMock = {
	     i: 0
	 };
	     problemMock.tick = function() {
		 this.i++;
	     }
	     problemMock.currentState = function() {
		 return {x: this.i};
	     }

	var sa = new SimpleAgent(problemMock);

	sa.performAction("right");
	sa.performAction("root");
	sa.performAction("right");

	expect(sa.history.length).toBe(3);
	expect(sa.history).toEqual( [{state: {x:0}, action: "right"}, {state: {x:1}, action: "root"}, {state: {x:2}, action: "right"}]);
    })

});
<commit_msg>Indentation fixed for specs<commit_after>describe('Simple Agent', function() {
    it('should exist', function() {
	expect(SimpleAgent).toBeDefined();
    });
    it('should be instantiated', function() {
	expect(new SimpleAgent()).toBeDefined();
    });

    it('should be able to ask a problemSystem for possibilities in that systems world', function() {
	var problemMock = {};
	    problemMock.getPossibleActions = function() {
		return [{state: {x: 0}, action: "left"},
			{state: {x: 2}, action: "right"}
		       ];
	    }

	var a = new SimpleAgent(problemMock);
	expect(a.getPossibleActions()).toEqual(problemMock.getPossibleActions());
    });

     describe('should choose an action from possible states using some solver', function() {
	 it('case1: mock returns first state', function() {
	     var problemMock = {};
	     problemMock.getPossibleActions = function() {
		 return [{state: {x: 0}, action: "left"},
			 {state: {x: 2}, action: "right"}

			];
	     }

	     var solverMock = {};
	     solverMock.evaluate = function(states) {
		 return states[0];
	     }
	     var a = new SimpleAgent(problemMock, solverMock);
	     expect(a.chooseAction()).toEqual({state: {x: 0}, action: "left"});
	 });

	 it('case2: mock returns second state', function() {
	     var problemMock = {};
	     problemMock.getPossibleActions = function() {
		 return [{state: {x: 0}, action: "left"},
			 {state: {x: 2}, action: "right"}

			];
	     }

	     var solverMock = {};
	     solverMock.evaluate = function(states) {
		 return states[1];
	     }
	     var a = new SimpleAgent(problemMock, solverMock);
	     expect(a.chooseAction()).toEqual({state: {x: 2}, action: "right"});
	 });
	 it('case3: using an actual instantiation of a function approximator', function() {
	     var problemMock = {};
	     problemMock.getPossibleActions = function() {
		 return [{state: {x: 0}, action: "left"},
			 {state: {x: 2}, action: "right"}

			];
	     }

	     var nonexplorerfa = new FunctionApproximator(null,null,0,null);
	     nonexplorerfa.addValueFunction(
		 nonexplorerfa.createValueFunction(function(s) { return s.x; } )
	     );

	     var a = new SimpleAgent(problemMock, nonexplorerfa);
	     expect(a.chooseAction()).toEqual({state: {x: 2}, action: "right"});
	 });
     });
    it('should be instantiated with a tick of 0, meaning it hasnt done anything to manipulate the problem', function() {
	var sa = new SimpleAgent();
	expect(sa.getTicked()).toBe(0);
    });

    it('should ticked++ when an action is performed', function() {
	 var problemMock = {};
	     problemMock.tick = function() {}
	     problemMock.currentState = function() {return 0;}

	var sa = new SimpleAgent(problemMock);
	expect(sa.getTicked()).toBe(0);
	sa.performAction("left");
	expect(sa.getTicked()).toBe(1);

    })

    it('should know how many actions it performed', function() {
	 var problemMock = {
	     i: 0
	 };
	     problemMock.tick = function() {
		 this.i++;
	     }
	     problemMock.currentState = function() {
		 return {x: this.i};
	     }

	var sa = new SimpleAgent(problemMock);

	sa.performAction("right");
	expect(problemMock.i).toBe(1);
	expect(problemMock.currentState()).toEqual({x: 1});

	sa.performAction("right");
	expect(problemMock.i).toBe(2);
 	expect(problemMock.currentState()).toEqual({x: 2});

    })

    it('should keep a history of all its transitioned states', function() {
	var problemMock = {
	    i: 0
	};
	problemMock.tick = function() {
	    this.i++;
	}
	problemMock.currentState = function() {
	    return {x: this.i};
	}

	var sa = new SimpleAgent(problemMock);

	sa.performAction("right");
	sa.performAction("root");
	sa.performAction("right");

	expect(sa.history.length).toBe(3);
	expect(sa.history).toEqual( [{state: {x:0}, action: "right"}, {state: {x:1}, action: "root"}, {state: {x:2}, action: "right"}]);
    })

});
<|endoftext|>


<commit_before>window.realtime = {};

window.realtime.notifyTimeOut = null;
window.realtime.notifyUser = function (message) {
    if ($('.notice.metamaps').length == 0) {
        $('body').prepend('
');
    }
    $('.notice.metamaps').hide().html(message).fadeIn('fast');

    clearTimeout(window.realtime.notifyTimeOut);
    window.realtime.notifyTimeOut = setTimeout(function () {
        $('.notice.metamaps').fadeOut('fast');
    }, 8000);
};

window.realtime.setupSocket = function () {
    var socket = window.realtime.socket;

    socket.emit('newMapperNotify', {
        userid: userid,
        username: username,
        mapid: mapid
    });

    // if you're the 'new guy' update your list with who's already online
    socket.on(userid + '-' + mapid + '-UpdateMapperList', function (data) {
        // data.userid
        // data.username
        // data.userrealtime

        MetamapsModel.mappersOnMap[data.userid] = {
            name: data.username,
            realtime: data.userrealtime
        };

        var onOff = data.userrealtime ? "On" : "Off";
        var mapperListItem = '
' + data.username + '
';
        $('.realtimeMapperList ul').append(mapperListItem);

        //alert(data.username + ' is already online');
    });

    // receive word that there's a new mapper on the map
    socket.on('maps-' + mapid + '-newmapper', function (data) {
        // data.userid
        // data.username

        MetamapsModel.mappersOnMap[data.userid] = {
            name: data.username,
            realtime: false
        };

        var mapperListItem = '
' + data.username + '
';
        $('.realtimeMapperList ul').append(mapperListItem);

        window.realtime.notifyUser(data.username + ' just joined the map');

        // send this new mapper back your details, and the awareness that you've loaded the map
        var update = {
            userToNotify: data.userid,
            username: username,
            userid: userid,
            userrealtime: goRealtime,
            mapid: mapid
        };
        socket.emit('updateNewMapperList', update);
    });

    // receive word that a mapper left the map
    socket.on('maps-' + mapid + '-lostmapper', function (data) {
        // data.userid
        // data.username

        delete MetamapsModel.mappersOnMap[data.userid];

        $('#mapper' + data.userid).remove();

        window.realtime.notifyUser(data.username + ' just left the map');
    });

    // receive word that there's a mapper turned on realtime
    socket.on('maps-' + mapid + '-newrealtime', function (data) {
        // data.userid
        // data.username

        MetamapsModel.mappersOnMap[data.userid].realtime = true;

        $('#mapper' + data.userid).removeClass('littleRtOff').addClass('littleRtOn');

        window.realtime.notifyUser(data.username + ' just turned on realtime');
    });

    // receive word that there's a mapper turned on realtime
    socket.on('maps-' + mapid + '-lostrealtime', function (data) {
        // data.userid
        // data.username

        MetamapsModel.mappersOnMap[data.userid].realtime = false;

        $('#mapper' + data.userid).removeClass('littleRtOn').addClass('littleRtOff');

        window.realtime.notifyUser(data.username + ' just turned off realtime');
    });

    socket.on('maps-' + mapid, function (data) {

        //as long as you weren't the origin of the changes, update your map
        if (data.origin != userid && goRealtime) {
            if (data.resource == 'Topic') {
                topic = $.parseJSON(data.obj);

                if (data.action == 'create') {
                    window.realtime.addTopicToMap(topic);
                } else if (data.action == 'update' && Mconsole.graph.getNode(topic.id) != 'undefined') {
                    window.realtime.updateTopicOnMap(topic);
                } else if (data.action == 'destroy' && Mconsole.graph.getNode(topic.id) != 'undefined') {
                    hideNode(topic.id)
                }

                return;
            } else if (data.resource == 'Synapse') {
                synapse = $.parseJSON(data.obj);

                if (data.action == 'create') {
                    window.realtime.addSynapseToMap(synapse);
                } else if (data.action == 'update' &&
                    Mconsole.graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']) != 'undefined') {
                    window.realtime.updateSynapseOnMap(synapse);
                } else if (data.action == 'destroy' &&
                    Mconsole.graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']) != 'undefined') {
                    var edge = Mconsole.graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']);
                    hideEdge(edge);
                }

                return;
            }
        }
    });
};

window.realtime.sendRealtimeOn = function () {
    // send this new mapper back your details, and the awareness that you're online
    var update = {
        username: username,
        userid: userid,
        mapid: mapid
    };
    window.realtime.socket.emit('notifyStartRealtime', update);
}

window.realtime.sendRealtimeOff = function () {
    // send this new mapper back your details, and the awareness that you're online
    var update = {
        username: username,
        userid: userid,
        mapid: mapid
    };
    window.realtime.socket.emit('notifyStopRealtime', update);
}

window.realtime.addTopicToMap = function (topic) {
    var newPos, tempForT;
    Mconsole.graph.addNode(topic);
    tempForT = Mconsole.graph.getNode(topic.id);
    tempForT.setData('dim', 1, 'start');
    tempForT.setData('dim', 25, 'end');
    newPos = new $jit.Complex();
    newPos.x = tempForT.data.$xloc;
    newPos.y = tempForT.data.$yloc;
    tempForT.setPos(newPos, 'start');
    tempForT.setPos(newPos, 'current');
    tempForT.setPos(newPos, 'end');
    Mconsole.fx.plotNode(tempForT, Mconsole.canvas);
    return Mconsole.labels.plotLabel(Mconsole.canvas, tempForT, Mconsole.config);
};

window.realtime.updateTopicOnMap = function (topic) {
    var newPos, tempForT;
    tempForT = Mconsole.graph.getNode(topic.id);
    tempForT.data = topic.data;
    tempForT.name = topic.name;
    if (MetamapsModel.showcardInUse === topic.id) {
        populateShowCard(tempForT);
    }
    newPos = new $jit.Complex();
    newPos.x = tempForT.data.$xloc;
    newPos.y = tempForT.data.$yloc;
    tempForT.setPos(newPos, 'start');
    tempForT.setPos(newPos, 'current');
    tempForT.setPos(newPos, 'end');
    return Mconsole.fx.animate({
        modes: ['linear', 'node-property:dim', 'edge-property:lineWidth'],
        transition: $jit.Trans.Quad.easeInOut,
        duration: 500
    });
};

window.realtime.addSynapseToMap = function (synapse) {
    var Node1, Node2, tempForS;
    Node1 = Mconsole.graph.getNode(synapse.data.$direction[0]);
    Node2 = Mconsole.graph.getNode(synapse.data.$direction[1]);
    Mconsole.graph.addAdjacence(Node1, Node2, {});
    tempForS = Mconsole.graph.getAdjacence(Node1.id, Node2.id);
    tempForS.setDataset('start', {
        lineWidth: 0.4
    });
    tempForS.setDataset('end', {
        lineWidth: 2
    });
    tempForS.data = synapse.data;
    Mconsole.fx.plotLine(tempForS, Mconsole.canvas);
    return Mconsole.fx.animate({
        modes: ['linear', 'node-property:dim', 'edge-property:lineWidth'],
        transition: $jit.Trans.Quad.easeInOut,
        duration: 500
    });
};

window.realtime.updateSynapseOnMap = function (synapse) {
    var k, tempForS, v, wasShowDesc, _ref;
    tempForS = Mconsole.graph.getAdjacence(synapse.data.$direction[0], synapse.data.$direction[1]);
    wasShowDesc = tempForS.data.$showDesc;
    _ref = synapse.data;
    for (k in _ref) {
        v = _ref[k];
        tempForS.data[k] = v;
    }
    tempForS.data.$showDesc = wasShowDesc;
    if (MetamapsModel.edgecardInUse === synapse.data.$id) {
        editEdge(tempForS, false);
    }
    return Mconsole.plot();
};<commit_msg>fixed issue where adding multiple versions of the same person to the realtime list<commit_after>window.realtime = {};

window.realtime.notifyTimeOut = null;
window.realtime.notifyUser = function (message) {
    if ($('.notice.metamaps').length == 0) {
        $('body').prepend('
');
    }
    $('.notice.metamaps').hide().html(message).fadeIn('fast');

    clearTimeout(window.realtime.notifyTimeOut);
    window.realtime.notifyTimeOut = setTimeout(function () {
        $('.notice.metamaps').fadeOut('fast');
    }, 8000);
};

window.realtime.setupSocket = function () {
    var socket = window.realtime.socket;

    socket.emit('newMapperNotify', {
        userid: userid,
        username: username,
        mapid: mapid
    });

    // if you're the 'new guy' update your list with who's already online
    socket.on(userid + '-' + mapid + '-UpdateMapperList', function (data) {
        // data.userid
        // data.username
        // data.userrealtime

        MetamapsModel.mappersOnMap[data.userid] = {
            name: data.username,
            realtime: data.userrealtime
        };

        var onOff = data.userrealtime ? "On" : "Off";
        var mapperListItem = '
' + data.username + '
';
        $('#mapper' + data.userid).remove();
        $('.realtimeMapperList ul').append(mapperListItem);
    });

    // receive word that there's a new mapper on the map
    socket.on('maps-' + mapid + '-newmapper', function (data) {
        // data.userid
        // data.username

        MetamapsModel.mappersOnMap[data.userid] = {
            name: data.username,
            realtime: false
        };

        var mapperListItem = '
' + data.username + '
';
        $('#mapper' + data.userid).remove();
        $('.realtimeMapperList ul').append(mapperListItem);

        window.realtime.notifyUser(data.username + ' just joined the map');

        // send this new mapper back your details, and the awareness that you've loaded the map
        var update = {
            userToNotify: data.userid,
            username: username,
            userid: userid,
            userrealtime: goRealtime,
            mapid: mapid
        };
        socket.emit('updateNewMapperList', update);
    });

    // receive word that a mapper left the map
    socket.on('maps-' + mapid + '-lostmapper', function (data) {
        // data.userid
        // data.username

        delete MetamapsModel.mappersOnMap[data.userid];

        $('#mapper' + data.userid).remove();

        window.realtime.notifyUser(data.username + ' just left the map');
    });

    // receive word that there's a mapper turned on realtime
    socket.on('maps-' + mapid + '-newrealtime', function (data) {
        // data.userid
        // data.username

        MetamapsModel.mappersOnMap[data.userid].realtime = true;

        $('#mapper' + data.userid).removeClass('littleRtOff').addClass('littleRtOn');

        window.realtime.notifyUser(data.username + ' just turned on realtime');
    });

    // receive word that there's a mapper turned on realtime
    socket.on('maps-' + mapid + '-lostrealtime', function (data) {
        // data.userid
        // data.username

        MetamapsModel.mappersOnMap[data.userid].realtime = false;

        $('#mapper' + data.userid).removeClass('littleRtOn').addClass('littleRtOff');

        window.realtime.notifyUser(data.username + ' just turned off realtime');
    });

    socket.on('maps-' + mapid, function (data) {

        //as long as you weren't the origin of the changes, update your map
        if (data.origin != userid && goRealtime) {
            if (data.resource == 'Topic') {
                topic = $.parseJSON(data.obj);

                if (data.action == 'create') {
                    window.realtime.addTopicToMap(topic);
                } else if (data.action == 'update' && Mconsole.graph.getNode(topic.id) != 'undefined') {
                    window.realtime.updateTopicOnMap(topic);
                } else if (data.action == 'destroy' && Mconsole.graph.getNode(topic.id) != 'undefined') {
                    hideNode(topic.id)
                }

                return;
            } else if (data.resource == 'Synapse') {
                synapse = $.parseJSON(data.obj);

                if (data.action == 'create') {
                    window.realtime.addSynapseToMap(synapse);
                } else if (data.action == 'update' &&
                    Mconsole.graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']) != 'undefined') {
                    window.realtime.updateSynapseOnMap(synapse);
                } else if (data.action == 'destroy' &&
                    Mconsole.graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']) != 'undefined') {
                    var edge = Mconsole.graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']);
                    hideEdge(edge);
                }

                return;
            }
        }
    });
};

window.realtime.sendRealtimeOn = function () {
    // send this new mapper back your details, and the awareness that you're online
    var update = {
        username: username,
        userid: userid,
        mapid: mapid
    };
    window.realtime.socket.emit('notifyStartRealtime', update);
}

window.realtime.sendRealtimeOff = function () {
    // send this new mapper back your details, and the awareness that you're online
    var update = {
        username: username,
        userid: userid,
        mapid: mapid
    };
    window.realtime.socket.emit('notifyStopRealtime', update);
}

window.realtime.addTopicToMap = function (topic) {
    var newPos, tempForT;
    Mconsole.graph.addNode(topic);
    tempForT = Mconsole.graph.getNode(topic.id);
    tempForT.setData('dim', 1, 'start');
    tempForT.setData('dim', 25, 'end');
    newPos = new $jit.Complex();
    newPos.x = tempForT.data.$xloc;
    newPos.y = tempForT.data.$yloc;
    tempForT.setPos(newPos, 'start');
    tempForT.setPos(newPos, 'current');
    tempForT.setPos(newPos, 'end');
    Mconsole.fx.plotNode(tempForT, Mconsole.canvas);
    return Mconsole.labels.plotLabel(Mconsole.canvas, tempForT, Mconsole.config);
};

window.realtime.updateTopicOnMap = function (topic) {
    var newPos, tempForT;
    tempForT = Mconsole.graph.getNode(topic.id);
    tempForT.data = topic.data;
    tempForT.name = topic.name;
    if (MetamapsModel.showcardInUse === topic.id) {
        populateShowCard(tempForT);
    }
    newPos = new $jit.Complex();
    newPos.x = tempForT.data.$xloc;
    newPos.y = tempForT.data.$yloc;
    tempForT.setPos(newPos, 'start');
    tempForT.setPos(newPos, 'current');
    tempForT.setPos(newPos, 'end');
    return Mconsole.fx.animate({
        modes: ['linear', 'node-property:dim', 'edge-property:lineWidth'],
        transition: $jit.Trans.Quad.easeInOut,
        duration: 500
    });
};

window.realtime.addSynapseToMap = function (synapse) {
    var Node1, Node2, tempForS;
    Node1 = Mconsole.graph.getNode(synapse.data.$direction[0]);
    Node2 = Mconsole.graph.getNode(synapse.data.$direction[1]);
    Mconsole.graph.addAdjacence(Node1, Node2, {});
    tempForS = Mconsole.graph.getAdjacence(Node1.id, Node2.id);
    tempForS.setDataset('start', {
        lineWidth: 0.4
    });
    tempForS.setDataset('end', {
        lineWidth: 2
    });
    tempForS.data = synapse.data;
    Mconsole.fx.plotLine(tempForS, Mconsole.canvas);
    return Mconsole.fx.animate({
        modes: ['linear', 'node-property:dim', 'edge-property:lineWidth'],
        transition: $jit.Trans.Quad.easeInOut,
        duration: 500
    });
};

window.realtime.updateSynapseOnMap = function (synapse) {
    var k, tempForS, v, wasShowDesc, _ref;
    tempForS = Mconsole.graph.getAdjacence(synapse.data.$direction[0], synapse.data.$direction[1]);
    wasShowDesc = tempForS.data.$showDesc;
    _ref = synapse.data;
    for (k in _ref) {
        v = _ref[k];
        tempForS.data[k] = v;
    }
    tempForS.data.$showDesc = wasShowDesc;
    if (MetamapsModel.edgecardInUse === synapse.data.$id) {
        editEdge(tempForS, false);
    }
    return Mconsole.plot();
};<|endoftext|>


<commit_before>/*global config:true, task:true*/
module.exports = function( grunt ) {

grunt.loadNpmTasks( "grunt-git-authors" );

grunt.initConfig({
	pkg: '<json:package.json>',
	qunit: {
		qunit: [
			'test/index.html',
			'test/async.html'
			// TODO figure out why this fails on our Jenkins server (Linux)
			// 'test/logs.html'
		],
		addons: [
			'addons/canvas/canvas.html',
			'addons/close-enough/close-enough.html',
			'addons/composite/composite-demo-test.html'
			// TODO same as above
			// 'addons/step/step.html'
		]
	},
	lint: {
		qunit: 'qunit/qunit.js',
		addons: 'addons/**.js',
		tests: 'test/**.js',
		grunt: 'grunt.js'
	},
	// TODO remove this once grunt 0.4 is out, see jquery-ui for other details
	jshint: (function() {
		function parserc( path ) {
			var rc = grunt.file.readJSON( (path || "") + ".jshintrc" ),
				settings = {
					options: rc,
					globals: {}
				};

			(rc.predef || []).forEach(function( prop ) {
				settings.globals[ prop ] = true;
			});
			delete rc.predef;

			return settings;
		}

		return {
			qunit: parserc( "qunit/" ),
			addons: parserc( "addons/" ),
			tests: parserc( "test/" )
		};
	})()
});

grunt.registerTask( "build-git", function( sha ) {
	function processor( content ) {
		var tagline = " - A JavaScript Unit Testing Framework";
		return content.replace( tagline, "-" + sha + " " + grunt.template.today('isoDate') + tagline );
	}
	grunt.file.copy( "qunit/qunit.css", "dist/qunit-git.css", {
		process: processor
	});
	grunt.file.copy( "qunit/qunit.js", "dist/qunit-git.js", {
		process: processor
	});
});

grunt.registerTask( "testswarm", function( commit, configFile ) {
	var testswarm = require( "testswarm" ),
		config = grunt.file.readJSON( configFile ).qunit,
		runs = {},
		done = this.async();
	["index", "async"].forEach(function (suite) {
		runs[suite] = config.testUrl + commit + "/test/" + suite + ".html";
	});
	testswarm.createClient( {
		url: config.swarmUrl,
		pollInterval: 10000,
		timeout: 1000 * 60 * 30
	} )
	.addReporter( testswarm.reporters.cli )
	.auth( {
		id: config.authUsername,
		token: config.authToken
	} )
	.addjob(
		{
			name: 'QUnit commit #' + commit.substr( 0, 10 ) + '',
			runs: runs,
			browserSets: config.browserSets
		}, function( err, passed ) {
			if ( err ) {
				grunt.log.error( err );
			}
			done( passed );
		}
	);
});

grunt.registerTask('default', 'lint qunit');

};
<commit_msg>Test: Temporary fix for jzaefferer/node-testswarm#9.<commit_after>/*global config:true, task:true*/
module.exports = function( grunt ) {

grunt.loadNpmTasks( "grunt-git-authors" );

grunt.initConfig({
	pkg: '<json:package.json>',
	qunit: {
		qunit: [
			'test/index.html',
			'test/async.html'
			// TODO figure out why this fails on our Jenkins server (Linux)
			// 'test/logs.html'
		],
		addons: [
			'addons/canvas/canvas.html',
			'addons/close-enough/close-enough.html',
			'addons/composite/composite-demo-test.html'
			// TODO same as above
			// 'addons/step/step.html'
		]
	},
	lint: {
		qunit: 'qunit/qunit.js',
		addons: 'addons/**.js',
		tests: 'test/**.js',
		grunt: 'grunt.js'
	},
	// TODO remove this once grunt 0.4 is out, see jquery-ui for other details
	jshint: (function() {
		function parserc( path ) {
			var rc = grunt.file.readJSON( (path || "") + ".jshintrc" ),
				settings = {
					options: rc,
					globals: {}
				};

			(rc.predef || []).forEach(function( prop ) {
				settings.globals[ prop ] = true;
			});
			delete rc.predef;

			return settings;
		}

		return {
			qunit: parserc( "qunit/" ),
			addons: parserc( "addons/" ),
			tests: parserc( "test/" )
		};
	})()
});

grunt.registerTask( "build-git", function( sha ) {
	function processor( content ) {
		var tagline = " - A JavaScript Unit Testing Framework";
		return content.replace( tagline, "-" + sha + " " + grunt.template.today('isoDate') + tagline );
	}
	grunt.file.copy( "qunit/qunit.css", "dist/qunit-git.css", {
		process: processor
	});
	grunt.file.copy( "qunit/qunit.js", "dist/qunit-git.js", {
		process: processor
	});
});

grunt.registerTask( "testswarm", function( commit, configFile ) {
	var testswarm = require( "testswarm" ),
		config = grunt.file.readJSON( configFile ).qunit,
		runs = {},
		done = this.async();
	["index", "async"].forEach(function (suite) {
		runs[suite] = config.testUrl + commit + "/test/" + suite + ".html";
	});
	testswarm.createClient( {
		url: config.swarmUrl,
		pollInterval: 10000,
		timeout: 1000 * 60 * 30
	} )
	.addReporter( testswarm.reporters.cli )
	.auth( {
		id: config.authUsername,
		token: config.authToken
	} )
	.addjob(
		{
			name: 'QUnit commit #' + commit.substr( 0, 10 ) + '',
			runs: runs,
			browserSets: config.browserSets
		}, function( err, passed ) {
			if ( err ) {
				grunt.log.error( err );
			}
			done( passed === true );
		}
	);
});

grunt.registerTask('default', 'lint qunit');

};
<|endoftext|>


<commit_before>/* file: learning.js
 * authors: H. Bouakaz, S. van Vliet, S. de Jong & E. Werkema
 * date: 25/3/2016
 * version 1.2
 *
 * Description:
 * Main script for initiating the learning app.
 */

/*jshint esversion: 6 */
define(['jquery', 'app/lang', 'app/string', 'bootstrap', 'app/config', 'app/database', 'app/messages', 'app/question', 'app/timer', 'app/ready', 'app/user', 'app/time', 'app/keys'], function ($, lang, string, bootstrap, config, db, messages, questions, timer, ready, user, time, keys) {
  var waitingForEnter = false;

  function disableAutocomplete() {
    $('input').attr('autocomplete', 'off');
  }

	function inputIsEmpty() {
		return $.trim($("#answer").val()).length === 0;
	}

	function prepareAnswerField() {
	  $( "#answer" ).prop("disabled", false);
    $( "#answer" ).val( "" );
    $( "#answer" ).focus();
  }

  function nextQuestion() {
    clearTimeout(timeout);
    timer.clearCountdown();
    messages.clear();
    questions.nextQuestion();

    questions.show();
    waitingForEnter = false;
  }

  function handleEnter() {
    if (waitingForEnter) {
      nextQuestion();
    } else if (!inputIsEmpty()) {
      $( "#answer" ).prop("disabled", true);
      questions.checkAnswer();
      waitingForEnter = true;
      timeout = setTimeout(nextQuestion,time.secondsToMilliseconds( $(".countdown").data("seconds") ) );
    }
  }

  function formatFactList(items) {
    var newList = [];
    items.forEach(function(item) {
      newItem = {
        id: item.item_id,
        text: item.item_question,
        answer: item.item_answer,
        hint: item.item_hint
      };
      newList.push(newItem);
    });
    return newList;
  }

	// Write localisable text to the page
	string.fillinTextClasses();
	$("#answer").prop("placeholder", lang("placeholder_typeanswerhere"));

  disableAutocomplete();

	// Replace user data in view from database
	$("span[data-replace]").each(function() {
		var user_info = $(this).data("replace");
		var text = user.get(user_info);
		$(this).html(text);
	});
	$("span[data-username]").html(user.get("user_firstname")+" "+user.get("user_lastname"));

  // When the page is loaded we get the datasetId from the page url and load the dataset from the database
  ready.on(function() {
    var url = window.location.href;
    var datasetId = url.substring(url.indexOf('?')+1);
    var factList = formatFactList(db.getQuery("getDatasetItems",[datasetId]));
    questions.initialize(factList);
  	questions.show();

    timer.startTimer(".timer", config.constant("TIME_LIMIT"));
  });

  // Temporary hint button
  $("#hintButton").click(function() {
    if (questions.hint()!=="")
      messages.showHint(questions.hint());
  });

  // Read the user input when the Enter key is pressed and evaluate it.
  // Then show the next question.
  $(document).bind("keypress", function (e) {
  	if (e.keyCode == keys.ENTER) {
      handleEnter();
  	}
  });
});
<commit_msg>added functions to learning.js<commit_after>/* file: learning.js
 * authors: H. Bouakaz, S. van Vliet, S. de Jong & E. Werkema
 * date: 25/3/2016
 * version 1.2
 *
 * Description:
 * Main script for initiating the learning app.
 */

/*jshint esversion: 6 */
define(['jquery', 'app/lang', 'app/string', 'bootstrap', 'app/config', 'app/database', 'app/messages', 'app/question', 'app/timer', 'app/ready', 'app/user', 'app/time', 'app/keys'], function ($, lang, string, bootstrap, config, db, messages, questions, timer, ready, user, time, keys) {
  var waitingForEnter = false;

  function disableAutocomplete() {
    $('input').attr('autocomplete', 'off');
  }

	function inputIsEmpty() {
		return $.trim($("#answer").val()).length === 0;
	}

	function prepareAnswerField() {
	  $( "#answer" ).prop("disabled", false);
    $( "#answer" ).val( "" );
    $( "#answer" ).focus();
  }

  function nextQuestion() {
    clearTimeout(timeout);
    timer.clearCountdown();
    messages.clear();
    questions.nextQuestion();

    questions.show();
    waitingForEnter = false;
  }

  function handleEnter() {
    if (waitingForEnter) {
      nextQuestion();
    } else if (!inputIsEmpty()) {
      $( "#answer" ).prop("disabled", true);
      questions.checkAnswer();
      waitingForEnter = true;
      timeout = setTimeout(nextQuestion,time.secondsToMilliseconds( $(".countdown").data("seconds") ) );
    }
  }

  function formatFactList(items) {
    var newList = [];
    items.forEach(function(item) {
      newItem = {
        id: item.item_id,
        text: item.item_question,
        answer: item.item_answer,
        hint: item.item_hint
      };
      newList.push(newItem);
    });
    return newList;
  }

	// Write localisable text to the page
	string.fillinTextClasses();
	$("#answer").prop("placeholder", lang("placeholder_typeanswerhere"));

  disableAutocomplete();

	// Replace user data in view from database
	$("span[data-replace]").each(function() {
		var user_info = $(this).data("replace");
		var text = user.get(user_info);
		$(this).html(text);
	});
	$("span[data-username]").html(user.get("user_firstname")+" "+user.get("user_lastname"));

  function getDatasetIdFromURL(url) {
  var datasetId = url.substring(url.indexOf('?')+1);
  return datasetId;
	}

	function retrieveDataSet(datasetId) {
  var factList = formatFactList(db.getQuery("getDatasetItems",[datasetId]));
  return factList;
	}

  // When the page is loaded we get the datasetId from the page url and load the dataset from the database
  ready.on(function() {
    var url = window.location.href;
    var datasetId = getDatasetIdFromURL(url);
    var factList = retrieveDataSet(datasetId)

    questions.initialize(factList);
  	questions.show();

    timer.startTimer(".timer", config.constant("TIME_LIMIT"));
  });

  // Temporary hint button
  $("#hintButton").click(function() {
    if (questions.hint()!=="")
      messages.showHint(questions.hint());
  });

  // Read the user input when the Enter key is pressed and evaluate it.
  // Then show the next question.
  $(document).bind("keypress", function (e) {
  	if (e.keyCode == keys.ENTER) {
      handleEnter();
  	}
  });
});
<|endoftext|>