<commit_before>/**
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * http://code.google.com/p/google-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 Math blocks for Blockly.
 * @author fraser@google.com (Neil Fraser)
 * Due to the frequency of long strings, the 80-column wrap rule need not apply
 * to language files.
 */

if (!Blockly.Language) {
  Blockly.Language = {};
}

Blockly.Language.math_number = {
  // Numeric value.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Number',
  init: function() {
    this.setColour(230);
    this.addTitle(new Blockly.FieldTextInput('0', function(text) {
      // Ensure that only a number may be entered.
      // TODO: Handle cases like 'o', 'ten', '1,234', '3,14', etc.
      var n = window.parseFloat(text || 0);
      return window.isNaN(n) ? null : String(n);
    }));
    this.setOutput(true);
    this.setTooltip('A number.');
  }
};

Blockly.Language.math_arithmetic = {
  // Basic arithmetic operator.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Arithmetic',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    this.addInput('', '', Blockly.INPUT_VALUE);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [
          thisBlock.MSG_ADD,
          thisBlock.MSG_MINUS,
          thisBlock.MSG_MULTIPLY,
          thisBlock.MSG_DIVIDE,
          thisBlock.MSG_POW
        ];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setInputsInline(true);
    this.setTooltip(function() {
      switch (thisBlock.getValueLabel(1)) {
        case thisBlock.MSG_ADD:
          return 'Return the sum of the two numbers.';
        case thisBlock.MSG_MINUS:
          return 'Return the difference of the two numbers.';
        case thisBlock.MSG_MULTIPLY:
          return 'Return the product of the two numbers.';
        case thisBlock.MSG_DIVIDE:
          return 'Return the quotient of the two numbers.';
        case thisBlock.MSG_POW:
          return 'Return the first number raised to\nthe power of the second number.';
      }
      return '';
    });
  },
  MSG_ADD: '+',
  MSG_MINUS: '-',
  MSG_MULTIPLY: '\u00D7',
  MSG_DIVIDE: '\u00F7',
  MSG_POW: '^'
};

Blockly.Language.math_change = {
  // Add to a variable in place.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Negation',
  init: function() {
    this.setColour(230);
    this.addTitle('change');
    this.addTitle(new Blockly.FieldDropdown(
        Blockly.Variables.dropdownCreate, Blockly.Variables.dropdownChange))
        .setText('item');
    this.addInput('by', '', Blockly.INPUT_VALUE);
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      return 'Add a number to variable "' + thisBlock.getTitleText(1) + '".';
    });
  },
  getVars: function() {
    return [this.getTitleText(1)];
  },
  renameVar: function(oldName, newName) {
    if (Blockly.Variables.nameEquals(oldName, this.getTitleText(1))) {
      this.setTitleText(newName, 1);
    }
  }
};

Blockly.Language.math_single = {
  // Advanced math operators with single operand.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Square_root',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [thisBlock.MSG_ROOT,
              thisBlock.MSG_ABS,
              thisBlock.MSG_NEG,
              thisBlock.MSG_LN,
              thisBlock.MSG_LOG10,
              thisBlock.MSG_EXP,
              thisBlock.MSG_10POW];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setTooltip(function() {
      switch (thisBlock.getValueLabel(0)) {
        case thisBlock.MSG_ROOT:
          return 'Return the square root of a number.';
        case thisBlock.MSG_ABS:
          return 'Return the absolute value of a number.';
        case thisBlock.MSG_NEG:
          return 'Return the negation of a number.';
        case thisBlock.MSG_LN:
          return 'Return the natural logarithm of a number.';
        case thisBlock.MSG_LOG10:
          return 'Return the base 10 logarithm of a number.';
        case thisBlock.MSG_EXP:
          return 'Return e to the power of a number.';
        case thisBlock.MSG_10POW:
          return 'Return 10 to the power of a number.';
      }
      return '';
    });
  },
  MSG_ROOT: 'square root',
  MSG_ABS: 'absolute',
  MSG_NEG: '-',
  MSG_LN: 'ln',
  MSG_LOG10: 'log10',
  MSG_EXP: 'e^',
  MSG_10POW: '10^'
};

Blockly.Language.math_round = {
  // Rounding functions.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Rounding',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [thisBlock.MSG_ROUND,
              thisBlock.MSG_ROUNDUP,
              thisBlock.MSG_ROUNDDOWN];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setTooltip('Round a number up or down.');
  },
  MSG_ROUND: 'round',
  MSG_ROUNDUP: 'round up',
  MSG_ROUNDDOWN: 'round down'
};

Blockly.Language.math_trig = {
  // Trigonometry operators.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Square_root',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [thisBlock.MSG_SIN,
              thisBlock.MSG_COS,
              thisBlock.MSG_TAN,
              thisBlock.MSG_ASIN,
              thisBlock.MSG_ACOS,
              thisBlock.MSG_ATAN];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setTooltip(function() {
      switch (thisBlock.getValueLabel(0)) {
        case thisBlock.MSG_SIN:
          return 'Return the sine of a degree.';
        case thisBlock.MSG_COS:
          return 'Return the cosine of a degree.';
        case thisBlock.MSG_TAN:
          return 'Return the tangent of a degree.';
        case thisBlock.MSG_ASIN:
          return 'Return the arcsine of a number.';
        case thisBlock.MSG_ACOS:
          return 'Return the arccosine of a number.';
        case thisBlock.MSG_ATAN:
          return 'Return the arctangent of a number.';
      }
      return '';
    });
  },
  MSG_SIN: 'sin',
  MSG_COS: 'cos',
  MSG_TAN: 'tan',
  MSG_ASIN: 'asin',
  MSG_ACOS: 'acos',
  MSG_ATAN: 'atan'
};

Blockly.Language.math_on_list = {
    // Evaluate a list of numbers to return sum, average, min, max, etc.
    category: 'Math',
    helpUrl: '',
    init: function() {
      // Assign 'this' to a variable for use in the closures below.
      var thisBlock = this;
      this.setColour('baby');
      this.setOutput(true);
      var dropdown = new Blockly.FieldDropdown(thisBlock.MSG_SUM, function() {
        return [thisBlock.MSG_SUM,
                thisBlock.MSG_MIN,
                thisBlock.MSG_MAX,
                thisBlock.MSG_AVERAGE,
                thisBlock.MSG_MEDIAN,
                thisBlock.MSG_MODE,
                thisBlock.MSG_STD_DEV,
                thisBlock.MSG_RANDOM_ITEM
                ];
      });
      this.addInput(dropdown, '', Blockly.INPUT_VALUE);
      this.setTooltip('Evaluate a list of numbers and return a member,\nor an aggregated result.');
    },
    MSG_SUM: 'sum',
    MSG_MIN: 'min',
    MSG_MAX: 'max',
    MSG_AVERAGE: 'average',
    MSG_MEDIAN: 'median',
    MSG_MODE: 'mode',
    MSG_STD_DEV: 'standard deviation',
    MSG_RANDOM_ITEM: 'random item from'
  };

Blockly.Language.math_modulo = {
  // Remainder of a division.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Modulo_operation',
  init: function() {
    this.setColour(230);
    this.setOutput(true);
    this.addInput('remainder of', '', Blockly.INPUT_VALUE);
    this.addInput('\u00F7', '', Blockly.INPUT_VALUE);
    this.setInputsInline(true);
    this.setTooltip('Return the remainder of dividing both numbers.');
  }
};

Blockly.Language.math_random_int = {
  // Random integer between [X] and [Y].
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Random_number_generation',
  init: function() {
    this.setColour(230);
    this.setOutput(true);
    this.addTitle('random integer');
    this.addInput('from', '', Blockly.INPUT_VALUE);
    this.addInput('to', '', Blockly.INPUT_VALUE);
    // TODO: Ensure that only number blocks may used to set range.
    this.setInputsInline(true);
    this.setTooltip('Return a random integer between the two\n specified limits, inclusive.');
  }
};

Blockly.Language.math_random_float = {
  // Random fraction between 0 and 1.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Random_number_generation',
  init: function() {
    this.setColour(230);
    this.setOutput(true);
    this.addTitle('random fraction');
    this.setTooltip('Return a random fraction between\n0.0 (inclusive) and 1.0 (exclusive).');
  }
};
<commit_msg>Change colour on math_on_list to match Math blocks. Add comment.<commit_after>/**
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * http://code.google.com/p/google-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 Math blocks for Blockly.
 * @author fraser@google.com (Neil Fraser)
 * Due to the frequency of long strings, the 80-column wrap rule need not apply
 * to language files.
 */

if (!Blockly.Language) {
  Blockly.Language = {};
}

Blockly.Language.math_number = {
  // Numeric value.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Number',
  init: function() {
    this.setColour(230);
    this.addTitle(new Blockly.FieldTextInput('0', function(text) {
      // Ensure that only a number may be entered.
      // TODO: Handle cases like 'o', 'ten', '1,234', '3,14', etc.
      var n = window.parseFloat(text || 0);
      return window.isNaN(n) ? null : String(n);
    }));
    this.setOutput(true);
    this.setTooltip('A number.');
  }
};

Blockly.Language.math_arithmetic = {
  // Basic arithmetic operator.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Arithmetic',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    this.addInput('', '', Blockly.INPUT_VALUE);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [
          thisBlock.MSG_ADD,
          thisBlock.MSG_MINUS,
          thisBlock.MSG_MULTIPLY,
          thisBlock.MSG_DIVIDE,
          thisBlock.MSG_POW
        ];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setInputsInline(true);
    this.setTooltip(function() {
      switch (thisBlock.getValueLabel(1)) {
        case thisBlock.MSG_ADD:
          return 'Return the sum of the two numbers.';
        case thisBlock.MSG_MINUS:
          return 'Return the difference of the two numbers.';
        case thisBlock.MSG_MULTIPLY:
          return 'Return the product of the two numbers.';
        case thisBlock.MSG_DIVIDE:
          return 'Return the quotient of the two numbers.';
        case thisBlock.MSG_POW:
          return 'Return the first number raised to\nthe power of the second number.';
      }
      return '';
    });
  },
  MSG_ADD: '+',
  MSG_MINUS: '-',
  MSG_MULTIPLY: '\u00D7',
  MSG_DIVIDE: '\u00F7',
  MSG_POW: '^'
};

Blockly.Language.math_change = {
  // Add to a variable in place.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Negation',
  init: function() {
    this.setColour(230);
    this.addTitle('change');
    this.addTitle(new Blockly.FieldDropdown(
        Blockly.Variables.dropdownCreate, Blockly.Variables.dropdownChange))
        .setText('item');
    this.addInput('by', '', Blockly.INPUT_VALUE);
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      return 'Add a number to variable "' + thisBlock.getTitleText(1) + '".';
    });
  },
  getVars: function() {
    return [this.getTitleText(1)];
  },
  renameVar: function(oldName, newName) {
    if (Blockly.Variables.nameEquals(oldName, this.getTitleText(1))) {
      this.setTitleText(newName, 1);
    }
  }
};

Blockly.Language.math_single = {
  // Advanced math operators with single operand.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Square_root',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [thisBlock.MSG_ROOT,
              thisBlock.MSG_ABS,
              thisBlock.MSG_NEG,
              thisBlock.MSG_LN,
              thisBlock.MSG_LOG10,
              thisBlock.MSG_EXP,
              thisBlock.MSG_10POW];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setTooltip(function() {
      switch (thisBlock.getValueLabel(0)) {
        case thisBlock.MSG_ROOT:
          return 'Return the square root of a number.';
        case thisBlock.MSG_ABS:
          return 'Return the absolute value of a number.';
        case thisBlock.MSG_NEG:
          return 'Return the negation of a number.';
        case thisBlock.MSG_LN:
          return 'Return the natural logarithm of a number.';
        case thisBlock.MSG_LOG10:
          return 'Return the base 10 logarithm of a number.';
        case thisBlock.MSG_EXP:
          return 'Return e to the power of a number.';
        case thisBlock.MSG_10POW:
          return 'Return 10 to the power of a number.';
      }
      return '';
    });
  },
  MSG_ROOT: 'square root',
  MSG_ABS: 'absolute',
  MSG_NEG: '-',
  MSG_LN: 'ln',
  MSG_LOG10: 'log10',
  MSG_EXP: 'e^',
  MSG_10POW: '10^'
};

Blockly.Language.math_round = {
  // Rounding functions.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Rounding',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [thisBlock.MSG_ROUND,
              thisBlock.MSG_ROUNDUP,
              thisBlock.MSG_ROUNDDOWN];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setTooltip('Round a number up or down.');
  },
  MSG_ROUND: 'round',
  MSG_ROUNDUP: 'round up',
  MSG_ROUNDDOWN: 'round down'
};

Blockly.Language.math_trig = {
  // Trigonometry operators.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Square_root',
  init: function() {
    // Assign 'this' to a variable for use in the closures below.
    var thisBlock = this;
    this.setColour(230);
    this.setOutput(true);
    var dropdown = new Blockly.FieldDropdown(function() {
      return [thisBlock.MSG_SIN,
              thisBlock.MSG_COS,
              thisBlock.MSG_TAN,
              thisBlock.MSG_ASIN,
              thisBlock.MSG_ACOS,
              thisBlock.MSG_ATAN];
    });
    this.addInput(dropdown, '', Blockly.INPUT_VALUE);
    this.setTooltip(function() {
      switch (thisBlock.getValueLabel(0)) {
        case thisBlock.MSG_SIN:
          return 'Return the sine of a degree.';
        case thisBlock.MSG_COS:
          return 'Return the cosine of a degree.';
        case thisBlock.MSG_TAN:
          return 'Return the tangent of a degree.';
        case thisBlock.MSG_ASIN:
          return 'Return the arcsine of a number.';
        case thisBlock.MSG_ACOS:
          return 'Return the arccosine of a number.';
        case thisBlock.MSG_ATAN:
          return 'Return the arctangent of a number.';
      }
      return '';
    });
  },
  MSG_SIN: 'sin',
  MSG_COS: 'cos',
  MSG_TAN: 'tan',
  MSG_ASIN: 'asin',
  MSG_ACOS: 'acos',
  MSG_ATAN: 'atan'
};

Blockly.Language.math_on_list = {
    // Evaluate a list of numbers to return sum, average, min, max, etc.
    // Some functions also work on text (min, max, mode, median).
    category: 'Math',
    helpUrl: '',
    init: function() {
      // Assign 'this' to a variable for use in the closures below.
      var thisBlock = this;
      this.setColour(230);
      this.setOutput(true);
      var dropdown = new Blockly.FieldDropdown(thisBlock.MSG_SUM, function() {
        return [thisBlock.MSG_SUM,
                thisBlock.MSG_MIN,
                thisBlock.MSG_MAX,
                thisBlock.MSG_AVERAGE,
                thisBlock.MSG_MEDIAN,
                thisBlock.MSG_MODE,
                thisBlock.MSG_STD_DEV,
                thisBlock.MSG_RANDOM_ITEM
                ];
      });
      this.addInput(dropdown, '', Blockly.INPUT_VALUE);
      this.setTooltip('Evaluate a list of numbers and return a member,\nor an aggregated result.');
    },
    MSG_SUM: 'sum',
    MSG_MIN: 'min',
    MSG_MAX: 'max',
    MSG_AVERAGE: 'average',
    MSG_MEDIAN: 'median',
    MSG_MODE: 'mode',
    MSG_STD_DEV: 'standard deviation',
    MSG_RANDOM_ITEM: 'random item from'
  };

Blockly.Language.math_modulo = {
  // Remainder of a division.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Modulo_operation',
  init: function() {
    this.setColour(230);
    this.setOutput(true);
    this.addInput('remainder of', '', Blockly.INPUT_VALUE);
    this.addInput('\u00F7', '', Blockly.INPUT_VALUE);
    this.setInputsInline(true);
    this.setTooltip('Return the remainder of dividing both numbers.');
  }
};

Blockly.Language.math_random_int = {
  // Random integer between [X] and [Y].
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Random_number_generation',
  init: function() {
    this.setColour(230);
    this.setOutput(true);
    this.addTitle('random integer');
    this.addInput('from', '', Blockly.INPUT_VALUE);
    this.addInput('to', '', Blockly.INPUT_VALUE);
    // TODO: Ensure that only number blocks may used to set range.
    this.setInputsInline(true);
    this.setTooltip('Return a random integer between the two\n specified limits, inclusive.');
  }
};

Blockly.Language.math_random_float = {
  // Random fraction between 0 and 1.
  category: 'Math',
  helpUrl: 'http://en.wikipedia.org/wiki/Random_number_generation',
  init: function() {
    this.setColour(230);
    this.setOutput(true);
    this.addTitle('random fraction');
    this.setTooltip('Return a random fraction between\n0.0 (inclusive) and 1.0 (exclusive).');
  }
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 Google LLC.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
import './file-pane.js';
import './output-pane.js';
import '../configuration/whitelisted.js';
import '../lib/platform/loglevel-web.js';

import {Runtime} from '../../build/runtime/runtime.js';
import {Loader} from '../../build/platform/loader.js';
import {Arc} from '../../build/runtime/arc.js';
import {IdGenerator} from '../../build/runtime/id.js';
import {pecIndustry} from '../../build/platform/pec-industry-web.js';
import {RecipeResolver} from '../../build/runtime/recipe/recipe-resolver.js';
import {StorageProviderFactory} from '../../build/runtime/storage/storage-provider-factory.js';
import {devtoolsArcInspectorFactory} from '../../build/devtools-connector/devtools-arc-inspector.js';
import {UiSlotComposer} from '../../build/runtime/ui-slot-composer.js';
import {SlotObserver} from '../lib/xen-renderer.js';

import '../../build/services/ml5-service.js';
import '../../build/services/random-service.js';

const root = '../..';
const urlMap = Runtime.mapFromRootPath(root);

// import DOM node references
const {
  filePane,
  outputPane,
  popupContainer,
  executeButton,
  toggleFilesButton,
  exportFilesButton,
  helpButton
} = window;

init();

function init() {
  filePane.init(execute, toggleFilesButton, exportFilesButton);
  executeButton.addEventListener('click', execute);
  helpButton.addEventListener('click', showHelp);
  popupContainer.addEventListener('click', () => popupContainer.style.display = 'none');

  const params = new URLSearchParams(window.location.search);
  window.logLevel = (params.get('log') !== null) ? 1 : 0;

  const manifestParam = params.get('m') || params.get('manifest');
  if (manifestParam) {
    filePane.seedManifest(manifestParam.split(';').map(m => `import '${m}'`));
    execute();
  } else {
    const exampleManifest = `\
import 'https://$particles/Tutorial/Javascript/1_HelloWorld/HelloWorld.arcs'

schema Data
  num: Number
  txt: Text

resource DataResource
  start
  [{"num": 73, "txt": "xyz"}]

store DataStore of Data in DataResource

particle P in 'a.js'
  root: consumes Slot
  data: reads Data

recipe
  h0: map DataStore
  P
    data: reads h0`;

    const exampleParticle = `
defineParticle(({SimpleParticle, html, log}) => {
  return class extends SimpleParticle {
    get template() {
      log(\`Add '?log' to the URL to enable particle logging\`);
      return html\`<span>{{num}}</span> : <span>{{str}}</span>\`;
    }
    render({data}) {
      return data ? {num: data.num, str: data.txt} : {};
    }
  };
});`;

    filePane.seedExample(exampleManifest, exampleParticle);
  }
}

function execute() {
  wrappedExecute().catch(e => outputPane.showError('Unhandled exception', e.stack));
}

async function wrappedExecute() {
  document.dispatchEvent(new Event('clear-arcs-explorer'));
  outputPane.reset();

  const loader = new Loader(urlMap, filePane.getFileMap());
  // TODO(sjmiles): should be a static method
  loader.flushCaches();

  const pecFactory = pecIndustry(loader);

  let manifest;
  try {
    const options = {loader, fileName: './manifest', throwImportErrors: true};
    manifest = await Runtime.parseManifest(filePane.getManifest(), options);
  } catch (e) {
    outputPane.showError('Error in Manifest.parse', e);
    return;
  }

  if (manifest.allRecipes.length == 0) {
    outputPane.showError('No recipes found in Manifest.parse');
  }

  let arcIndex = 1;
  for (const recipe of manifest.allRecipes) {
    const id = IdGenerator.newSession().newArcId('arc' + arcIndex++);
    const arcPanel = outputPane.addArcPanel(id);

    const errors = new Map();
    if (!recipe.normalize({errors})) {
      arcPanel.showError('Error in recipe.normalize', [...errors.values()].join('\n'));
      continue;
    }

    const slotComposer = new UiSlotComposer();
    slotComposer.observeSlots(new SlotObserver(arcPanel.shadowRoot));

    const storage = new StorageProviderFactory(id);
    const arc = new Arc({
      id,
      context: manifest,
      pecFactories: [pecFactory],
      slotComposer,
      loader,
      storageProviderFactory: storage,
      inspectorFactory: devtoolsArcInspectorFactory
    });
    arcPanel.attachArc(arc);

    recipe.normalize();

    let resolvedRecipe = null;
    if (recipe.isResolved()) {
      resolvedRecipe = recipe;
    } else {
      const resolver = new RecipeResolver(arc);
      const options = {errors: new Map()};
      resolvedRecipe = await resolver.resolve(recipe, options);
      if (!resolvedRecipe) {
        arcPanel.showError('Error in RecipeResolver', `${
          [...options.errors.entries()].join('\n')
        }.\n${recipe.toString()}`);
        continue;
      }
    }

    try {
      await arc.instantiate(resolvedRecipe);
    } catch (e) {
      arcPanel.showError('Error in arc.instantiate', e);
      continue;
    }
    const description = await Runtime.getArcDescription(arc);
    await arcPanel.arcInstantiated(description);
  }
}

function showHelp() {
  popupContainer.style.display = 'block';
  document.addEventListener('keydown', hideHelp);
}

function hideHelp(e) {
  popupContainer.style.display = 'none';
  e.preventDefault();
  document.removeEventListener('keydown', hideHelp);
}
<commit_msg>Initialize volatile storage cache in dev shell. (#4367)<commit_after>/**
 * @license
 * Copyright 2019 Google LLC.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
import './file-pane.js';
import './output-pane.js';
import '../configuration/whitelisted.js';
import '../lib/platform/loglevel-web.js';

import {Runtime} from '../../build/runtime/runtime.js';
import {Loader} from '../../build/platform/loader.js';
import {Arc} from '../../build/runtime/arc.js';
import {IdGenerator} from '../../build/runtime/id.js';
import {pecIndustry} from '../../build/platform/pec-industry-web.js';
import {RecipeResolver} from '../../build/runtime/recipe/recipe-resolver.js';
import {StorageProviderFactory} from '../../build/runtime/storage/storage-provider-factory.js';
import {devtoolsArcInspectorFactory} from '../../build/devtools-connector/devtools-arc-inspector.js';
import {UiSlotComposer} from '../../build/runtime/ui-slot-composer.js';
import {SlotObserver} from '../lib/xen-renderer.js';
import {RuntimeCacheService} from '../../build/runtime/runtime-cache.js';
import {VolatileStorage} from '../../build/runtime/storage/volatile-storage.js';

import '../../build/services/ml5-service.js';
import '../../build/services/random-service.js';

const root = '../..';
const urlMap = Runtime.mapFromRootPath(root);

// import DOM node references
const {
  filePane,
  outputPane,
  popupContainer,
  executeButton,
  toggleFilesButton,
  exportFilesButton,
  helpButton
} = window;

init();

function init() {
  VolatileStorage.setStorageCache(new RuntimeCacheService());
  filePane.init(execute, toggleFilesButton, exportFilesButton);
  executeButton.addEventListener('click', execute);
  helpButton.addEventListener('click', showHelp);
  popupContainer.addEventListener('click', () => popupContainer.style.display = 'none');

  const params = new URLSearchParams(window.location.search);
  window.logLevel = (params.get('log') !== null) ? 1 : 0;

  const manifestParam = params.get('m') || params.get('manifest');
  if (manifestParam) {
    filePane.seedManifest(manifestParam.split(';').map(m => `import '${m}'`));
    execute();
  } else {
    const exampleManifest = `\
import 'https://$particles/Tutorial/Javascript/1_HelloWorld/HelloWorld.arcs'

schema Data
  num: Number
  txt: Text

resource DataResource
  start
  [{"num": 73, "txt": "xyz"}]

store DataStore of Data in DataResource

particle P in 'a.js'
  root: consumes Slot
  data: reads Data

recipe
  h0: map DataStore
  P
    data: reads h0`;

    const exampleParticle = `
defineParticle(({SimpleParticle, html, log}) => {
  return class extends SimpleParticle {
    get template() {
      log(\`Add '?log' to the URL to enable particle logging\`);
      return html\`<span>{{num}}</span> : <span>{{str}}</span>\`;
    }
    render({data}) {
      return data ? {num: data.num, str: data.txt} : {};
    }
  };
});`;

    filePane.seedExample(exampleManifest, exampleParticle);
  }
}

function execute() {
  wrappedExecute().catch(e => outputPane.showError('Unhandled exception', e.stack));
}

async function wrappedExecute() {
  document.dispatchEvent(new Event('clear-arcs-explorer'));
  outputPane.reset();

  const loader = new Loader(urlMap, filePane.getFileMap());
  // TODO(sjmiles): should be a static method
  loader.flushCaches();

  const pecFactory = pecIndustry(loader);

  let manifest;
  try {
    const options = {loader, fileName: './manifest', throwImportErrors: true};
    manifest = await Runtime.parseManifest(filePane.getManifest(), options);
  } catch (e) {
    outputPane.showError('Error in Manifest.parse', e);
    return;
  }

  if (manifest.allRecipes.length == 0) {
    outputPane.showError('No recipes found in Manifest.parse');
  }

  let arcIndex = 1;
  for (const recipe of manifest.allRecipes) {
    const id = IdGenerator.newSession().newArcId('arc' + arcIndex++);
    const arcPanel = outputPane.addArcPanel(id);

    const errors = new Map();
    if (!recipe.normalize({errors})) {
      arcPanel.showError('Error in recipe.normalize', [...errors.values()].join('\n'));
      continue;
    }

    const slotComposer = new UiSlotComposer();
    slotComposer.observeSlots(new SlotObserver(arcPanel.shadowRoot));

    const storage = new StorageProviderFactory(id);
    const arc = new Arc({
      id,
      context: manifest,
      pecFactories: [pecFactory],
      slotComposer,
      loader,
      storageProviderFactory: storage,
      inspectorFactory: devtoolsArcInspectorFactory
    });
    arcPanel.attachArc(arc);

    recipe.normalize();

    let resolvedRecipe = null;
    if (recipe.isResolved()) {
      resolvedRecipe = recipe;
    } else {
      const resolver = new RecipeResolver(arc);
      const options = {errors: new Map()};
      resolvedRecipe = await resolver.resolve(recipe, options);
      if (!resolvedRecipe) {
        arcPanel.showError('Error in RecipeResolver', `${
          [...options.errors.entries()].join('\n')
        }.\n${recipe.toString()}`);
        continue;
      }
    }

    try {
      await arc.instantiate(resolvedRecipe);
    } catch (e) {
      arcPanel.showError('Error in arc.instantiate', e);
      continue;
    }
    const description = await Runtime.getArcDescription(arc);
    await arcPanel.arcInstantiated(description);
  }
}

function showHelp() {
  popupContainer.style.display = 'block';
  document.addEventListener('keydown', hideHelp);
}

function hideHelp(e) {
  popupContainer.style.display = 'none';
  e.preventDefault();
  document.removeEventListener('keydown', hideHelp);
}
<|endoftext|>


<commit_before>// -- More info: https://github.com/ttezel/bayes
'use strict';
import LevelUp from 'levelup';
import Bayes from 'bayes';
// -- Internal
let db = LevelUp('./store/classifier.bayes')
let classifier = undefined;
db.get('bayes', function (error, value) {
  if (error) {
    classifier = Bayes();
  } else {
    classifier = Bayes.fromJson(value)
  }
})

export default {
  learn: (phrase, language, category) => {
    classifier.learn(phrase, category);
    return new Promise((resolve, reject) => {
      db.put('bayes', classifier.toJson(), (error) => {
        error ? reject(error) : resolve(category);
      });
    });
  },

  categorize: (phrase, language) => {
    return new Promise((resolve, reject) => {
      resolve(classifier.categorize(phrase));
    });
  }
};
<commit_msg>Classifier bayes with store (LevelUp)<commit_after>// -- More info: https://github.com/ttezel/bayes
'use strict';
import LevelUp from 'levelup';
import Bayes from 'bayes';
// -- Internal
let db = LevelUp('./store/classifier.bayes');
const classifierForLanguage = (key) => {
  return new Promise((resolve, reject) => {
    db.get(key, (error, value) => {
      if (error) {
        resolve(Bayes());
      } else {
        resolve(Bayes.fromJson(value));
      }
    });
  });
};

export default {
  learn: async (phrase, language, category) => {
    let classifier = await classifierForLanguage(language);
    classifier.learn(phrase, category);
    db.put(language, classifier.toJson());
  },

  categorize: async (phrase, language) => {
    const time = new Date();
    let classifier = await classifierForLanguage(language);
    return {
      engine: 'bayes',
      ms: (new Date() - time),
      category: classifier.categorize(phrase)
    };
  }
};
<|endoftext|>


<commit_before>/**
 * @author Jordi Torres
 */

OSG.globalify();

var minExtent = [ -1000000.0, -1000000.0 ];
var maxExtent = [ 1000000.0, 1000000.0 ];

var main = function () {

    // The 3D canvas.
    var canvas = document.getElementById( "3DView" );
    var w = window.innerWidth;
    var h = window.innerHeight;
    osg.log( "size " + w + " x " + h );
    canvas.style.width = w;
    canvas.style.height = h;
    canvas.width = w;
    canvas.height = h;
    var viewer;
    var size = 10;
    var node = osg.createTexturedQuadGeometry( minExtent[ 0 ], minExtent[ 1 ], 0, maxExtent[ 0 ] - minExtent[ 0 ], 0, 0, 0, maxExtent[ 1 ] - minExtent[ 1 ], 0 );

    function createTileForGeometry( i, x, y, width, height ) {

        var node = osg.createTexturedQuadGeometry( x, y, 0, width, 0, 0, 0, height, 0 );
        var materialGround = new osg.Material();
        materialGround.setAmbient( [ 1 * i / 8, 1 * i / 2 , 1 * i / 2, 1 ] );
        materialGround.setDiffuse( [ 0, 0, 0, 1 ] );
        node.getOrCreateStateSet().setAttributeAndMode( materialGround );
        return node;
    }

    function subTileLevelRowCol( subTileId, level, row, col ) {
        var x = 0;
        var y = 0; // subtileID = 0 is 0,0
        if ( subTileId === 1 ) {
            x = 1;
        } else if ( subTileId === 2 ) {
            y = 1;
        } else if ( subTileId === 3 ) {
            x = 1;
            y = 1;
        }

        sLevel = level + 1;
        sCol = col * 2 + x;
        sRow = row * 2 + y;
        return {
            sLevel: sLevel,
            sCol: sCol,
            sRow: sRow
        };
    }

    function levelRowColToXYWidthHeight( rootLevel, level, row, col ) {
        var leveldiff = level - rootLevel;
        var tileExtent = computeExtent( leveldiff, row, col );
        var width = maxx - minx;
        var height = maxy - miny;
        return {
            x: tileExtent.minx,
            y: tileExtent.miny,
            width: width,
            height: height
        };

    }

    function computeExtent( level, x, y ) {
        var numTiles = ( 1 << level );
        var width = ( maxExtent[ 0 ] - minExtent[ 0 ] ) / numTiles;
        var height = ( maxExtent[ 1 ] - minExtent[ 1 ] ) / numTiles;
        minx = minExtent[ 0 ] + x * width;
        miny = minExtent[ 1 ] + y * height;
        maxx = minx + width;
        maxy = miny + height;
        return {
            minx: minx,
            miny: miny,
            maxx: maxx,
            maxy: maxy
        };
    }

    var create = function createPagedLODGroup( parent ) {
        var group = new osg.Node();

        for ( i = 0; i < 4; i++ ) {
            var designation = subTileLevelRowCol( i, parent.level, parent.x, parent.y );
            var tileGeometry = levelRowColToXYWidthHeight( 0, designation.sLevel, designation.sRow, designation.sCol );
            // console.log('L =', designation.sLevel,' Row =', designation.sRow ,' Col =', designation.sCol);
            // console.log ('tileGeometry =', tileGeometry.x , tileGeometry.y, tileGeometry.width, tileGeometry.height);
            var node = createTileForGeometry( i, tileGeometry.x, tileGeometry.y, tileGeometry.width, tileGeometry.height );

            var plod = new osg.PagedLOD();
            plod.setRangeMode( osg.PagedLOD.PIXEL_SIZE_ON_SCREEN );
            plod.addChild( node, 0, 100000 );
            plod.setFunction( 1, create );
            plod.setRange( 1, 100000, Infinity );
            plod.level = designation.sLevel;
            plod.x = designation.sRow;
            plod.y = designation.sCol;
            group.addChild( plod );
        }
        //console.log('l=',parent.level,' x=',parent.x,' y =',parent.y);
        return group;
    }

    // Set up the PagedLOD root level
    var plod = new osg.PagedLOD();
    plod.addChild( node, 0, 100000 );
    plod.setRangeMode( osg.PagedLOD.PIXEL_SIZE_ON_SCREEN );
    plod.level = 0;
    plod.x = 0;
    plod.y = 0;
    plod.setFunction( 1, create );
    plod.setRange( 1, 100000, Infinity );

    // The viewer
    viewer = new osgViewer.Viewer( canvas );
    viewer.init();
    viewer.setSceneData( plod );
    var bs = plod.getBound();
    viewer.setupManipulator();
    viewer.getManipulator().setDistance( bs.radius() * 1.5 );
    viewer.run();
};

window.addEventListener( "load", main, true );
<commit_msg>Reenabled frustum culling<commit_after>/**
 * @author Jordi Torres
 */

OSG.globalify();

var minExtent = [ -1000000.0, -1000000.0 ];
var maxExtent = [ 1000000.0, 1000000.0 ];

var main = function () {

    // The 3D canvas.
    var canvas = document.getElementById( "3DView" );
    var w = window.innerWidth;
    var h = window.innerHeight;
    osg.log( "size " + w + " x " + h );
    canvas.style.width = w;
    canvas.style.height = h;
    canvas.width = w;
    canvas.height = h;
    var viewer;
    var size = 10;
    var node = osg.createTexturedQuadGeometry( minExtent[ 0 ], minExtent[ 1 ], 0, maxExtent[ 0 ] - minExtent[ 0 ], 0, 0, 0, maxExtent[ 1 ] - minExtent[ 1 ], 0 );

    function createTileForGeometry( i, x, y, width, height ) {

        var node = osg.createTexturedQuadGeometry( x, y, 0, width, 0, 0, 0, height, 0 );
        var materialGround = new osg.Material();
        materialGround.setAmbient( [ 1 * i / 8, 1 * i / 2 , 1 * i / 2, 1 ] );
        materialGround.setDiffuse( [ 0, 0, 0, 1 ] );
        node.getOrCreateStateSet().setAttributeAndMode( materialGround );
        return node;
    }

    function subTileLevelRowCol( subTileId, level, row, col ) {
        var x = 0;
        var y = 0; // subtileID = 0 is 0,0
        if ( subTileId === 1 ) {
            x = 1;
        } else if ( subTileId === 2 ) {
            y = 1;
        } else if ( subTileId === 3 ) {
            x = 1;
            y = 1;
        }

        sLevel = level + 1;
        sCol = col * 2 + x;
        sRow = row * 2 + y;
        return {
            sLevel: sLevel,
            sCol: sCol,
            sRow: sRow
        };
    }

    function levelRowColToXYWidthHeight( rootLevel, level, row, col ) {
        var leveldiff = level - rootLevel;
        var tileExtent = computeExtent( leveldiff, row, col );
        var width = maxx - minx;
        var height = maxy - miny;
        return {
            x: tileExtent.minx,
            y: tileExtent.miny,
            width: width,
            height: height
        };

    }

    function computeExtent( level, x, y ) {
        var numTiles = ( 1 << level );
        var width = ( maxExtent[ 0 ] - minExtent[ 0 ] ) / numTiles;
        var height = ( maxExtent[ 1 ] - minExtent[ 1 ] ) / numTiles;
        minx = minExtent[ 0 ] + x * width;
        miny = minExtent[ 1 ] + y * height;
        maxx = minx + width;
        maxy = miny + height;
        return {
            minx: minx,
            miny: miny,
            maxx: maxx,
            maxy: maxy
        };
    }

    var create = function createPagedLODGroup( parent ) {
        var group = new osg.Node();

        for ( i = 0; i < 4; i++ ) {
            var designation = subTileLevelRowCol( i, parent.level, parent.x, parent.y );
            var tileGeometry = levelRowColToXYWidthHeight( 0, designation.sLevel, designation.sRow, designation.sCol );
            // console.log('L =', designation.sLevel,' Row =', designation.sRow ,' Col =', designation.sCol);
            // console.log ('tileGeometry =', tileGeometry.x , tileGeometry.y, tileGeometry.width, tileGeometry.height);
            var node = createTileForGeometry( i, tileGeometry.x, tileGeometry.y, tileGeometry.width, tileGeometry.height );

            var plod = new osg.PagedLOD();
            plod.setRangeMode( osg.PagedLOD.PIXEL_SIZE_ON_SCREEN );
            plod.addChild( node, 0, 100000 );
            plod.setFunction( 1, create );
            plod.setRange( 1, 100000, Infinity );
            plod.level = designation.sLevel;
            plod.x = designation.sRow;
            plod.y = designation.sCol;
            group.addChild( plod );
        }
        //console.log('l=',parent.level,' x=',parent.x,' y =',parent.y);
        return group;
    }

    // Set up the PagedLOD root level
    var plod = new osg.PagedLOD();
    plod.addChild( node, 0, 100000 );
    plod.setRangeMode( osg.PagedLOD.PIXEL_SIZE_ON_SCREEN );
    plod.level = 0;
    plod.x = 0;
    plod.y = 0;
    plod.setFunction( 1, create );
    plod.setRange( 1, 100000, Infinity );

    // The viewer
    viewer = new osgViewer.Viewer( canvas , { 'enableFrustumCulling': true } );
    viewer.init();
    viewer.setSceneData( plod );
    var bs = plod.getBound();
    viewer.setupManipulator();
    viewer.getManipulator().setDistance( bs.radius() * 1.5 );
    viewer.run();
};

window.addEventListener( "load", main, true );
<|endoftext|>


<commit_before>const querystring = require('querystring');
const formatError = require('../../lib/format-error');
const atob = require('atob');
const Boom = require('boom');
const get = require('lodash/get');
const config = require('../../../config');

module.exports = (userService, emailService, renderTemplate, clientService, RedisAdapter, userFormData) => {

  const errorMessages = {
    email: {
      'any.required': 'Email address is required',
      'any.empty': 'Email address is required',
      'string.email': 'Must be a valid email address',
    },
    password: {
      'any.empty': 'Password is required',
      'string.min': 'Password must be at least 8 characters',
    },
    pass2: {
      'any.allowOnly': 'Passwords must match'
    },
    redirect_uri: {
      'any.required': 'Redirect URI is required',
    },
    client_id: {
      'any.required': 'Client ID is required'
    },
    response_type: {
      'any.required': 'Response type is required',
    },
    scope: {
      'any.required': 'Scope is required',
    },
    token: {
      'any.required': 'Token is required',
    },
    profile: {
      'string.uri': 'Must be a valid URL',
    },
    picture: {
      'string.uri': 'Must be a valid URL',
    },
    website: {
      'string.uri': 'Must be a valid URL',
    }
  };

  const handleRegistrationPost = function(request, reply) {
    userService.create(request.payload.email, request.payload.password)
      .then(user => {
        reply.redirect(`/op/auth?${querystring.stringify(request.query)}`);
      })
      .catch(error => {
        // assume email collision and show validation message
        reply.view('user-registration', {
          title: 'Register',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: true,
          validationErrorMessages: {email: ['That email address is already in use']},
          email: request.payload.email || ''
        });
      });
  };

  const handleProfilePost = function(user, request, reply) {
    const profile = user.get('profile');
    Object.assign(profile, request.payload);
    return user.save({ profile }).then(() => {
      return reply.redirect(request.query.redirect_uri);
    });
  };

  const getValidationMessages = function(error) {
    var validationErrorMessages = {};

    if (error) {
      error = formatError(error);
      error.output.payload.validationErrors.forEach(errorObj => {
        validationErrorMessages[errorObj.key] = validationErrorMessages[errorObj.key] || [];

        if (errorMessages[errorObj.key][errorObj.type]) {
          validationErrorMessages[errorObj.key].push(errorMessages[errorObj.key][errorObj.type]);
        } else {
          validationErrorMessages[errorObj.key].push(errorObj.message);
        }
      });
    }

    return validationErrorMessages;
  };

  return {
    registerFormHandler: function(request, reply, source, error) {
      request.payload = request.payload || {};

      if (!error && request.method === 'post') {
        handleRegistrationPost(request, reply);
      } else {
        reply.view('user-registration', {
          title: 'Register',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: !!error,
          validationErrorMessages: getValidationMessages(error),
          email: request.payload.email || ''
        });
      }
    },

    profileFormHandler: function(request, reply, source, error) {
      const redisAdapter = new RedisAdapter('AccessToken');
      const clientId = request.query.clientId;
      return clientService.findById(clientId).then(client => {
        const redirectUris = client.related('redirect_uris').map(uri => uri.get('uri'));
        if (redirectUris.indexOf(request.query.redirect_uri) < 0) {
          return reply(Boom.forbidden('redirect_uri not in whitelist'));
        }
        return client;
      }).then((client) => {
        redisAdapter.find(request.query.accessToken.substr(0, 48)).then(token => {
          if (!token || token && token.signature !== request.query.accessToken.substr(48)) {
            return reply.redirect(`${request.query.redirect_uri}?error=unauthorized&error_description=invalid access token`);
          }
          const payload = JSON.parse(atob(token.payload));
          const accountId = payload.accountId;
          userService.findById(accountId).then(user => {
            if (!user) {
              return reply.redirect(`${request.query.redirect_uri}?error=user_not_found&error_description=user not found`);
            }

            const validationErrorMessages = {};
            if (!error && request.method === 'post') {
              return handleProfilePost(user, request, reply);
            } else {
              if (error) {
                error = formatError(error);
                error.output.payload.validationErrors.forEach(errorObj => {
                  validationErrorMessages[errorObj.key] = validationErrorMessages[errorObj.key] || [];
                  if (errorMessages[errorObj.key] && errorMessages[errorObj.key][errorObj.type]) {
                    validationErrorMessages[errorObj.key].push(errorMessages[errorObj.key][errorObj.type]);
                  } else {
                    validationErrorMessages[errorObj.key].push('Invalid value');
                  }
                });
              }
            }

            const profile = user.get('profile');
            const getValue = (field) => {
              return (request.payload && request.payload[field]) || get(profile, field, '');
            };
            reply.view('user-profile', {
              returnTo: request.query.redirect_uri,
              fields: [
                {
                  name: 'name',
                  label: 'Name',
                  type: 'text',
                  value: getValue('name'),
                  error: validationErrorMessages.name,
                },
                {
                  name: 'given_name',
                  label: 'Given Name',
                  type: 'text',
                  value: getValue('given_name'),
                  error: validationErrorMessages.given_name,
                },
                {
                  name: 'family_name',
                  label: 'Family Name',
                  type: 'text',
                  value: getValue('family_name'),
                  error: validationErrorMessages.family_name,
                },
                {
                  name: 'middle_name',
                  label: 'Middle Name',
                  type: 'text',
                  value: getValue('middle_name'),
                  error: validationErrorMessages.middle_name,
                },
                {
                  name: 'nickname',
                  label: 'Nickname',
                  type: 'text',
                  value: getValue('nickname'),
                  error: validationErrorMessages.nickname,
                },
                {
                  name: 'preferred_username',
                  label: 'Preferred Username',
                  type: 'text',
                  value: getValue('preferred_username'),
                  error: validationErrorMessages.preferred_username,
                },
                {
                  name: 'profile',
                  label: 'Profile',
                  type: 'text',
                  value: getValue('profile'),
                  error: validationErrorMessages.profile,
                },
                {
                  name: 'picture',
                  label: 'Picture',
                  type: 'text',
                  value: getValue('picture'),
                  error: validationErrorMessages.picture,
                },
                {
                  name: 'website',
                  label: 'Website',
                  type: 'text',
                  value: getValue('website'),
                  error: validationErrorMessages.website,
                },
                {
                  name: 'email',
                  label: 'Email',
                  type: 'text',
                  value: getValue('email'),
                  error: validationErrorMessages.email,
                },
                {
                  name: 'gender',
                  label: 'Gender',
                  type: 'text',
                  value: getValue('gender'),
                  error: validationErrorMessages.gender,
                },
                {
                  name: 'birthdate',
                  label: 'Birthdate',
                  type: 'text',
                  value: getValue('birthdate'),
                  error: validationErrorMessages.birthdate,
                },
                {
                  name: 'zoneinfo',
                  label: 'Timezone',
                  isDropdown: true,
                  options: userFormData.timezones.map(name => ({
                    label: name,
                    value: name,
                    selected: getValue('zoneinfo') === name
                  })),
                  value: getValue('zoneinfo'),
                  error: validationErrorMessages.zoneinfo,
                },
                {
                  name: 'locale',
                  label: 'Locale',
                  isDropdown: true,
                  options: Object.keys(userFormData.locales).map((value) => ({
                    label: userFormData.locales[value],
                    value,
                    selected: getValue('locale') === value,
                  })),
                  value: getValue('locale'),
                  error: validationErrorMessages.locale,
                },
                {
                  name: 'phone_number',
                  label: 'Phone Number',
                  type: 'text',
                  value: getValue('phone_number'),
                  error: validationErrorMessages.phone_number,
                },
                {
                  name: 'address.street_address',
                  label: 'Street Address',
                  type: 'text',
                  value: getValue('address.street_address'),
                  error: validationErrorMessages['address.street_address'],
                },
                {
                  name: 'address.locality',
                  label: 'Locality',
                  type: 'text',
                  value: getValue('address.locality'),
                  error: validationErrorMessages['address.locality'],
                },
                {
                  name: 'address.region',
                  label: 'Region',
                  type: 'text',
                  value: getValue('address.region'),
                  error: validationErrorMessages['address.region'],
                },
                {
                  name: 'address.postal_code',
                  label: 'Postal Code',
                  type: 'text',
                  value: getValue('address.postal_code'),
                  error: validationErrorMessages['address.postal_code'],
                },
                {
                  name: 'address.country',
                  label: 'Country',
                  type: 'text',
                  value: getValue('address.country'),
                  error: validationErrorMessages['address.country'],
                },
              ]
            });
          });
        });
      });
    },

    getForgotPasswordForm: function(request, reply, source, error) {
      reply.view('forgot-password', {
        title: 'Forgot Password',
        formAction: `/user/forgot-password?${querystring.stringify(request.query)}`,
        returnTo: `${request.query.redirect_uri}?status=cancelled`,
        error: !!error,
        validationErrorMessages: getValidationMessages(error),
      });
    },

    postForgotPasswordForm: function(request, reply) {
      return userService.findByEmailForOidc(request.payload.email)
        .then(user => user ? userService.createPasswordResetToken(user.accountId): null)
        .then(token => {
          if (token) {
            const base = config('/baseUrl');
            const prevQuery = querystring.stringify(request.query);

            return renderTemplate('email/forgot-password', {
              url: `${base}/user/reset-password?${prevQuery}&token=${token.get('token')}`,
            });
          }
        })
        .then(emailBody => {
          if (emailBody) {
            emailService.send({
              to: request.payload.email,
              subject: 'Reset your password',
              html: emailBody,
            });
          }
        })
        .then(() => {
          reply.view('forgot-password-success');
        });
    },

    getResetPasswordForm: function(request, reply, source, error) {
      reply.view('reset-password', {
        title: 'Reset Password',
        formAction: `/user/reset-password?${querystring.stringify(request.query)}`,
        returnTo: `${request.query.redirect_uri}?status=cancelled`,
        error: !!error,
        validationErrorMessages: getValidationMessages(error),
      });
    },

    postResetPasswordForm: function(request, reply, source, error) {
      return userService.findByPasswordToken(request.query.token)
        .then(user => {
          if (user) {
            return userService.encryptPassword(request.payload.password)
              .then(password => userService.update(user.accountId, { password }))
              .then(() => userService.destroyPasswordToken(request.query.token))
              .then(() => reply.view('reset-password-success'));
          } else {
            return reply.view('reset-password', {
              title: 'Reset Password',
              formAction: `/user/reset-password?${querystring.stringify(request.query)}`,
              returnTo: `${request.query.redirect_uri}?status=cancelled`,
              error: true,
              validationErrorMessages: { token: ['Token is invalid or expired'] },
            });
          }
        });
    },
  };
};

module.exports['@singleton'] = true;
module.exports['@require'] = [
  'user/user-service',
  'email/email-service',
  'render-template',
  'client/client-service',
  'oidc-adapter/redis',
  'user/user-form-data',
];
<commit_msg>Use userService.update instead of calling save on a model in a controller<commit_after>const querystring = require('querystring');
const formatError = require('../../lib/format-error');
const atob = require('atob');
const Boom = require('boom');
const get = require('lodash/get');
const config = require('../../../config');

module.exports = (userService, emailService, renderTemplate, clientService, RedisAdapter, userFormData) => {

  const errorMessages = {
    email: {
      'any.required': 'Email address is required',
      'any.empty': 'Email address is required',
      'string.email': 'Must be a valid email address',
    },
    password: {
      'any.empty': 'Password is required',
      'string.min': 'Password must be at least 8 characters',
    },
    pass2: {
      'any.allowOnly': 'Passwords must match'
    },
    redirect_uri: {
      'any.required': 'Redirect URI is required',
    },
    client_id: {
      'any.required': 'Client ID is required'
    },
    response_type: {
      'any.required': 'Response type is required',
    },
    scope: {
      'any.required': 'Scope is required',
    },
    token: {
      'any.required': 'Token is required',
    },
    profile: {
      'string.uri': 'Must be a valid URL',
    },
    picture: {
      'string.uri': 'Must be a valid URL',
    },
    website: {
      'string.uri': 'Must be a valid URL',
    }
  };

  const handleRegistrationPost = function(request, reply) {
    userService.create(request.payload.email, request.payload.password)
      .then(user => {
        reply.redirect(`/op/auth?${querystring.stringify(request.query)}`);
      })
      .catch(error => {
        // assume email collision and show validation message
        reply.view('user-registration', {
          title: 'Register',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: true,
          validationErrorMessages: {email: ['That email address is already in use']},
          email: request.payload.email || ''
        });
      });
  };

  const getValidationMessages = function(error) {
    var validationErrorMessages = {};

    if (error) {
      error = formatError(error);
      error.output.payload.validationErrors.forEach(errorObj => {
        validationErrorMessages[errorObj.key] = validationErrorMessages[errorObj.key] || [];

        if (errorMessages[errorObj.key][errorObj.type]) {
          validationErrorMessages[errorObj.key].push(errorMessages[errorObj.key][errorObj.type]);
        } else {
          validationErrorMessages[errorObj.key].push(errorObj.message);
        }
      });
    }

    return validationErrorMessages;
  };

  return {
    registerFormHandler: function(request, reply, source, error) {
      request.payload = request.payload || {};

      if (!error && request.method === 'post') {
        handleRegistrationPost(request, reply);
      } else {
        reply.view('user-registration', {
          title: 'Register',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: !!error,
          validationErrorMessages: getValidationMessages(error),
          email: request.payload.email || ''
        });
      }
    },

    profileFormHandler: function(request, reply, source, error) {
      const redisAdapter = new RedisAdapter('AccessToken');
      const clientId = request.query.clientId;
      return clientService.findById(clientId).then(client => {
        const redirectUris = client.related('redirect_uris').map(uri => uri.get('uri'));
        if (redirectUris.indexOf(request.query.redirect_uri) < 0) {
          return reply(Boom.forbidden('redirect_uri not in whitelist'));
        }
        return client;
      }).then((client) => {
        redisAdapter.find(request.query.accessToken.substr(0, 48)).then(token => {
          if (!token || token && token.signature !== request.query.accessToken.substr(48)) {
            return reply.redirect(`${request.query.redirect_uri}?error=unauthorized&error_description=invalid access token`);
          }
          const payload = JSON.parse(atob(token.payload));
          const accountId = payload.accountId;
          userService.findById(accountId).then(user => {
            if (!user) {
              return reply.redirect(`${request.query.redirect_uri}?error=user_not_found&error_description=user not found`);
            }

            const validationErrorMessages = {};
            if (!error && request.method === 'post') {
              const profile = user.get('profile');
              Object.assign(profile, request.payload);
              return userService.update(user.get('id'), { profile }).then(() => {
                return reply.redirect(request.query.redirect_uri);
              });
            } else {
              if (error) {
                error = formatError(error);
                error.output.payload.validationErrors.forEach(errorObj => {
                  validationErrorMessages[errorObj.key] = validationErrorMessages[errorObj.key] || [];
                  if (errorMessages[errorObj.key] && errorMessages[errorObj.key][errorObj.type]) {
                    validationErrorMessages[errorObj.key].push(errorMessages[errorObj.key][errorObj.type]);
                  } else {
                    validationErrorMessages[errorObj.key].push('Invalid value');
                  }
                });
              }
            }

            const profile = user.get('profile');
            const getValue = (field) => {
              return (request.payload && request.payload[field]) || get(profile, field, '');
            };
            reply.view('user-profile', {
              returnTo: request.query.redirect_uri,
              fields: [
                {
                  name: 'name',
                  label: 'Name',
                  type: 'text',
                  value: getValue('name'),
                  error: validationErrorMessages.name,
                },
                {
                  name: 'given_name',
                  label: 'Given Name',
                  type: 'text',
                  value: getValue('given_name'),
                  error: validationErrorMessages.given_name,
                },
                {
                  name: 'family_name',
                  label: 'Family Name',
                  type: 'text',
                  value: getValue('family_name'),
                  error: validationErrorMessages.family_name,
                },
                {
                  name: 'middle_name',
                  label: 'Middle Name',
                  type: 'text',
                  value: getValue('middle_name'),
                  error: validationErrorMessages.middle_name,
                },
                {
                  name: 'nickname',
                  label: 'Nickname',
                  type: 'text',
                  value: getValue('nickname'),
                  error: validationErrorMessages.nickname,
                },
                {
                  name: 'preferred_username',
                  label: 'Preferred Username',
                  type: 'text',
                  value: getValue('preferred_username'),
                  error: validationErrorMessages.preferred_username,
                },
                {
                  name: 'profile',
                  label: 'Profile',
                  type: 'text',
                  value: getValue('profile'),
                  error: validationErrorMessages.profile,
                },
                {
                  name: 'picture',
                  label: 'Picture',
                  type: 'text',
                  value: getValue('picture'),
                  error: validationErrorMessages.picture,
                },
                {
                  name: 'website',
                  label: 'Website',
                  type: 'text',
                  value: getValue('website'),
                  error: validationErrorMessages.website,
                },
                {
                  name: 'email',
                  label: 'Email',
                  type: 'text',
                  value: getValue('email'),
                  error: validationErrorMessages.email,
                },
                {
                  name: 'gender',
                  label: 'Gender',
                  type: 'text',
                  value: getValue('gender'),
                  error: validationErrorMessages.gender,
                },
                {
                  name: 'birthdate',
                  label: 'Birthdate',
                  type: 'text',
                  value: getValue('birthdate'),
                  error: validationErrorMessages.birthdate,
                },
                {
                  name: 'zoneinfo',
                  label: 'Timezone',
                  isDropdown: true,
                  options: userFormData.timezones.map(name => ({
                    label: name,
                    value: name,
                    selected: getValue('zoneinfo') === name
                  })),
                  value: getValue('zoneinfo'),
                  error: validationErrorMessages.zoneinfo,
                },
                {
                  name: 'locale',
                  label: 'Locale',
                  isDropdown: true,
                  options: Object.keys(userFormData.locales).map((value) => ({
                    label: userFormData.locales[value],
                    value,
                    selected: getValue('locale') === value,
                  })),
                  value: getValue('locale'),
                  error: validationErrorMessages.locale,
                },
                {
                  name: 'phone_number',
                  label: 'Phone Number',
                  type: 'text',
                  value: getValue('phone_number'),
                  error: validationErrorMessages.phone_number,
                },
                {
                  name: 'address.street_address',
                  label: 'Street Address',
                  type: 'text',
                  value: getValue('address.street_address'),
                  error: validationErrorMessages['address.street_address'],
                },
                {
                  name: 'address.locality',
                  label: 'Locality',
                  type: 'text',
                  value: getValue('address.locality'),
                  error: validationErrorMessages['address.locality'],
                },
                {
                  name: 'address.region',
                  label: 'Region',
                  type: 'text',
                  value: getValue('address.region'),
                  error: validationErrorMessages['address.region'],
                },
                {
                  name: 'address.postal_code',
                  label: 'Postal Code',
                  type: 'text',
                  value: getValue('address.postal_code'),
                  error: validationErrorMessages['address.postal_code'],
                },
                {
                  name: 'address.country',
                  label: 'Country',
                  type: 'text',
                  value: getValue('address.country'),
                  error: validationErrorMessages['address.country'],
                },
              ]
            });
          });
        });
      });
    },

    getForgotPasswordForm: function(request, reply, source, error) {
      reply.view('forgot-password', {
        title: 'Forgot Password',
        formAction: `/user/forgot-password?${querystring.stringify(request.query)}`,
        returnTo: `${request.query.redirect_uri}?status=cancelled`,
        error: !!error,
        validationErrorMessages: getValidationMessages(error),
      });
    },

    postForgotPasswordForm: function(request, reply) {
      return userService.findByEmailForOidc(request.payload.email)
        .then(user => user ? userService.createPasswordResetToken(user.accountId): null)
        .then(token => {
          if (token) {
            const base = config('/baseUrl');
            const prevQuery = querystring.stringify(request.query);

            return renderTemplate('email/forgot-password', {
              url: `${base}/user/reset-password?${prevQuery}&token=${token.get('token')}`,
            });
          }
        })
        .then(emailBody => {
          if (emailBody) {
            emailService.send({
              to: request.payload.email,
              subject: 'Reset your password',
              html: emailBody,
            });
          }
        })
        .then(() => {
          reply.view('forgot-password-success');
        });
    },

    getResetPasswordForm: function(request, reply, source, error) {
      reply.view('reset-password', {
        title: 'Reset Password',
        formAction: `/user/reset-password?${querystring.stringify(request.query)}`,
        returnTo: `${request.query.redirect_uri}?status=cancelled`,
        error: !!error,
        validationErrorMessages: getValidationMessages(error),
      });
    },

    postResetPasswordForm: function(request, reply, source, error) {
      return userService.findByPasswordToken(request.query.token)
        .then(user => {
          if (user) {
            return userService.encryptPassword(request.payload.password)
              .then(password => userService.update(user.accountId, { password }))
              .then(() => userService.destroyPasswordToken(request.query.token))
              .then(() => reply.view('reset-password-success'));
          } else {
            return reply.view('reset-password', {
              title: 'Reset Password',
              formAction: `/user/reset-password?${querystring.stringify(request.query)}`,
              returnTo: `${request.query.redirect_uri}?status=cancelled`,
              error: true,
              validationErrorMessages: { token: ['Token is invalid or expired'] },
            });
          }
        });
    },
  };
};

module.exports['@singleton'] = true;
module.exports['@require'] = [
  'user/user-service',
  'email/email-service',
  'render-template',
  'client/client-service',
  'oidc-adapter/redis',
  'user/user-form-data',
];
<|endoftext|>


<commit_before>function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987,
            // so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}

function isNumeric(num){
    return !isNaN(num)
}

function sendLoginAttempt(query){
    $.ajax({
        url: "http://d.rhocode.com:5000/login.html" + query,
        data: {},
        type: "GET",
        crossDomain: true,
        dataType: "jsonp",
        success: function (data) {
            $("#serverresponselogin").text("Sign-in successful! Welcome " + $("#name").val());
            setTimeout(function(){$('#signin').modal('toggle');$("#serverresponselogin").text(" ");}, 1000);
        },
        error: function (xhr, status) {
            $("#serverresponselogin").text("Server might be offline. Please contact aafu@ucdavis.edu!");
        },
        complete: function (xhr, status) {
            console.log("complete");
        }
    });
}
$(document).ready(function() {
  // set defaults
  $("#locationform").hide();
  $("#locationdropdown").val("computer");
  var dropdown = true;

  // dropdown changer
  $("#locationdropdown").change(function() {
    if ($("#locationdropdown").val() == "location") {
      dropdown = false;
      $("#locationform").show();
      $("#computerform").hide();
    } else {
      dropdown = true;
      $("#locationform").hide();
      $("#computerform").show();
    }
  });

  // form submission
  $("#submit").click(function(e) {
    //input validation
    var valid = 0;
    var query = "?name="
    // REALLY BAD INPUT VALIDATION
    if (!$("#name").val()) {
      $("#name").parent('div').addClass("has-error");
    } else {
      $("#name").parent('div').removeClass("has-error");
      valid++;
      query += encodeRFC5987ValueChars($("#name").val());
    }

    if (dropdown) {
      if (!$("#num").val() || !isNumeric($("#num").val())) {
        $("#num").parent('div').addClass("has-error");
      } else {
        $("#num").parent('div').removeClass("has-error");
        valid++;
        query += "&num=" + encodeRFC5987ValueChars($("#num").val());
      }
    } else {
      if (!$("#location").val()) {
        $("#location").parent('div').addClass("has-error");
      } else {
        $("#location").parent('div').removeClass("has-error");
        valid++;
        query += "&loc=" + encodeRFC5987ValueChars($("#location").val());
      }
    }

    var format = /^[0-9]+[a-zA-Z]*[\s]*([\s,]+[0-9]+[a-zA-Z]*)*$/i;
    if (!$("#subject").val() ||  !format.test( $("#subject").val() ) ) {
      $("#subject").parent('div').addClass("has-error");
    } else {
      $("#subject").parent('div').removeClass("has-error");
      valid++;
      query += "&sub=" + encodeRFC5987ValueChars($("#location").val());
    }
    if (!$("#password").val()) {
      $("#password").parent('div').addClass("has-error");
    } else {
      $("#password").parent('div').removeClass("has-error");
      valid++;
      query += "&pass=" + encodeRFC5987ValueChars($("#password").val());
    }

    if (valid == 4) {
      //do submit
      console.log("we good");
      console.log(query);
      sendLoginAttempt(query);
    } else {
      console.log("nice try kid");
    }

  });

  // row toggle
  $(".rowtoggle").click(function(e) {
    if ($(this).hasClass("success")) {
      $(this).addClass("danger").removeClass("success");
      //send to server BUSY
    } else {
      $(this).addClass("success").removeClass("danger");
      //send to server AVAILABLE
    }
  });

});

<commit_msg>Added a "tutorCode"<commit_after>function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987,
            // so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}

function isNumeric(num){
    return !isNaN(num)
}

function sendLoginAttempt(query){
    $.ajax({
        url: "http://d.rhocode.com:5000/login.html" + query,
        data: {},
        type: "GET",
        crossDomain: true,
        dataType: "jsonp",
        success: function (data) {
            if(data.status == 'success') {
              $("#serverresponselogin").html("Sign-in successful! Welcome " + $("#name").val() + '! Your tutor code is <b>' + data.tutorcode + '</b>.');
            } else {
              $("#serverresponselogin").text("Sign-in failed.");
            }

        },
        error: function (xhr, status) {
            $("#serverresponselogin").text("Server might be offline. Please contact aafu@ucdavis.edu!");
        },
        complete: function (xhr, status) {
            console.log("complete");
        }
    });
}
$(document).ready(function() {
  // set defaults
  $("#locationform").hide();
  $("#locationdropdown").val("computer");
  var dropdown = true;

  // dropdown changer
  $("#locationdropdown").change(function() {
    if ($("#locationdropdown").val() == "location") {
      dropdown = false;
      $("#locationform").show();
      $("#computerform").hide();
    } else {
      dropdown = true;
      $("#locationform").hide();
      $("#computerform").show();
    }
  });

  // form submission
  $("#submit").click(function(e) {
    //input validation
    var valid = 0;
    var query = "?name="
    // REALLY BAD INPUT VALIDATION
    if (!$("#name").val()) {
      $("#name").parent('div').addClass("has-error");
    } else {
      $("#name").parent('div').removeClass("has-error");
      valid++;
      query += encodeRFC5987ValueChars($("#name").val());
    }

    if (dropdown) {
      if (!$("#num").val() || !isNumeric($("#num").val())) {
        $("#num").parent('div').addClass("has-error");
      } else {
        $("#num").parent('div').removeClass("has-error");
        valid++;
        query += "&num=" + encodeRFC5987ValueChars($("#num").val());
      }
    } else {
      if (!$("#location").val()) {
        $("#location").parent('div').addClass("has-error");
      } else {
        $("#location").parent('div').removeClass("has-error");
        valid++;
        query += "&loc=" + encodeRFC5987ValueChars($("#location").val());
      }
    }

    var format = /^[0-9]+[a-zA-Z]*[\s]*([\s,]+[0-9]+[a-zA-Z]*)*$/i;
    if (!$("#subject").val() ||  !format.test( $("#subject").val() ) ) {
      $("#subject").parent('div').addClass("has-error");
    } else {
      $("#subject").parent('div').removeClass("has-error");
      valid++;
      query += "&sub=" + encodeRFC5987ValueChars($("#location").val());
    }
    if (!$("#password").val()) {
      $("#password").parent('div').addClass("has-error");
    } else {
      $("#password").parent('div').removeClass("has-error");
      valid++;
      query += "&pass=" + encodeRFC5987ValueChars($("#password").val());
    }

    if (valid == 4) {
      //do submit
      console.log("we good");
      console.log(query);
      sendLoginAttempt(query);
    } else {
      console.log("nice try kid");
    }

  });

  // row toggle
  $(".rowtoggle").click(function(e) {
    if ($(this).hasClass("success")) {
      $(this).addClass("danger").removeClass("success");
      //send to server BUSY
    } else {
      $(this).addClass("success").removeClass("danger");
      //send to server AVAILABLE
    }
  });

});

<|endoftext|>


<commit_before>Template.chart.rendered = function () {
grabInfo(); //Pushes Data into an array based on format required for C3.js chart rendering
 var chart = c3.generate({
      bindto: this.find('#chart'), //Looks for chart id in html
      data:{  x: 'date',
          columns: [
            grabDate,
            grabDistance,
          ],
          types: {
            Running: 'area-spline',
            Walking: 'area-spline',
            Swimming: 'area-spline',
            Cycling: 'area-spline'
          },
          hide: true
          },
      subchart: { show: true },
      zoom: { enabled: true },
      axis: {
              x: { label: { text: 'Date', position: 'outer-middle'}, type: 'timeseries', tick: { format: '%m-%d'} },
              y: { label: { text: 'Distance', position: 'outer-middle'} }
            },
      legend: { show: false }
    });

  this.autorun(function (tracker) {
  $("#cardio,#strength,#flexibility").change(function(){
    //When a selection is made from the dropdown menu
      var c1 = $("#cardio").find('option:selected').val();
      grabInfo();
      chart.hide(null,{ withLegend: true });
      chart.show([c1],{ withLegend: true });

    });

    //For when the user clicks to Show Time
    $('#A').on('click',function(){
      chart.load({ columns:[ grabTime, ], unload: ['Running'], });
      chart.axis.labels({y: "Time"});

    });

    //For when the user clicks to Show Distance
    $('#B').on('click',function(){
      chart.load({ columns:[ grabDistance, ], unload: ['Running Time'],});
      chart.axis.labels({y: "Distance"});

    });

  });
}

//C3.js requires the first element of the array to be an string of the category
var grabDistance = ['Running'];
var grabTime = ['Running Time'];
var grabDate = ['date'];

      function grabInfo() {
        var allCardio = Cardio.find().fetch(); //Finds all Cardio data at the moment and stores into C3.js formats
        allCardio.forEach(function(finished) { //Should eventually include only the users data and exclude startup
            grabDistance.push(finished.Distance);
            grabTime.push(finished.Time);
            grabDate.push(finished.analyticsDate);
        });
      }
<commit_msg>fixed bug where analytics stacks data when navigating away from page and returning<commit_after>Template.chart.rendered = function () {
  grabInfo(); //Pushes Data into an array based on format required for C3.js chart rendering
 var chart = c3.generate({
      bindto: this.find('#chart'), //Looks for chart id in html
      data:{  x: 'date',
          columns: [
            grabDate,
            grabDistance,
          ],
          types: {
            Running: 'area-spline',
            Walking: 'area-spline',
            Swimming: 'area-spline',
            Cycling: 'area-spline'
          },
          hide: true
          },
      subchart: { show: true },
      zoom: { enabled: true },
      axis: {
              x: { label: { text: 'Date', position: 'outer-middle'}, type: 'timeseries', tick: { format: '%m-%d'} },
              y: { label: { text: 'Distance', position: 'outer-middle'} }
            },
      legend: { show: false }
    });

  this.autorun(function (tracker) {
  $("#cardio,#strength,#flexibility").change(function(){
    //When a selection is made from the dropdown menu
      var c1 = $("#cardio").find('option:selected').val();
      chart.hide(null,{ withLegend: true });
      chart.show([c1],{ withLegend: true });

    });

    //For when the user clicks to Show Time
    $('#A').on('click',function(){
      chart.load({ columns:[ grabTime, ], unload: ['Running'], });
      chart.axis.labels({y: "Time"});

    });

    //For when the user clicks to Show Distance
    $('#B').on('click',function(){
      chart.load({ columns:[ grabDistance, ], unload: ['Running Time'],});
      chart.axis.labels({y: "Distance"});

    });

  });
}

//C3.js requires the first element of the array to be an string of the category
var grabDistance = ['Running'];
var grabTime = ['Running Time'];
var grabDate = ['date'];

      function grabInfo() {
        grabDistance = ['Running'];  //Makes sure to clear data upon navigating away from page
        grabTime = ['Running Time'];
        grabDate = ['date'];
        var allCardio = Cardio.find().fetch(); //Finds all Cardio data at the moment and stores into C3.js formats
        allCardio.forEach(function(finished) { //Should eventually include only the users data and exclude startup
            grabDistance.push(finished.Distance);
            grabTime.push(finished.Time);
            grabDate.push(finished.analyticsDate);
        });
      }
<|endoftext|>


<commit_before>var sinon = require("sinon");
var assert = require("chai").assert;
var expect = require("chai").expect;
var enqueue = require("./enqueue.js");

const sample_data = { kind: 'storage#object', resourceState: 'exists', id: 'm-lab-sandbox/testfile/1491851987540929', selfLink: 'https://www.googleapis.com/storage/v1/b/m-lab-sandbox/o/testfile', name: 'testfile', bucket: 'm-lab-sandbox', generation: '1491851987540929', metageneration: '1', contentType: 'binary/octet-stream', timeCreated: '2017-04-10T19:19:47.519Z', updated: '2017-04-10T19:19:47.519Z', storageClass: 'REGIONAL', size: '0', md5Hash: 'ZDQxZDhjZDk4ZjAwYjIwNGU5ODAwOTk4ZWNmODQyN2U=', mediaLink: 'https://www.googleapis.com/storage/v1/b/m-lab-sandbox/o/testfile?generation=1491851987540929&alt=media', crc32c: 'AAAAAA==' }

describe("ProcessNotification", function () {
  it("calls the callback", function () {
    var callback = sinon.spy()
    enqueue.fileNotification({"data": sample_data}, callback);
    assert(callback.called);
  });
});

describe("queueForFile", function () {
  it("won't return a queue for unparsed files", function () {
    assert.isNotOk(enqueue.queueForFile("test/2008/07/12/blah.tgz"));
    assert.isNotOk(enqueue.queueForFile("npad/2008/07/12/blah.tgz"));
  });
  it("will return a queue for files that should be parsed", function () {
    assert.isOk(enqueue.queueForFile("ndt/2008/07/12/blah.tgz"));
    assert.isOk(enqueue.queueForFile("sidestream/2008/07/12/blah.tgz"));
    assert.isOk(enqueue.queueForFile("paris-traceroute/2008/07/12/blah.tgz"));
  });
});

describe("fileIsProcessable", function() {
  it("won't be processable if it does not exist", function() {
    assert.isNotOk(enqueue.fileIsProcessable({"resourceState": "not_exists"}));
  });
});
<commit_msg>We changed function names without running the unit tests.<commit_after>var sinon = require("sinon");
var assert = require("chai").assert;
var expect = require("chai").expect;
var enqueue = require("./enqueue.js");

const sample_data = { kind: 'storage#object', resourceState: 'exists', id: 'm-lab-sandbox/testfile/1491851987540929', selfLink: 'https://www.googleapis.com/storage/v1/b/m-lab-sandbox/o/testfile', name: 'testfile', bucket: 'm-lab-sandbox', generation: '1491851987540929', metageneration: '1', contentType: 'binary/octet-stream', timeCreated: '2017-04-10T19:19:47.519Z', updated: '2017-04-10T19:19:47.519Z', storageClass: 'REGIONAL', size: '0', md5Hash: 'ZDQxZDhjZDk4ZjAwYjIwNGU5ODAwOTk4ZWNmODQyN2U=', mediaLink: 'https://www.googleapis.com/storage/v1/b/m-lab-sandbox/o/testfile?generation=1491851987540929&alt=media', crc32c: 'AAAAAA==' }

describe("ProcessNotification", function () {
  it("calls the callback", function () {
    var callback = sinon.spy()
    enqueue.createStagingTaskOnFileNotification({"data": sample_data}, callback);
    assert(callback.called);
  });
});

describe("queueForFile", function () {
  it("won't return a queue for unparsed files", function () {
    assert.isNotOk(enqueue.queueForFile("test/2008/07/12/blah.tgz"));
    assert.isNotOk(enqueue.queueForFile("npad/2008/07/12/blah.tgz"));
  });
  it("will return a queue for files that should be parsed", function () {
    assert.isOk(enqueue.queueForFile("ndt/2008/07/12/blah.tgz"));
    assert.isOk(enqueue.queueForFile("sidestream/2008/07/12/blah.tgz"));
    assert.isOk(enqueue.queueForFile("paris-traceroute/2008/07/12/blah.tgz"));
  });
});

describe("fileIsProcessable", function() {
  it("won't be processable if it does not exist", function() {
    assert.isNotOk(enqueue.fileIsProcessable({"resourceState": "not_exists"}));
  });
});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import KeyboardArrowLeft from '../internal/svg-icons/KeyboardArrowLeft';
import KeyboardArrowRight from '../internal/svg-icons/KeyboardArrowRight';
import withStyles from '../styles/withStyles';
import ButtonBase from '../ButtonBase';

export const styles = {
  /* Styles applied to the root element. */
  root: {
    color: 'inherit',
    flex: '0 0 56px',
  },
};

/**
 * @ignore - internal component.
 */
function TabScrollButton(props) {
  const { classes, className: classNameProp, direction, onClick, visible, ...other } = props;

  const className = classNames(classes.root, classNameProp);

  if (!visible) {
    return
;
  }

  return (
    <ButtonBase className={className} onClick={onClick} tabIndex={-1} {...other}>
      {direction === 'left' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
    </ButtonBase>
  );
}

TabScrollButton.propTypes = {
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * Which direction should the button indicate?
   */
  direction: PropTypes.oneOf(['left', 'right']),
  /**
   * Callback to execute for button press.
   */
  onClick: PropTypes.func,
  /**
   * Should the button be present or just consume space.
   */
  visible: PropTypes.bool,
};

TabScrollButton.defaultProps = {
  visible: true,
};

export default withStyles(styles, { name: 'MuiPrivateTabScrollButton' })(TabScrollButton);
<commit_msg>[Tabs] Fix infinite loop in the scroll button logic (#14033)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import KeyboardArrowLeft from '../internal/svg-icons/KeyboardArrowLeft';
import KeyboardArrowRight from '../internal/svg-icons/KeyboardArrowRight';
import withStyles from '../styles/withStyles';
import ButtonBase from '../ButtonBase';

export const styles = {
  /* Styles applied to the root element. */
  root: {
    color: 'inherit',
    width: 56,
    flexShrink: 0,
  },
};

/**
 * @ignore - internal component.
 */
function TabScrollButton(props) {
  const { classes, className: classNameProp, direction, onClick, visible, ...other } = props;

  const className = classNames(classes.root, classNameProp);

  if (!visible) {
    return
;
  }

  return (
    <ButtonBase className={className} onClick={onClick} tabIndex={-1} {...other}>
      {direction === 'left' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
    </ButtonBase>
  );
}

TabScrollButton.propTypes = {
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * Which direction should the button indicate?
   */
  direction: PropTypes.oneOf(['left', 'right']),
  /**
   * Callback to execute for button press.
   */
  onClick: PropTypes.func,
  /**
   * Should the button be present or just consume space.
   */
  visible: PropTypes.bool,
};

TabScrollButton.defaultProps = {
  visible: true,
};

export default withStyles(styles, { name: 'MuiPrivateTabScrollButton' })(TabScrollButton);
<|endoftext|>


<commit_before>var working = false;
var site = "beam";
var addevents = [];
var delevents = [];

$("body").on("DOMNodeInserted", ".messages .nano-content", function() {
	if(!working) {
		for(var i = 0; i < addevents.length; i++) {
			if(addevents[i]) {
				var name = $(".message:last-child .message-author").clone().children().remove().end().text();
				var message = $(".message:last-child .message-body").html();
				var id = $(".message:last-child").attr("id");

				addevents[i](name, message, id);
			}
		}
	}
});
$("body").on("DOMNodeRemoved", ".messages .nano-content", function() {
	for(var i = 0; i < delevents.length; i++) {
		if(delevents[i]) {
			delevents[i]();
		}
	}
});

function addMessage(name, message, id) {
	working = true;

	if(id) {
		var toid = " id='" + id + "'";
		var toda = " data-message='" + id + "'";
	} else {
		var toid = "";
		var toda = "";
	}

	$(".message:last-child").append(
		"
" +
			"
" +
				name +
			"
" +
			"
" +
				message +
			"
" +
		"
"
	);

	working = false;
}
function replaceMessage(name, message) {
	working = true;
	var ranks = getRanks();

	$(".message:last-child .message-author").html(name);
	$(".message:last-child .message-body").html(message);

	setRanks(ranks);
	working = false;
}
function removeMessage() {
	working = true;
	$(".message:last-child").remove();
	working = false;
}

function addColor(color) {
	working = true;
	$(".message:last-child .message-author").css("color", color);
	working = false;
}
function addBadge(image) {
	working = true;
	$(".message:last-child .message-author").prepend("");
	working = false;
}

function getRanks() {
	var text = $(".message:last-child .message-author .text-role").text();
	var ranks = [];

	if(text.indexOf("Owner") > -1) {
		ranks.push("streamer");
	}
	if(text.indexOf("Mod") > -1) {
		ranks.push("mod");
	}
	if(text.indexOf("Admin") > -1) {
		ranks.push("admin");
	}
	if(text.indexOf("Dev") > -1) {
		ranks.push("dev");
	}
	if(text.indexOf("Pro") > -1) {
		ranks.push("pro");
	}
	if(text.indexOf("Subscriber") > -1) {
		ranks.push("sub");
	}

	return ranks;
}
function setRanks(ranks) {
	working = true;
	var name = $(".message:last-child .message-author").clone().children().remove().end().text();
	var toranks = [];

	for(var i = 0; i < ranks.length; i++) {
		if(ranks[i] == "streamer") {
			toranks.push("Owner");
		}
		if(ranks[i] == "mod") {
			toranks.push("Mod");
		}
		if(ranks[i] == "admin") {
			toranks.push("Admin");
		}
		if(ranks[i] == "dev") {
			toranks.push("Dev");
		}
		if(ranks[i] == "pro") {
			toranks.push("Pro");
		}
		if(ranks[i] == "sub") {
			toranks.push("Subscriber");
		}
	}

	var divranks = "";
	for(var i = 0; i < toranks.length; i++) {
		divranks += "" + toranks[i] + "";
	}
	$(".message:last-child .message-author").html(name + "
" + divranks + "
");

	$(".message:last-child").removeClass().addClass("message fadeIn a-s-fast message-role-User");
	for(var i = 0; i < toranks.length; i++) {
		$(".message:last-child").addClass("message-role-" + toranks[i]);
	}

	var danranks = "";
	for(var i = 0; i < toranks.length; i++) {
		danranks += toranks[i] + "|";
	}
	$(".message:last-child").attr("data-role", danranks + "User");

	working = false;
}

function getStreamerName() {
	name = window.location.pathname;
	arr = [];

	for(var i = 0; i < name.length; i++) {
		if(name.charAt(i) == "/") {
			arr.push("");
		} else {
			arr[arr.length - 1] += name.charAt(i);
		}
	}

	return arr[arr.length - 1];
}

function onMessageAdd(callback) {
	return addevents.push(callback) - 1;
}
function onMessageRemove(callback) {
	return delevents.push(callback) - 1;
}

function offMessageAdd(num) {
	addevents[num] = false;
}
function offMessageRemove(num) {
	delevents[num] = false;
}
<commit_msg>Made addMessage() actually do anything<commit_after>var working = false;
var site = "beam";
var addevents = [];
var delevents = [];

$("body").on("DOMNodeInserted", ".messages .nano-content", function() {
	if(!working) {
		for(var i = 0; i < addevents.length; i++) {
			if(addevents[i]) {
				var name = $(".message:last-child .message-author").clone().children().remove().end().text();
				var message = $(".message:last-child .message-body").html();
				var id = $(".message:last-child").attr("id");

				addevents[i](name, message, id);
			}
		}
	}
});
$("body").on("DOMNodeRemoved", ".messages .nano-content", function() {
	for(var i = 0; i < delevents.length; i++) {
		if(delevents[i]) {
			delevents[i]();
		}
	}
});

function addMessage(name, message, id) {
	working = true;

	if(id) {
		var toid = " id='" + id + "'";
		var toda = " data-message='" + id + "'";
	} else {
		var toid = "";
		var toda = "";
	}

	$(".messages .nano-content").append(
		"
" +
			"
" +
				name +
			"
" +
			"
" +
				message +
			"
" +
		"
"
	);

	working = false;
}
function replaceMessage(name, message) {
	working = true;
	var ranks = getRanks();

	$(".message:last-child .message-author").html(name);
	$(".message:last-child .message-body").html(message);

	setRanks(ranks);
	working = false;
}
function removeMessage() {
	working = true;
	$(".message:last-child").remove();
	working = false;
}

function addColor(color) {
	working = true;
	$(".message:last-child .message-author").css("color", color);
	working = false;
}
function addBadge(image) {
	working = true;
	$(".message:last-child .message-author").prepend("");
	working = false;
}

function getRanks() {
	var text = $(".message:last-child .message-author .text-role").text();
	var ranks = [];

	if(text.indexOf("Owner") > -1) {
		ranks.push("streamer");
	}
	if(text.indexOf("Mod") > -1) {
		ranks.push("mod");
	}
	if(text.indexOf("Admin") > -1) {
		ranks.push("admin");
	}
	if(text.indexOf("Dev") > -1) {
		ranks.push("dev");
	}
	if(text.indexOf("Pro") > -1) {
		ranks.push("pro");
	}
	if(text.indexOf("Subscriber") > -1) {
		ranks.push("sub");
	}

	return ranks;
}
function setRanks(ranks) {
	working = true;
	var name = $(".message:last-child .message-author").clone().children().remove().end().text();
	var toranks = [];

	for(var i = 0; i < ranks.length; i++) {
		if(ranks[i] == "streamer") {
			toranks.push("Owner");
		}
		if(ranks[i] == "mod") {
			toranks.push("Mod");
		}
		if(ranks[i] == "admin") {
			toranks.push("Admin");
		}
		if(ranks[i] == "dev") {
			toranks.push("Dev");
		}
		if(ranks[i] == "pro") {
			toranks.push("Pro");
		}
		if(ranks[i] == "sub") {
			toranks.push("Subscriber");
		}
	}

	var divranks = "";
	for(var i = 0; i < toranks.length; i++) {
		divranks += "" + toranks[i] + "";
	}
	$(".message:last-child .message-author").html(name + "
" + divranks + "
");

	$(".message:last-child").removeClass().addClass("message fadeIn a-s-fast message-role-User");
	for(var i = 0; i < toranks.length; i++) {
		$(".message:last-child").addClass("message-role-" + toranks[i]);
	}

	var danranks = "";
	for(var i = 0; i < toranks.length; i++) {
		danranks += toranks[i] + "|";
	}
	$(".message:last-child").attr("data-role", danranks + "User");

	working = false;
}

function getStreamerName() {
	name = window.location.pathname;
	arr = [];

	for(var i = 0; i < name.length; i++) {
		if(name.charAt(i) == "/") {
			arr.push("");
		} else {
			arr[arr.length - 1] += name.charAt(i);
		}
	}

	return arr[arr.length - 1];
}

function onMessageAdd(callback) {
	return addevents.push(callback) - 1;
}
function onMessageRemove(callback) {
	return delevents.push(callback) - 1;
}

function offMessageAdd(num) {
	addevents[num] = false;
}
function offMessageRemove(num) {
	delevents[num] = false;
}
<|endoftext|>