<commit_before>var console = require('console');
var i2c = require('i2c');
var _ = require('lodash');
var utils = require('./utils');

var BH1750 = function (opts) {
    this.options = _.extend({}, {
        address: 0x23,
        device: '/dev/i2c-1',
        command: 0x10,
        length: 2
    }, opts);
    this.verbose = this.options.verbose || false;
    this.wire = new i2c(this.options.address, {device: this.options.device});
};

BH1750.prototype.readLight = function (cb) {
    var self = this;
    if (!utils.exists(cb)) {
        throw new Error("Invalid param");
    }
    self.wire.readBytes(self.options.command, self.options.length, function (err, res) {
        if (utils.exists(err)) {
            if (self.verbose)
                console.error("error: I/O failure on BH1750 - command: ", self.options.command);
            return cb(err, null);
        }
        var hi = res.readUInt8(0);
        var lo = res.readUInt8(1);
        var lux = ((hi << 8) + lo)/1.2;
        if (self.options.command === 0x11) {
            lux = lux/2;
        }
        cb(null, lux);
    });
};

module.exports = BH1750;
<commit_msg>iotjs: fallback to array<commit_after>var console = require('console');
var i2c = require('i2c');
var _ = require('lodash');
var utils = require('./utils');

var BH1750 = function (opts) {
    this.options = _.extend({}, {
        address: 0x23,
        device: '/dev/i2c-1',
        command: 0x10,
        length: 2
    }, opts);
    this.verbose = this.options.verbose || false;
    this.wire = new i2c(this.options.address, {device: this.options.device});
};

BH1750.prototype.readLight = function (cb) {
    var self = this;
    if (!utils.exists(cb)) {
        throw new Error("Invalid param");
    }
    self.wire.readBytes(self.options.command, self.options.length, function (err, res) {
        if (utils.exists(err)) {
            if (self.verbose)
                console.error("error: I/O failure on BH1750 - command: ", self.options.command);
            return cb(err, null);
        }
        var hi = res[0];
        var lo = res[1];
        if (Buffer.isBuffer(res)) {
           hi = res.readUInt8(0);
           lo = res.readUInt8(1);
        }

        var lux = ((hi << 8) + lo)/1.2;
        if (self.options.command === 0x11) {
            lux = lux/2;
        }
        cb(null, lux);
    });
};

module.exports = BH1750;
<|endoftext|>


<commit_before>// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// 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 Error handling utilities.
 *
 */

goog.provide('goog.debug.ErrorHandler');

goog.require('goog.debug');
goog.require('goog.debug.EntryPointMonitor');
goog.require('goog.debug.Trace');

/**
 * The ErrorHandler can be used to to wrap functions with a try/catch
 * statement. If an exception is thrown, the given error handler function will
 * be called.
 *
 * When this object is disposed, it will stop handling exceptions and tracing.
 * It will also try to restore window.setTimeout and window.setInterval
 * if it wrapped them. Notice that in the general case, it is not technically
 * possible to remove the wrapper, because functions have no knowledge of
 * what they have been assigned to. So the app is responsible for other
 * forms of unwrapping.
 *
 * @param {Function} handler Handler for exceptions.
 * @constructor
 * @extends {goog.Disposable}
 * @implements {goog.debug.EntryPointMonitor}
 */
goog.debug.ErrorHandler = function(handler) {
  /**
   * Handler for exceptions, which can do logging, reporting, etc.
   * @type {Function}
   * @private
   */
  this.errorHandlerFn_ = handler;
};
goog.inherits(goog.debug.ErrorHandler, goog.Disposable);

/**
 * Whether to add tracers when instrumenting entry points.
 * @type {boolean}
 * @private
 */
goog.debug.ErrorHandler.prototype.addTracersToProtectedFunctions_ = false;

/**
 * Enable tracers when instrumenting entry points.
 * @param {boolean} newVal See above.
 */
goog.debug.ErrorHandler.prototype.setAddTracersToProtectedFunctions =
    function(newVal) {
  this.addTracersToProtectedFunctions_ = newVal;
};

/** @inheritDoc */
goog.debug.ErrorHandler.prototype.wrap = function(fn) {
  return this.protectEntryPoint(fn);
};

/** @inheritDoc */
goog.debug.ErrorHandler.prototype.unwrap = function(fn) {
  return fn[this.getFunctionIndex_(false)] || fn;
};

/**
 * Private helper function to return a span that can be clicked on to display
 * an alert with the current stack trace. Newlines are replaced with a
 * placeholder so that they will not be html-escaped.
 * @param {string} stackTrace The stack trace to create a span for.
 * @return {string} A span which can be clicked on to show the stack trace.
 * @private
 */
goog.debug.ErrorHandler.prototype.getStackTraceHolder_ = function(stackTrace) {
  var buffer = [];
  buffer.push('##PE_STACK_START##');
  buffer.push(stackTrace.replace(/(\r\n|\r|\n)/g, '##STACK_BR##'));
  buffer.push('##PE_STACK_END##');
  return buffer.join('');
};

/**
 * Get the index for a function. Used for internal indexing.
 * @param {boolean} wrapper True for the wrapper; false for the wrapped.
 * @return {string} The index where we should store the function in its
 *     wrapper/wrapped function.
 * @private
 */
goog.debug.ErrorHandler.prototype.getFunctionIndex_ = function(wrapper) {
  return (wrapper ? '__wrapper_' : '__protected_') + goog.getUid(this) + '__';
};

/**
 * Installs exception protection for an entry point function. When an exception
 * is thrown from a protected function, a handler will be invoked to handle it.
 *
 * @param {Function} fn An entry point function to be protected.
 * @return {!Function} A protected wrapper function that calls the entry point
 *     function.
 */
goog.debug.ErrorHandler.prototype.protectEntryPoint = function(fn) {
  var protectedFnName = this.getFunctionIndex_(true);
  if (!fn[protectedFnName]) {
    var wrapper = fn[protectedFnName] = this.getProtectedFunction(fn);
    wrapper[this.getFunctionIndex_(false)] = fn;
  }
  return fn[protectedFnName];
};

/**
 * Helps {@link #protectEntryPoint} by actually creating the protected
 * wrapper function, after {@link #protectEntryPoint} determines that one does
 * not already exist for the given function.  Can be overriden by subclasses
 * that may want to implement different error handling, or add additional
 * entry point hooks.
 * @param {!Function} fn An entry point function to be protected.
 * @return {!Function} protected wrapper function.
 * @protected
 */
goog.debug.ErrorHandler.prototype.getProtectedFunction = function(fn) {
  var that = this;
  var tracers = this.addTracersToProtectedFunctions_;
  if (tracers) {
    var stackTrace = goog.debug.getStacktraceSimple(15);
  }
  var result = function() {
    if (that.isDisposed()) {
      return fn.apply(this, arguments);
    }

    if (tracers) {
      var tracer = goog.debug.Trace.startTracer('protectedEntryPoint: ' +
          that.getStackTraceHolder_(stackTrace));
    }
    try {
      return fn.apply(this, arguments);
    } catch (e) {
      that.errorHandlerFn_(e);
      throw e;  // Re-throw it since this may be expected by the caller.
    } finally {
      if (tracers) {
        goog.debug.Trace.stopTracer(tracer);
      }
    }
  };
  result[this.getFunctionIndex_(false)] = fn;
  return result;
};

/**
 * Installs exception protection for window.setTimeout to handle exceptions.
 */
goog.debug.ErrorHandler.prototype.protectWindowSetTimeout =
    function() {
  this.protectWindowFunctionsHelper_('setTimeout');
};

/**
 * Install exception protection for window.setInterval to handle exceptions.
 */
goog.debug.ErrorHandler.prototype.protectWindowSetInterval =
    function() {
  this.protectWindowFunctionsHelper_('setInterval');
};

/**
 * Helper function for protecting setTimeout/setInterval.
 * @param {string} fnName The name of the function we're protecting. Must
 *     be setTimeout or setInterval.
 * @private
 */
goog.debug.ErrorHandler.prototype.protectWindowFunctionsHelper_ =
    function(fnName) {
  var win = goog.getObjectByName('window');
  var originalFn = win[fnName];
  var that = this;
  win[fnName] = function(fn, time) {
    // Don't try to protect strings. In theory, we could try to globalEval
    // the string, but this seems to lead to permission errors on IE6.
    if (goog.isString(fn)) {
      fn = goog.partial(goog.globalEval, fn);
    }
    fn = that.protectEntryPoint(fn);

    // IE doesn't support .call for setInterval/setTimeout, but it
    // also doesn't care what "this" is, so we can just call the
    // original function directly
    if (originalFn.call) {
      return originalFn.call(this, fn, time);
    } else {
      return originalFn(fn, time);
    }
  };
  win[fnName][this.getFunctionIndex_(false)] = originalFn;
};

/** @inheritDoc */
goog.debug.ErrorHandler.prototype.disposeInternal = function() {
  // Try to unwrap window.setTimeout and window.setInterval.
  var win = goog.getObjectByName('window');
  win.setTimeout = this.unwrap(win.setTimeout);
  win.setInterval = this.unwrap(win.setInterval);

  goog.base(this, 'disposeInternal');
};
<commit_msg><commit_after>// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// 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 Error handling utilities.
 *
 */

goog.provide('goog.debug.ErrorHandler');

goog.require('goog.debug');
goog.require('goog.debug.EntryPointMonitor');
goog.require('goog.debug.Trace');

/**
 * The ErrorHandler can be used to to wrap functions with a try/catch
 * statement. If an exception is thrown, the given error handler function will
 * be called.
 *
 * When this object is disposed, it will stop handling exceptions and tracing.
 * It will also try to restore window.setTimeout and window.setInterval
 * if it wrapped them. Notice that in the general case, it is not technically
 * possible to remove the wrapper, because functions have no knowledge of
 * what they have been assigned to. So the app is responsible for other
 * forms of unwrapping.
 *
 * @param {Function} handler Handler for exceptions.
 * @constructor
 * @extends {goog.Disposable}
 * @implements {goog.debug.EntryPointMonitor}
 */
goog.debug.ErrorHandler = function(handler) {
  goog.base(this);

  /**
   * Handler for exceptions, which can do logging, reporting, etc.
   * @type {Function}
   * @private
   */
  this.errorHandlerFn_ = handler;
};
goog.inherits(goog.debug.ErrorHandler, goog.Disposable);

/**
 * Whether to add tracers when instrumenting entry points.
 * @type {boolean}
 * @private
 */
goog.debug.ErrorHandler.prototype.addTracersToProtectedFunctions_ = false;

/**
 * Enable tracers when instrumenting entry points.
 * @param {boolean} newVal See above.
 */
goog.debug.ErrorHandler.prototype.setAddTracersToProtectedFunctions =
    function(newVal) {
  this.addTracersToProtectedFunctions_ = newVal;
};

/** @inheritDoc */
goog.debug.ErrorHandler.prototype.wrap = function(fn) {
  return this.protectEntryPoint(fn);
};

/** @inheritDoc */
goog.debug.ErrorHandler.prototype.unwrap = function(fn) {
  return fn[this.getFunctionIndex_(false)] || fn;
};

/**
 * Private helper function to return a span that can be clicked on to display
 * an alert with the current stack trace. Newlines are replaced with a
 * placeholder so that they will not be html-escaped.
 * @param {string} stackTrace The stack trace to create a span for.
 * @return {string} A span which can be clicked on to show the stack trace.
 * @private
 */
goog.debug.ErrorHandler.prototype.getStackTraceHolder_ = function(stackTrace) {
  var buffer = [];
  buffer.push('##PE_STACK_START##');
  buffer.push(stackTrace.replace(/(\r\n|\r|\n)/g, '##STACK_BR##'));
  buffer.push('##PE_STACK_END##');
  return buffer.join('');
};

/**
 * Get the index for a function. Used for internal indexing.
 * @param {boolean} wrapper True for the wrapper; false for the wrapped.
 * @return {string} The index where we should store the function in its
 *     wrapper/wrapped function.
 * @private
 */
goog.debug.ErrorHandler.prototype.getFunctionIndex_ = function(wrapper) {
  return (wrapper ? '__wrapper_' : '__protected_') + goog.getUid(this) + '__';
};

/**
 * Installs exception protection for an entry point function. When an exception
 * is thrown from a protected function, a handler will be invoked to handle it.
 *
 * @param {Function} fn An entry point function to be protected.
 * @return {!Function} A protected wrapper function that calls the entry point
 *     function.
 */
goog.debug.ErrorHandler.prototype.protectEntryPoint = function(fn) {
  var protectedFnName = this.getFunctionIndex_(true);
  if (!fn[protectedFnName]) {
    var wrapper = fn[protectedFnName] = this.getProtectedFunction(fn);
    wrapper[this.getFunctionIndex_(false)] = fn;
  }
  return fn[protectedFnName];
};

/**
 * Helps {@link #protectEntryPoint} by actually creating the protected
 * wrapper function, after {@link #protectEntryPoint} determines that one does
 * not already exist for the given function.  Can be overriden by subclasses
 * that may want to implement different error handling, or add additional
 * entry point hooks.
 * @param {!Function} fn An entry point function to be protected.
 * @return {!Function} protected wrapper function.
 * @protected
 */
goog.debug.ErrorHandler.prototype.getProtectedFunction = function(fn) {
  var that = this;
  var tracers = this.addTracersToProtectedFunctions_;
  if (tracers) {
    var stackTrace = goog.debug.getStacktraceSimple(15);
  }
  var result = function() {
    if (that.isDisposed()) {
      return fn.apply(this, arguments);
    }

    if (tracers) {
      var tracer = goog.debug.Trace.startTracer('protectedEntryPoint: ' +
          that.getStackTraceHolder_(stackTrace));
    }
    try {
      return fn.apply(this, arguments);
    } catch (e) {
      that.errorHandlerFn_(e);
      throw e;  // Re-throw it since this may be expected by the caller.
    } finally {
      if (tracers) {
        goog.debug.Trace.stopTracer(tracer);
      }
    }
  };
  result[this.getFunctionIndex_(false)] = fn;
  return result;
};

/**
 * Installs exception protection for window.setTimeout to handle exceptions.
 */
goog.debug.ErrorHandler.prototype.protectWindowSetTimeout =
    function() {
  this.protectWindowFunctionsHelper_('setTimeout');
};

/**
 * Install exception protection for window.setInterval to handle exceptions.
 */
goog.debug.ErrorHandler.prototype.protectWindowSetInterval =
    function() {
  this.protectWindowFunctionsHelper_('setInterval');
};

/**
 * Helper function for protecting setTimeout/setInterval.
 * @param {string} fnName The name of the function we're protecting. Must
 *     be setTimeout or setInterval.
 * @private
 */
goog.debug.ErrorHandler.prototype.protectWindowFunctionsHelper_ =
    function(fnName) {
  var win = goog.getObjectByName('window');
  var originalFn = win[fnName];
  var that = this;
  win[fnName] = function(fn, time) {
    // Don't try to protect strings. In theory, we could try to globalEval
    // the string, but this seems to lead to permission errors on IE6.
    if (goog.isString(fn)) {
      fn = goog.partial(goog.globalEval, fn);
    }
    fn = that.protectEntryPoint(fn);

    // IE doesn't support .call for setInterval/setTimeout, but it
    // also doesn't care what "this" is, so we can just call the
    // original function directly
    if (originalFn.call) {
      return originalFn.call(this, fn, time);
    } else {
      return originalFn(fn, time);
    }
  };
  win[fnName][this.getFunctionIndex_(false)] = originalFn;
};

/** @inheritDoc */
goog.debug.ErrorHandler.prototype.disposeInternal = function() {
  // Try to unwrap window.setTimeout and window.setInterval.
  var win = goog.getObjectByName('window');
  win.setTimeout = this.unwrap(win.setTimeout);
  win.setInterval = this.unwrap(win.setInterval);

  goog.base(this, 'disposeInternal');
};
<|endoftext|>


<commit_before>/**
 * @overview ccm component for building fill-in-the-blank texts
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

( function () {

  var ccm_version = '8.0.0';
  var ccm_url     = '../../ccm-developer/ccm/ccm.js';

  var component_name = 'cloze_builder';
  var component_obj  = {

    name: component_name,

    config: {

      html_templates: {
        main: {
          id: 'main',
          inner: [
            { id: 'input_mask' },
            { id: 'cloze_preview' }
          ]
        },
        preview: {
          tag: 'fieldset',
          inner: [
            { tag: 'legend' },
            { id: 'preview' }
          ]
        }
      },
      css_layout: [ 'ccm.load', '../cloze_builder/layouts/default.css' ],
      input_mask: [ 'ccm.component', '../input/ccm.input.js', {
        css_layout: [ 'ccm.load', '../input/layouts/table.css' ],
        inputs: [
          {
            label: 'Layout',
            name: 'css_layout',
            input: 'select',
            options: [
              {
                value: "['ccm.load','../cloze/layouts/default.css']",
                caption: 'Standard-Layout'
              },
              {
                value: "['ccm.load','../cloze/layouts/lea.css']",
                caption: 'LEA-ähnliches Layout'
              }
            ]
          },
          {
            label: 'Lückentext',
            name: 'text',
            input: 'textarea',
            placeholder: 'Hello, [[(W)o(rl)d]]!'
          },
          {
            label: 'Vorgegebene Lösungswörter',
            name: 'keywords',
            input: 'checkbox'
          },
          {
            label: 'Individuelle Lösungswörter',
            name: 'keyword_list',
            input: 'textarea'
          },
          {
            label: 'Leere Eingabefelder',
            name: 'blank',
            input: 'checkbox'
          },
          {
            label: 'Groß- und Kleinschreibung ignorieren',
            name: 'ignore_case',
            input: 'checkbox'
          },
          {
            label: 'Punkte pro Lückenfeld',
            name: 'points_per_gap',
            input: 'number',
            min: 1
          },
          {
            label: 'Zeitlimit (in Sekunden)',
            name: 'time',
            input: 'number',
            min: 1
          },
          {
            label: 'Beschriftung des Buttons',
            name: 'button_caption',
            input: 'text'
          },
          {
            label: 'Nutzerkreis',
            name: 'user',
            input: 'select',
            options: [
              {
                value: ' ',
                caption: 'Öffentlich'
              },
              {
                value: "['ccm.instance','../user/ccm.user.js',{'sign_on':'guest'}]",
                caption: 'Gast'
              },
              {
                value: "['ccm.instance','../user/ccm.user.js',{'sign_on':'demo'}]",
                caption: 'Demo'
              },
              {
                value: "['ccm.instance','../user/ccm.user.js',{'sign_on':'hbrsinfkaul'}]",
                caption: 'FB02'
              },
              {
                value: '',
                caption: 'LEA (not yet)'
              },
              {
                value: '',
                caption: 'OpenOLAT (not yet)'
              }
            ]
          }
        ]
      } ]

  //  cloze_preview: [ 'ccm.component', '../cloze/ccm.cloze.js' ],
  //  initial_data: {},
  //  onfinish: function ( instance, results ) { console.log( results ); }

    },

    Instance: function () {

      var self = this;
      var my;           // contains privatized instance members

      this.ready = function ( callback ) {

        // privatize all possible instance members
        my = self.ccm.helper.privatize( self );

        callback();
      };

      this.start = function ( callback ) {

        // show loading icon until rendering is finished
        self.ccm.helper.hide( self );

        // prepare main HTML structure
        var main_elem = self.ccm.helper.html( my.html_templates.main );
        var preview_elem = main_elem.querySelector( '#cloze_preview' );

        // set content of own website area (not visible yet)
        self.ccm.helper.setContent( self.element, self.ccm.helper.protect( main_elem ) );

        // prepare initial dataset
        var initial_data; prepareInitialData();

        // render input mask
        my.input_mask.start( {

          element: main_elem.querySelector( '#input_mask' ),
          initial_data: initial_data,
          onchange: function ( instance, results, name ) {

            // show/hide post-relevant entries
            if ( name === 'keywords' ) instance.element.querySelector( '.entry[data-name=keyword_list]' ).classList.toggle( 'hidden' );

            // prepare result data
            prepareResults( results );

            // update preview container
            renderPreview( results );

          },
          onfinish: function ( instance, results ) {

            // prepare result data
            prepareResults( results );

            // provide result data
            self.ccm.helper.onFinish( self, results );

          }

        }, function ( input_mask ) {

          // hide post-relevant entries
          if ( !input_mask.element.querySelector( 'input[name=keywords]' ).checked ) input_mask.element.querySelector( '.entry[data-name=keyword_list]' ).classList.add( 'hidden' );

          // replace loading icon with hidden rendered content
          self.ccm.helper.show( self );

          // render preview
          renderPreview( my.initial_data );

          if ( callback ) callback();
        } );

        /** prepares the initial dataset */
        function prepareInitialData() {

          // no initial dataset? => abort
          if ( !my.initial_data ) return;

          // clone initial dataset
          initial_data = self.ccm.helper.clone( my.initial_data );

          // handle values of post-relevant properties
          if ( Array.isArray( initial_data.keywords ) ) {
            initial_data.keyword_list = initial_data.keywords.join( ' ' );
            initial_data.keywords = true;
          }

          // encode ccm dependencies in initial dataset
          self.ccm.helper.encodeDependencies( initial_data );

        }

        /** prepares the result data */
        function prepareResults( results ) {

          // handle values of post-relevant properties
          if ( results.keywords && results.keyword_list ) results.keywords = results.keyword_list.split( /\s+/ );
          delete results.keyword_list;

          // decode ccm dependencies in result data
          self.ccm.helper.decodeDependencies( results );

        }

        /** renders preview of build fill-in-the-blank text */
        function renderPreview( config ) {

          if ( !my.cloze_preview ) return;
          self.ccm.helper.setContent( preview_elem, self.ccm.helper.protect( self.ccm.helper.html( my.html_templates.preview ) ) );
          my.cloze_preview.start( { key: config, element: preview_elem.querySelector( '#preview' ) } );

        }

      }

    }

  };

  var namespace = window.ccm && ccm.components[ component_name ]; if ( namespace ) { if ( namespace.ccm_version ) ccm_version = namespace.ccm_version; if ( namespace.ccm_url ) ccm_url = namespace.ccm_url; }
  if ( !window.ccm || !ccm[ ccm_version ] ) { var tag = document.createElement( 'script' ); document.head.appendChild( tag ); tag.onload = register; tag.src = ccm_url; } else register();
  function register() { ccm[ ccm_version ].component( component_obj ); }
}() );<commit_msg>minor changes<commit_after>/**
 * @overview ccm component for building fill-in-the-blank texts
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

( function () {

  var ccm_version = '8.0.0';
  var ccm_url     = '../../ccm-developer/ccm/ccm.js';

  var component_name = 'cloze_builder';
  var component_obj  = {

    name: component_name,

    config: {

      html_templates: {
        main: {
          id: 'main',
          inner: [
            { id: 'input_mask' },
            { id: 'cloze_preview' }
          ]
        },
        preview: {
          tag: 'fieldset',
          inner: [
            { tag: 'legend' },
            { id: 'preview' }
          ]
        }
      },
      css_layout: [ 'ccm.load', '../cloze_builder/layouts/default.css' ],
      input_mask: [ 'ccm.component', '../input/ccm.input.js', {
        css_layout: [ 'ccm.load', '../input/layouts/table.css' ],
        inputs: [
          {
            label: 'Layout',
            name: 'css_layout',
            input: 'select',
            options: [
              {
                value: "['ccm.load','../cloze/layouts/default.css']",
                caption: 'Standard-Layout'
              },
              {
                value: "['ccm.load','../cloze/layouts/lea.css']",
                caption: 'LEA-ähnliches Layout'
              }
            ]
          },
          {
            label: 'Lückentext',
            name: 'text',
            input: 'textarea',
            placeholder: 'Hello, [[(W)o(rl)d]]!'
          },
          {
            label: 'Vorgegebene Lösungswörter',
            name: 'keywords',
            input: 'checkbox'
          },
          {
            label: 'Individuelle Lösungswörter',
            name: 'keyword_list',
            input: 'textarea'
          },
          {
            label: 'Leere Eingabefelder',
            name: 'blank',
            input: 'checkbox'
          },
          {
            label: 'Groß- und Kleinschreibung ignorieren',
            name: 'ignore_case',
            input: 'checkbox'
          },
          {
            label: 'Punkte pro Lückenfeld',
            name: 'points_per_gap',
            input: 'number',
            min: 1
          },
          {
            label: 'Zeitlimit (in Sekunden)',
            name: 'time',
            input: 'number',
            min: 1
          },
          {
            label: 'Beschriftung des Buttons',
            name: 'button_caption',
            input: 'text'
          },
          {
            label: 'Nutzerkreis',
            name: 'user',
            input: 'select',
            options: [
              {
                value: ' ',
                caption: 'Öffentlich'
              },
              {
                value: "['ccm.instance','../user/ccm.user.js',{'sign_on':'guest'}]",
                caption: 'Gast'
              },
              {
                value: "['ccm.instance','../user/ccm.user.js',{'sign_on':'demo'}]",
                caption: 'Demo'
              },
              {
                value: "['ccm.instance','../user/ccm.user.js',{'sign_on':'hbrsinfkaul'}]",
                caption: 'FB02'
              },
              {
                value: '',
                caption: 'LEA (not yet)'
              },
              {
                value: '',
                caption: 'OpenOLAT (not yet)'
              }
            ]
          }
        ]
      } ]

  //  initial_data: {},
  //  cloze_preview: [ 'ccm.component', '../cloze/ccm.cloze.js' ],
  //  onfinish: function ( instance, results ) { console.log( results ); }

    },

    Instance: function () {

      var self = this;
      var my;           // contains privatized instance members

      this.ready = function ( callback ) {

        // privatize all possible instance members
        my = self.ccm.helper.privatize( self );

        callback();
      };

      this.start = function ( callback ) {

        // show loading icon until rendering is finished
        self.ccm.helper.hide( self );

        // prepare main HTML structure
        var main_elem = self.ccm.helper.html( my.html_templates.main );
        var preview_elem = main_elem.querySelector( '#cloze_preview' );

        // set content of own website area (not visible yet)
        self.ccm.helper.setContent( self.element, self.ccm.helper.protect( main_elem ) );

        // prepare initial dataset
        var initial_data; prepareInitialData();

        // render input mask
        my.input_mask.start( {

          element: main_elem.querySelector( '#input_mask' ),
          initial_data: initial_data,
          onchange: function ( instance, results, name ) {

            // show/hide post-relevant entries
            if ( name === 'keywords' ) instance.element.querySelector( '.entry[data-name=keyword_list]' ).classList.toggle( 'hidden' );

            // prepare result data
            prepareResults( results );

            // update preview container
            renderPreview( results );

          },
          onfinish: function ( instance, results ) {

            // prepare result data
            prepareResults( results );

            // provide result data
            self.ccm.helper.onFinish( self, results );

          }

        }, function ( input_mask ) {

          // hide post-relevant entries
          if ( !input_mask.element.querySelector( 'input[name=keywords]' ).checked ) input_mask.element.querySelector( '.entry[data-name=keyword_list]' ).classList.add( 'hidden' );

          // replace loading icon with hidden rendered content
          self.ccm.helper.show( self );

          // render preview
          renderPreview( my.initial_data );

          if ( callback ) callback();
        } );

        /** prepares the initial dataset */
        function prepareInitialData() {

          // no initial dataset? => abort
          if ( !my.initial_data ) return;

          // clone initial dataset
          initial_data = self.ccm.helper.clone( my.initial_data );

          // handle values of post-relevant properties
          if ( Array.isArray( initial_data.keywords ) ) {
            initial_data.keyword_list = initial_data.keywords.join( ' ' );
            initial_data.keywords = true;
          }

          // encode ccm dependencies in initial dataset
          self.ccm.helper.encodeDependencies( initial_data );

        }

        /** prepares the result data */
        function prepareResults( results ) {

          // handle values of post-relevant properties
          if ( results.keywords && results.keyword_list ) results.keywords = results.keyword_list.split( /\s+/ );
          delete results.keyword_list;

          // decode ccm dependencies in result data
          self.ccm.helper.decodeDependencies( results );

        }

        /** renders preview of build fill-in-the-blank text */
        function renderPreview( config ) {

          if ( !my.cloze_preview ) return;
          self.ccm.helper.setContent( preview_elem, self.ccm.helper.protect( self.ccm.helper.html( my.html_templates.preview ) ) );
          my.cloze_preview.start( { key: config, element: preview_elem.querySelector( '#preview' ) } );

        }

      }

    }

  };

  var namespace = window.ccm && ccm.components[ component_name ]; if ( namespace ) { if ( namespace.ccm_version ) ccm_version = namespace.ccm_version; if ( namespace.ccm_url ) ccm_url = namespace.ccm_url; }
  if ( !window.ccm || !ccm[ ccm_version ] ) { var tag = document.createElement( 'script' ); document.head.appendChild( tag ); tag.onload = register; tag.src = ccm_url; } else register();
  function register() { ccm[ ccm_version ].component( component_obj ); }
}() );<|endoftext|>


<commit_before>;(function(ns, window, undefined){
    var zero = ns.olamedia;
    if (!zero){
        throw new Error("olamedia-js support not found. see https://github.com/olamedia/olamedia-js");
    }
    zero.leader = null;
    var storage = zero.localStorage;
    var JSON = zero.JSON;
    if (!storage || !JSON){
        return;
    }
    var hiddenProperty = 'hidden' in document ? 'hidden' :
                         'webkitHidden' in document ? 'webkitHidden' :
                         'mozHidden' in document ? 'mozHidden' :
                         null;
    var visibilityStateProperty = 'visibilityState' in document ? 'visibilityState' :
                                  'webkitVisibilityState' in document ? 'webkitVisibilityState' :
                                  'mozVisibilityState' in document ? 'mozVisibilityState' :
                                  null;
    var storagePrefix = 'olamedia/vote/';
    var elect = function(peers){
        var self = this;
        var m = 99999;
        var leader = null;
        for (var k in peers){
            var t = peers[k];
            var dt = zero.microtime() - t;
            if (dt < m){
                m = dt;
                leader = k;
            }
        }
        return leader;
    };
    var filterPeers = function(peers){
        var leader = elect(peers);
        if (leader){
            var lt = peers[leader];
            var ldt = zero.microtime() - lt;
            for (var k in peers){
                if (leader != k){
                    var t = peers[k];
                    var dt = zero.microtime() - t;
                    if (dt > ldt + 10){
                        if (Object.keys(peers).length >= 1){
                            delete peers[k];
                        }
                    }
                }
            }
        }
        return peers;
    };
    var Vote = zero.Class.fextend(function Vote(){
        this.init();
    }, {
        id: null,
        leader: null,
        activeTime: null,
        callbacks: [],
        isLeader: function(){
            var self = this;
            return self.id === self.leader;
        },
        setTime: function(t){
            var self = this;
            if (self.activeTime){
                if (self.isLeader() && (t < self.activeTime + 10)){
                    // too fast, we're a leader already
                    return;
                }
            }
            self.activeTime = t;
            // update peer list
            var peers = self.getPeers();
            peers[self.id] = self.activeTime;
            peers = filterPeers(peers);
            storage[storagePrefix + 'peers'] = JSON.stringify(peers);
        },
        up: function(){ // update time, vote up for self
            var self = this;
            self.setTime(zero.microtime());
            self.vote();
        },
        down: function(){
            var self = this;
            self.setTime(0);
            self.vote();
        },
        vote: function(){
            var self = this;
            var leader = elect(self.getPeers());
            if (leader){
                self.accept(leader, true);
            }
        },
        accept: function(leader, force){
            var self = this;
            if (leader !== self.leader){
                self.leader = leader;
                if (self.callbacks.length){
                    for (var k in self.callbacks){
                        self.callbacks[k](leader);
                    }
                }
            }
            if (force){
                storage[storagePrefix + 'leader'] = leader;
            }
        },
        getPeers: function(){
            var self = this;
            var peers = storage[storagePrefix + 'peers'] || {};
            if (typeof peers === 'string') {
                try{
                    peers = JSON.parse(peers);
                }catch(e){
                }
            }
            if (typeof peers !== 'object') {
                peers = {};
            }
            peers = filterPeers(peers);
            return peers;
        },
        init: function(){
            var self = this;
            self.id = zero.uuidv4();
            self.up();
            zero.on('storage', function(e){
                if (e.key == storagePrefix + 'leader'){
                    self.accept(e.newValue, false);
                }
            });
            var list = ['focus', 'mouseover', 'touchenter', 'pointerenter', 'keydown', 'keyup'];
            for (var k in list){
                zero.on(list[k], function(){
                    self.up();
                });
            }
            zero.on('beforeunload', function(){
                self.down();
            });
            if (hiddenProperty === null || visibilityStateProperty === null) {
            }else{
                var visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
                zero.don(visibilityChangeEvent, function(){
                    self.up();
                });
            }
        },
        onChange: function(callback){
            var self = this;
            if (callback){
                self.callbacks.push(callback);
                if (self.leader){
                    callback(self.leader);
                }
            }
        },
    });
    zero.leader = new Vote();
})(this, window);
<commit_msg>added onLead()<commit_after>;(function(ns, window, undefined){
    var zero = ns.olamedia;
    if (!zero){
        throw new Error("olamedia-js support not found. see https://github.com/olamedia/olamedia-js");
    }
    zero.leader = null;
    var storage = zero.localStorage;
    var JSON = zero.JSON;
    if (!storage || !JSON){
        return;
    }
    var hiddenProperty = 'hidden' in document ? 'hidden' :
                         'webkitHidden' in document ? 'webkitHidden' :
                         'mozHidden' in document ? 'mozHidden' :
                         null;
    var visibilityStateProperty = 'visibilityState' in document ? 'visibilityState' :
                                  'webkitVisibilityState' in document ? 'webkitVisibilityState' :
                                  'mozVisibilityState' in document ? 'mozVisibilityState' :
                                  null;
    var storagePrefix = 'olamedia/vote/';
    var elect = function(peers){
        var self = this;
        var m = 99999;
        var leader = null;
        for (var k in peers){
            var t = peers[k];
            var dt = zero.microtime() - t;
            if (dt < m){
                m = dt;
                leader = k;
            }
        }
        return leader;
    };
    var filterPeers = function(peers){
        var leader = elect(peers);
        if (leader){
            var lt = peers[leader];
            var ldt = zero.microtime() - lt;
            for (var k in peers){
                if (leader != k){
                    var t = peers[k];
                    var dt = zero.microtime() - t;
                    if (dt > ldt + 10){
                        if (Object.keys(peers).length >= 1){
                            delete peers[k];
                        }
                    }
                }
            }
        }
        return peers;
    };
    var Vote = zero.Class.fextend(function Vote(){
        this.init();
    }, {
        id: null,
        leader: null,
        activeTime: null,
        callbacks: [],
        leadCallbacks: [],
        isLeader: function(){
            var self = this;
            return self.id === self.leader;
        },
        setTime: function(t){
            var self = this;
            if (self.activeTime){
                if (self.isLeader() && (t < self.activeTime + 10)){
                    // too fast, we're a leader already
                    return;
                }
            }
            self.activeTime = t;
            // update peer list
            var peers = self.getPeers();
            peers[self.id] = self.activeTime;
            peers = filterPeers(peers);
            storage[storagePrefix + 'peers'] = JSON.stringify(peers);
        },
        up: function(){ // update time, vote up for self
            var self = this;
            self.setTime(zero.microtime());
            self.vote();
        },
        down: function(){
            var self = this;
            self.setTime(0);
            self.vote();
        },
        vote: function(){
            var self = this;
            var leader = elect(self.getPeers());
            if (leader){
                self.accept(leader, true);
            }
        },
        accept: function(leader, force){
            var self = this;
            if (leader !== self.leader){
                self.leader = leader;
                if (self.callbacks.length){
                    for (var k in self.callbacks){
                        self.callbacks[k](leader);
                    }
                }
                if (self.isLeader()){
                    if (self.leadCallbacks.length){
                        for (var k in self.leadCallbacks){
                            self.leadCallbacks[k]();
                        }
                    }
                }
            }
            if (force){
                storage[storagePrefix + 'leader'] = leader;
            }
        },
        getPeers: function(){
            var self = this;
            var peers = storage[storagePrefix + 'peers'] || {};
            if (typeof peers === 'string') {
                try{
                    peers = JSON.parse(peers);
                }catch(e){
                }
            }
            if (typeof peers !== 'object') {
                peers = {};
            }
            peers = filterPeers(peers);
            return peers;
        },
        init: function(){
            var self = this;
            self.id = zero.uuidv4();
            self.up();
            zero.on('storage', function(e){
                if (e.key == storagePrefix + 'leader'){
                    self.accept(e.newValue, false);
                }
            });
            var list = ['focus', 'mouseover', 'touchenter', 'pointerenter', 'keydown', 'keyup'];
            for (var k in list){
                zero.on(list[k], function(){
                    self.up();
                });
            }
            zero.on('beforeunload', function(){
                self.down();
            });
            if (hiddenProperty === null || visibilityStateProperty === null) {
            }else{
                var visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
                zero.don(visibilityChangeEvent, function(){
                    self.up();
                });
            }
        },
        onLead: function(callback){
            var self = this;
            if (callback){
                self.leadCallbacks.push(callback);
                if (self.isLeader()){
                    callback(self.leader);
                }
            }
        },
        onChange: function(callback){
            var self = this;
            if (callback){
                self.callbacks.push(callback);
                if (self.leader){
                    callback(self.leader);
                }
            }
        },
    });
    zero.leader = new Vote();
})(this, window);
<|endoftext|>


<commit_before>/*
 Copyright 2015 Province of British Columbia

 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.
 */

'use strict';
// Declare app level module which depends on views, and components
var app = angular.module('bcdevxApp', [
  'bcdevxApp.auth',
  'angulartics',
  'angulartics.google.analytics'
  'ngRoute',
    'ngRoute',
  'bcdevxApp.home',
    'bcdevxApp.home',
  'bcdevxApp.auth',
  'bcdevxApp.account',
  'bcdevxApp.resources'
])
   .config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {

        // check if user is connected
        var checkLoggedIn = function($q, $timeout, $location, AuthService) {
            // initialize a new promise
            var deferred = $q.defer();

            if (AuthService.isAuthenticated()) {
                $timeout(deferred.resolve, 0);
            } else {
                $timeout(function() {deferred.reject();}, 0);
                $location.url('/login');
            }

            return deferred.promise;
        };

        $routeProvider
            .when('/home', {
                templateUrl: 'home/home.html',
                controller: 'HomeCtrl'
            })
            .when('/login', {
                templateUrl: 'auth/login.html',
                controller: 'AuthCtrl'
            })
            .when('/account', {
                templateUrl: 'account/account.html',
                controller: 'AccountCtrl',
                resolve: {
                    loggedin: checkLoggedIn
                }
            })
            .otherwise({redirectTo: '/home'});

        // add an interceptor for AJAX errors
        $httpProvider.responseInterceptors.push(function($q, $location) {
            return function(promise) {
                return promise.then(
                    // success
                    function(response) {
                        return response;
                    },
                    // error
                    function(response) {
                        if (response.status === 401) {
                            $location.url('/login');
                        }
                        return $q.reject(response);
                    }
                );
            }
        });

}]).run(function($rootScope, $http) {
        // Add config to ALL scopes, only makes sense instead of passing in everywhere
        $http.get('/config').
            success(function(data, status, headers, config) {
                $rootScope.config = data;
            });

});

app.directive('showOnLoggedIn', ['$rootScope', 'AuthService', function($rootScope, AuthService) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var prevDisp = element.css('display');
            $rootScope.$watch('user', function(user) {
                if(!AuthService.isAuthenticated())
                    element.css('display', 'none');
                else
                    element.css('display', prevDisp);
            });
        }
    };
    'bcdevxApp.auth',
    'angulartics',
    'angulartics.google.analytics'
]).
config(['$routeProvider', function($routeProvider) {
    $routeProvider.otherwise({redirectTo: '/home'});
}]);

app.directive('showOnLoggedOut', ['$rootScope', 'AuthService', function($rootScope, AuthService) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var prevDisp = element.css('display');
            $rootScope.$watch('user', function(user) {
                if(AuthService.isAuthenticated())
                    element.css('display', 'none');
                else
                    element.css('display', prevDisp);
            });
        }
    };
}]);

app.controller('IndexCtrl', ['$scope', '$location', '$anchorScroll', 'AuthService', function($scope, $location, $anchorScroll, AuthService) {
    $scope.logout = function() {
        AuthService.logout();
    };

}]);

// Init all popovers
$(function () {
    $('[data-toggle="popover"]').popover({html:true})
})

app.controller('IndexCtrl', function($scope, $location, $anchorScroll) {
});<commit_msg>fixed a bad merge<commit_after>/*
 Copyright 2015 Province of British Columbia

 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.
 */

'use strict';
// Declare app level module which depends on views, and components
var app = angular.module('bcdevxApp', [
  'ngRoute',
  'bcdevxApp.home',
  'bcdevxApp.auth',
  'bcdevxApp.account',
  'bcdevxApp.resources',
    'angulartics',
    'angulartics.google.analytics'
])
   .config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {

        // check if user is connected
        var checkLoggedIn = function($q, $timeout, $location, AuthService) {
            // initialize a new promise
            var deferred = $q.defer();

            if (AuthService.isAuthenticated()) {
                $timeout(deferred.resolve, 0);
            } else {
                $timeout(function() {deferred.reject();}, 0);
                $location.url('/login');
            }

            return deferred.promise;
        };

        $routeProvider
            .when('/home', {
                templateUrl: 'home/home.html',
                controller: 'HomeCtrl'
            })
            .when('/login', {
                templateUrl: 'auth/login.html',
                controller: 'AuthCtrl'
            })
            .when('/account', {
                templateUrl: 'account/account.html',
                controller: 'AccountCtrl',
                resolve: {
                    loggedin: checkLoggedIn
                }
            })
            .otherwise({redirectTo: '/home'});

        // add an interceptor for AJAX errors
        $httpProvider.responseInterceptors.push(function($q, $location) {
            return function(promise) {
                return promise.then(
                    // success
                    function(response) {
                        return response;
                    },
                    // error
                    function(response) {
                        if (response.status === 401) {
                            $location.url('/login');
                        }
                        return $q.reject(response);
                    }
                );
            }
        });

}]).run(function($rootScope, $http) {
        // Add config to ALL scopes, only makes sense instead of passing in everywhere
        $http.get('/config').
            success(function(data, status, headers, config) {
                $rootScope.config = data;
            });

});

app.directive('showOnLoggedIn', ['$rootScope', 'AuthService', function($rootScope, AuthService) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var prevDisp = element.css('display');
            $rootScope.$watch('user', function(user) {
                if(!AuthService.isAuthenticated())
                    element.css('display', 'none');
                else
                    element.css('display', prevDisp);
            });
        }
    };
}]);

app.directive('showOnLoggedOut', ['$rootScope', 'AuthService', function($rootScope, AuthService) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var prevDisp = element.css('display');
            $rootScope.$watch('user', function(user) {
                if(AuthService.isAuthenticated())
                    element.css('display', 'none');
                else
                    element.css('display', prevDisp);
            });
        }
    };
}]);

app.controller('IndexCtrl', ['$scope', '$location', '$anchorScroll', 'AuthService', function($scope, $location, $anchorScroll, AuthService) {
    $scope.logout = function() {
        AuthService.logout();
    };

}]);

// Init all popovers
$(function () {
    $('[data-toggle="popover"]').popover({html:true})
})
<|endoftext|>


<commit_before>function add_to_cart(id)
{
    alert('You added pizza with id:' + id);
}

function something()

{

  var x = window.localStorage.getItem('bbb');
  x = x * 1 + 1;
  window.localStorage.setItem('bbb', x)
  alert(x);
}
<commit_msg>Update add_to_cart function<commit_after>function add_to_cart(id)
{
    var key = 'product_' + id;
    var x = window.localStorage.getItem(key);
    x = x*1+1;
    window.localStorage.setItem(key, x);
}

function something()

{

  var x = window.localStorage.getItem('bbb');
  x = x * 1 + 1;
  window.localStorage.setItem('bbb', x)
  alert(x);
}
<|endoftext|>


<commit_before>const xml2js = require('xml2js').parseString,
      Utils = require('./Utils.js').Utils,
      https = require('https');

/**
* Makes a HTTP GET request to the specified URL.
* @param {String} url - URL to make a GET request to
* @param {Function} callback - Callback function containing the returned XML String.
*/
function GetRequest(url, callback) {
    let xml = '';

    https.get(url, (result) => {
        result.on('data', (data) => {
            xml += data;
        });

        result.on('end', _ => {
            callback(xml);
        });
    });
}

/**
* Splits an array into a properly formatted string for URL
* @param {Array} arr - The array to split and restructure
*/
function ArrToUrl(arr) {
    return arr.length === 1 ? arr[0] : arr.join('+');
}

/**
* Builds the URL to make a GET request to.
* @param {Object} props - Passed to getCareers as an object with search parameters.
*/
function UrlBuilder(props) {

    let builtUrl = Utils.UrlPrefix;

    if(props.query) { builtUrl += props.query }

    if(props.location) { builtUrl += Utils.Location + props.location }

    if(props.techDisliked) {
        let EncodedTechDisliked = [];
        props.techDisliked.forEach((tech) => {
            EncodedTechDisliked.push(Utils.EncodeProtectedCharacters(tech))
        });

        builtUrl += Utils.TechDisliked + ArrToUrl(EncodedTechDisliked);
    }

    if(props.techLiked) {
        let EncodedTechLiked = [];
        props.techLiked.forEach((tech) => {
            EncodedTechLiked.push(Utils.EncodeProtectedCharacters(tech))
        });

        builtUrl += Utils.TechLiked + ArrToUrl(EncodedTechLiked);
    }

    if(props.unit) { builtUrl += Utils.Unit + props.unit }

    return builtUrl;
}

/**
* @property {Object} props - Properties for your search
* @property {String} query - Additional information for the search (eg. "Junior" or "remote full time" etc).
* @property {String} location - Location for the job search. Make this as specific as possible.
* @property {String[]} techLiked - An array of technologies prefered. (eg. ["javascript", "c", "Java", "wordpress"])
* @property {String[]} techDisliked - An array of technologies to filter out. (eg. ["fortran", "c++", "AWS"])
* @property {String} Unit - Unit of measurement for distance. Typically this should be miles.
* @param {Function} cb - Callback for the array of objects returned.
*/
function getCareers(props, cb) {
    let url = UrlBuilder(props);

    var data = GetRequest(url, (data) => {
        xml2js(data, (err, jobs) => {
            cb(jobs.rss.channel[0].item)
        });
    });
};

module.exports = {
    getCareers,
};<commit_msg>Fixed the JSDoc, my bad.<commit_after>const xml2js = require('xml2js').parseString,
      Utils = require('./Utils.js').Utils,
      https = require('https');

/**
* Makes a HTTP GET request to the specified URL.
* @param {String} url - URL to make a GET request to
* @param {Function} callback - Callback function containing the returned XML String.
*/
function GetRequest(url, callback) {
    let xml = '';

    https.get(url, (result) => {
        result.on('data', (data) => {
            xml += data;
        });

        result.on('end', _ => {
            callback(xml);
        });
    });
}

/**
* Splits an array into a properly formatted string for URL
* @param {Array} arr - The array to split and restructure
*/
function ArrToUrl(arr) {
    return arr.length === 1 ? arr[0] : arr.join('+');
}

/**
* Builds the URL to make a GET request to.
* @param {Object} props - Passed to getCareers as an object with search parameters.
*/
function UrlBuilder(props) {

    let builtUrl = Utils.UrlPrefix;

    if(props.query) { builtUrl += props.query }

    if(props.location) { builtUrl += Utils.Location + props.location }

    if(props.techDisliked) {
        let EncodedTechDisliked = [];
        props.techDisliked.forEach((tech) => {
            EncodedTechDisliked.push(Utils.EncodeProtectedCharacters(tech))
        });

        builtUrl += Utils.TechDisliked + ArrToUrl(EncodedTechDisliked);
    }

    if(props.techLiked) {
        let EncodedTechLiked = [];
        props.techLiked.forEach((tech) => {
            EncodedTechLiked.push(Utils.EncodeProtectedCharacters(tech))
        });

        builtUrl += Utils.TechLiked + ArrToUrl(EncodedTechLiked);
    }

    if(props.unit) { builtUrl += Utils.Unit + props.unit }

    return builtUrl;
}

/**
* @param {Object} props - Properties for your search
* @param {String} props.query - Additional information for the search (eg. "Junior" or "remote full time" etc).
* @param {String} props.location - Location for the job search. Make this as specific as possible.
* @param {String[]} props.techLiked - An array of technologies prefered. (eg. ["javascript", "c", "Java", "wordpress"])
* @param {String[]} props.techDisliked - An array of technologies to filter out. (eg. ["fortran", "c++", "AWS"])
* @param {String} props.unit - Unit of measurement for distance. Typically this should be miles.
* @param {Function} cb - Callback for the array of objects returned.
*/
function getCareers(props, cb) {
    let url = UrlBuilder(props);

    var data = GetRequest(url, (data) => {
        xml2js(data, (err, jobs) => {
            cb(jobs.rss.channel[0].item)
        });
    });
};

module.exports = {
    getCareers,
};<|endoftext|>


<commit_before>/*
 * The webapp module provides support for building web applications in Helma NG.
 */

// import modules
require('core/string');

include('helma/webapp/request');
include('helma/webapp/response');

import('helma/system', 'system');
import('helma/httpserver', 'server');
import('helma/logging', 'logging');

export('start', 'stop', 'getConfig', 'handleRequest', 'error', 'notfound');

var log = logging.getLogger(__name__);

var __shared__ = true;

/**
 * Handler function called by the Jack servlet.
 *
 * @param env the jack environment argument
 */
function handleRequest(env) {
    // get config and apply it to req, res
    var config = getConfig();
    if (log.debugEnabled) log.debug('got config: ' + config.toSource());

    var req = new Request(env);
    var res = null;
    // set up jack env, request and config properties in per-request env module
    var webenv = require('helma/webapp/env');
    webenv.init(env, req, config);

    req.charset = config.charset || 'utf8';

    // resolve path and invoke action
    var path = req.path;
    if (path.startsWith('/')) {
        // strip leading slash
        path = path.slice(1);
    }
    // used to compose req.actionPath, which is the part of the path
    // that resolves to the action (req.path minus argument elements)
    var actionPath = ["/"];

    function getPattern(spec) {
        var pattern = spec[0];
        if (typeof pattern == "string") {
            if (pattern.startsWith("/"))
                pattern = pattern.replace("/", "^");
            pattern = spec[0] = new RegExp(pattern);
        } else if (!(pattern instanceof RegExp)) {
            throw Error("Pattern must be a regular expression or string");
        }
        return pattern;
    }

    function getModule(spec, prefix) {
        var module = spec[1];
        if (typeof module == "string") {
            module = require(prefix + module);
        } else if (!(module instanceof Object)) {
            throw Error("Module must be a string or object");
        }
        return module;
    }

    function getAction(module, name) {
        name = name || "index";
        var action = module[name.replace(/\./g, "_")];
        if (typeof action == "function") {
            return action;
        }
        return null;
    }

    function resolveInConfig(config, path, prefix) {
        if (log.isDebugEnabled) log.debug('resolving path ' + path);
        if (config.urls instanceof Array) {
            var urls = config.urls;
            for (var i = 0; i < urls.length; i++) {
                if (log.isDebugEnabled) log.debug("checking url line: " + urls[i]);
                var match = getPattern(urls[i]).exec(path);
                if (log.isDebugEnabled) log.debug("got match: " + match);
                if (match != null) {
                    var module = getModule(urls[i], prefix);
                    if (log.isDebugEnabled) log.debug("module: " + module);
                    // cut matching prefix from path
                    path = path.substring(match[0].length);
                    // remove leading and trailing slashes
                    path = path.replace(/^\/+|\/+$/g, "");
                    //split
                    var pathArray = path.split(/\/+/);
                    var action = getAction(module, pathArray[0]);
                    // log.debug("got action: " + action);
                    if (typeof action == "function" && pathArray.length <= action.length) {
                        // set req.actionPath to the part of the path that resolves to the action
                        actionPath.push(match[0], pathArray[0] || "index");
                        req.actionPath =  actionPath.join("/").replace(/\/+/g, "/");
                        print(req.actionPath);
                        // add remaining path elements as additional action arguments
                        var actionArgs = pathArray.slice(1);
                        var matchedArgs = match.slice(1);
                        var args = [req].concat(matchedArgs).concat(actionArgs);
                        var middleware = config.middleware;
                        var middlewareIndex = 0;
                        // set up middleware chain in request object
                        req.process = function() {
                            if (middlewareIndex < middleware.length) {
                                return invokeMiddleware(middleware[middlewareIndex++], [req]);
                            } else {
                                return action.apply(module, args);
                            }
                        }
                        return req.process();
                    } else if (module.urls instanceof Array) {
                        // nested app
                        actionPath.push(match[0]);
                        return resolveInConfig(module, path, match[0]);
                    } else {
                        break;
                    }
                }
            }
        }
    }

    try {
        res = resolveInConfig(config, decodeURI(path), "");
    } catch (e) {
        if (e.retry) {
            throw e;
        } else if (e.redirect) {
            return new RedirectResponse(e.redirect);
        } else {
            res = error(req, e);
        }
    } finally {
        // TODO
        if (!res)
            res = notfound(req);
        if (!(res instanceof Array) && res.close)
            res = res.close();
    }
    return res;
}

function invokeMiddleware(middleware, args) {
    var functionName = 'handleRequest';
    var dot = middleware.indexOf('.');
    if (dot > -1) {
        functionName = middleware.substring(dot + 1);
        middleware = middleware.substring(0, dot);
    }
    var module = require(middleware);
    if (typeof module[functionName] !== 'function') {
        throw new Error('Middleware function ' + functionName + ' is not defined in ' + middleware);
    }
    log.debug('invoking middleware: ' + middleware);
    return module[functionName].apply(module, args);
}

/**
 * Standard error page
 * @param e the error that happened
 */
function error(req, e) {
    var res = new Response();
    res.status = 500;
    res.contentType = 'text/html';
    res.writeln('
', e, '
');
    if (e.fileName && e.lineNumber) {
        res.writeln('
In file', e.fileName, 'at line', e.lineNumber, '
');
    }
    if (e.rhinoException) {
        res.writeln('
Script Stack
');
        res.writeln('
', e.rhinoException.scriptStackTrace, '
');
        res.writeln('
Java Stack
');
        var writer = new java.io.StringWriter();
        var printer = new java.io.PrintWriter(writer);
        e.rhinoException.printStackTrace(printer);
        res.writeln('
', writer.toString(), '
');
        log.error(e.toString(), e.rhinoException);
    } else {
        log.error(e.toString());
    }
    return res.close();
}

/**
 * Standard notfound page
 */
function notfound(req) {
    var res = new Response();
    res.status = 404;
    res.contentType = 'text/html';
    res.writeln('
Not Found
');
    res.writeln('The requested URL', req.pathDecoded, 'was not found on the server.');
    return res.close();
}

/**
 * Try to load the configuration module.
 * @param configModuleName optional module name, default is 'config'
 */
function getConfig(configModuleName) {
    configModuleName = configModuleName || 'config';
    var config;
    try {
        config = require(configModuleName);
    } catch (noConfig) {
        log.info('Couldn\'t load config module: ' + noConfig);
    }
    return config || {};
}

/**
 * Start the jetty server.
 */
function start(config) {
    // start jetty http server
    config = config || getConfig();
    var httpConfig = config.httpConfig;
    server.start(httpConfig);
}

/**
 * Stop the jetty server.
 */
function stop() {
    // stop jetty HTTP server
    server.stop();
}

if (__name__ == '__main__') {
    for (var i = 1; i < system.args.length; i++) {
        var arg = system.args[i];
        if (arg.indexOf('-') == 0) {
            break;
        }
        system.addRepository(arg);
    }
    log.info('Setup module search: ' + system.getRepositories());
    start();
}
<commit_msg>Remove print() statement<commit_after>/*
 * The webapp module provides support for building web applications in Helma NG.
 */

// import modules
require('core/string');

include('helma/webapp/request');
include('helma/webapp/response');

import('helma/system', 'system');
import('helma/httpserver', 'server');
import('helma/logging', 'logging');

export('start', 'stop', 'getConfig', 'handleRequest', 'error', 'notfound');

var log = logging.getLogger(__name__);

var __shared__ = true;

/**
 * Handler function called by the Jack servlet.
 *
 * @param env the jack environment argument
 */
function handleRequest(env) {
    // get config and apply it to req, res
    var config = getConfig();
    if (log.debugEnabled) log.debug('got config: ' + config.toSource());

    var req = new Request(env);
    var res = null;
    // set up jack env, request and config properties in per-request env module
    var webenv = require('helma/webapp/env');
    webenv.init(env, req, config);

    req.charset = config.charset || 'utf8';

    // resolve path and invoke action
    var path = req.path;
    if (path.startsWith('/')) {
        // strip leading slash
        path = path.slice(1);
    }
    // used to compose req.actionPath, which is the part of the path
    // that resolves to the action (req.path minus argument elements)
    var actionPath = ["/"];

    function getPattern(spec) {
        var pattern = spec[0];
        if (typeof pattern == "string") {
            if (pattern.startsWith("/"))
                pattern = pattern.replace("/", "^");
            pattern = spec[0] = new RegExp(pattern);
        } else if (!(pattern instanceof RegExp)) {
            throw Error("Pattern must be a regular expression or string");
        }
        return pattern;
    }

    function getModule(spec, prefix) {
        var module = spec[1];
        if (typeof module == "string") {
            module = require(prefix + module);
        } else if (!(module instanceof Object)) {
            throw Error("Module must be a string or object");
        }
        return module;
    }

    function getAction(module, name) {
        name = name || "index";
        var action = module[name.replace(/\./g, "_")];
        if (typeof action == "function") {
            return action;
        }
        return null;
    }

    function resolveInConfig(config, path, prefix) {
        if (log.isDebugEnabled) log.debug('resolving path ' + path);
        if (config.urls instanceof Array) {
            var urls = config.urls;
            for (var i = 0; i < urls.length; i++) {
                if (log.isDebugEnabled) log.debug("checking url line: " + urls[i]);
                var match = getPattern(urls[i]).exec(path);
                if (log.isDebugEnabled) log.debug("got match: " + match);
                if (match != null) {
                    var module = getModule(urls[i], prefix);
                    if (log.isDebugEnabled) log.debug("module: " + module);
                    // cut matching prefix from path
                    path = path.substring(match[0].length);
                    // remove leading and trailing slashes
                    path = path.replace(/^\/+|\/+$/g, "");
                    //split
                    var pathArray = path.split(/\/+/);
                    var action = getAction(module, pathArray[0]);
                    // log.debug("got action: " + action);
                    if (typeof action == "function" && pathArray.length <= action.length) {
                        // set req.actionPath to the part of the path that resolves to the action
                        actionPath.push(match[0], pathArray[0] || "index");
                        req.actionPath =  actionPath.join("/").replace(/\/+/g, "/");
                        // add remaining path elements as additional action arguments
                        var actionArgs = pathArray.slice(1);
                        var matchedArgs = match.slice(1);
                        var args = [req].concat(matchedArgs).concat(actionArgs);
                        var middleware = config.middleware;
                        var middlewareIndex = 0;
                        // set up middleware chain in request object
                        req.process = function() {
                            if (middlewareIndex < middleware.length) {
                                return invokeMiddleware(middleware[middlewareIndex++], [req]);
                            } else {
                                return action.apply(module, args);
                            }
                        }
                        return req.process();
                    } else if (module.urls instanceof Array) {
                        // nested app
                        actionPath.push(match[0]);
                        return resolveInConfig(module, path, match[0]);
                    } else {
                        break;
                    }
                }
            }
        }
    }

    try {
        res = resolveInConfig(config, decodeURI(path), "");
    } catch (e) {
        if (e.retry) {
            throw e;
        } else if (e.redirect) {
            return new RedirectResponse(e.redirect);
        } else {
            res = error(req, e);
        }
    } finally {
        // TODO
        if (!res)
            res = notfound(req);
        if (!(res instanceof Array) && res.close)
            res = res.close();
    }
    return res;
}

function invokeMiddleware(middleware, args) {
    var functionName = 'handleRequest';
    var dot = middleware.indexOf('.');
    if (dot > -1) {
        functionName = middleware.substring(dot + 1);
        middleware = middleware.substring(0, dot);
    }
    var module = require(middleware);
    if (typeof module[functionName] !== 'function') {
        throw new Error('Middleware function ' + functionName + ' is not defined in ' + middleware);
    }
    log.debug('invoking middleware: ' + middleware);
    return module[functionName].apply(module, args);
}

/**
 * Standard error page
 * @param e the error that happened
 */
function error(req, e) {
    var res = new Response();
    res.status = 500;
    res.contentType = 'text/html';
    res.writeln('
', e, '
');
    if (e.fileName && e.lineNumber) {
        res.writeln('
In file', e.fileName, 'at line', e.lineNumber, '
');
    }
    if (e.rhinoException) {
        res.writeln('
Script Stack
');
        res.writeln('
', e.rhinoException.scriptStackTrace, '
');
        res.writeln('
Java Stack
');
        var writer = new java.io.StringWriter();
        var printer = new java.io.PrintWriter(writer);
        e.rhinoException.printStackTrace(printer);
        res.writeln('
', writer.toString(), '
');
        log.error(e.toString(), e.rhinoException);
    } else {
        log.error(e.toString());
    }
    return res.close();
}

/**
 * Standard notfound page
 */
function notfound(req) {
    var res = new Response();
    res.status = 404;
    res.contentType = 'text/html';
    res.writeln('
Not Found
');
    res.writeln('The requested URL', req.pathDecoded, 'was not found on the server.');
    return res.close();
}

/**
 * Try to load the configuration module.
 * @param configModuleName optional module name, default is 'config'
 */
function getConfig(configModuleName) {
    configModuleName = configModuleName || 'config';
    var config;
    try {
        config = require(configModuleName);
    } catch (noConfig) {
        log.info('Couldn\'t load config module: ' + noConfig);
    }
    return config || {};
}

/**
 * Start the jetty server.
 */
function start(config) {
    // start jetty http server
    config = config || getConfig();
    var httpConfig = config.httpConfig;
    server.start(httpConfig);
}

/**
 * Stop the jetty server.
 */
function stop() {
    // stop jetty HTTP server
    server.stop();
}

if (__name__ == '__main__') {
    for (var i = 1; i < system.args.length; i++) {
        var arg = system.args[i];
        if (arg.indexOf('-') == 0) {
            break;
        }
        system.addRepository(arg);
    }
    log.info('Setup module search: ' + system.getRepositories());
    start();
}
<|endoftext|>


<commit_before>var fs = require('fs');
var commands = require('./commands');
var units = require('./units');
var upgrades = require('./upgrades');
var research = require('./research');
var abbrevs = require('./abbrevs.json');

var pyaiText;
var aiscript;
var currentRace;

var binaryFilename = 'build/aiscript.bin';

fs.writeFileSync(binaryFilename, '');

function reset() {
    pyaiText = '';
    aiscript = {
        buf: new Buffer(32000),
        length: 0,
        cursor: 0,
        getAddress: function () {
            return this.cursor + 4;
        }
    };
    currentRace = '';
}
reset();

// Add ai commands
Object.keys(commands).forEach(function (command, i) {
    exports[command] = generateCommandFunction(command, commands[command].params);
});

// Add abbreviations
Object.keys(abbrevs).forEach(function (abbrev, i) {
    function clean(str) {
        str = str.toLowerCase();
        str = str.replace(/ /g, '_');
        return str;
    }

    exports[clean(abbrev)] = abbrev;
    abbrevs[abbrev].forEach(function(shortcut) {
        exports[clean(shortcut)] = abbrev;
    });
});

function checkParams(validParams, params) {
    var ret = [];

    validParams.forEach(function (validParam, i) {
        if(validParam === 'priority' && params[i] === undefined) {
            params[i] = 80;
        }

        ret.push(params[i]);
    });

    return ret;
}

function append(str) {
    pyaiText += str;
}

function binWrite(b) {
    aiscript.buf[aiscript.cursor] = b;
    aiscript.cursor += 1;
    aiscript.length += 1;
}

function binWriteWord(w) {
    aiscript.buf.writeUInt16LE(w, aiscript.cursor)
    aiscript.cursor += 2;
    aiscript.length += 2;
}

function appendCommand(command) {
    pyaiText += command + '(';
    binWrite(commands[command].op);
}

function appendArg(val, type) {
    pyaiText += val + ',';

    switch (type) {
        case 'byte':
        case 'priority':
            binWrite(val);
            break;
        case 'address':
        case 'word':
            binWriteWord(val);
            break;
        case 'building':
        case 'unit':
        case 'military':
            binWriteWord(units[val].id);
            break;
        default:
            console.error('Type not recognized: ' + type);
    }
}

function closeCommand() {
    pyaiText = pyaiText.replace(/,$/, '');
    pyaiText += ')\n';
}

addresses = {};

/* Creates a block and returns its address */
// Blocks are created inline and skipped over using a goto
// If true, isUnique causes the block to be added without a check to see if it already exists
function createBlock(block, isUnique) {
    if (isUnique || !addresses[block]) {
        var skipAddressLocation = aiscript.cursor + 1;
        exports.goto(0);
        addresses[block] = aiscript.cursor + 4;
        block();
        aiscript.buf.writeUInt16LE(aiscript.cursor + 4, skipAddressLocation)
    }

    return addresses[block];
}

function generateCommandFunction(command, validParams) {
    return function () {
        var params = checkParams(validParams, arguments);

        if (params) {
            // Translate functions to addresses and insert contents
            validParams.forEach(function (type, i) {
                if (type == 'address' && typeof(params[i]) == 'function') {
                    params[i] = createBlock(params[i]);
                }
            });

            appendCommand(command);
            validParams.forEach(function addParam(type, i) {
                // Evaluate functions to get a simple value
                if (type != 'address' && typeof(params[i]) == 'function') {
                    params[i] = params[i]();
                }

                appendArg(params[i], type);
            });
            closeCommand();
        }
    }
}

/* Macros */

exports.build_start = function(quantity, building, priority) {
    exports.build(quantity, building, priority);
    exports.wait_buildstart(quantity, building);
}

exports.build_finish = function(quantity, building, priority) {
    exports.build_start(quantity, building, priority);
    exports.wait_build(quantity, building);
}

exports.loop = function(block) {
    var inner = function () {
        block();
        exports.wait(10);
        exports.goto(inner);
    };

    exports.goto(inner);
}

exports.pick = function(blocks) {
    if (typeof blocks.length == 'undefined') {
        var blocks_obj = blocks;
        blocks = [];
        Object.keys(blocks_obj).forEach(function (key) {
            blocks.push(blocks_obj[key]);
        });
    }

    var startAddress = aiscript.cursor;
    var startJumpLocations = [];
    var finishJumpLocations = [];

    exports.loop(function() {
        blocks.forEach(function(block) {
            var newBlock = function() {
                if (block.options && block.options.versus) {
                    var raceAddr = [
                        block.options.versus.terran ? aiscript.cursor + 4 + 7 : 0xffff,
                        block.options.versus.zerg ? aiscript.cursor + 4 + 7 : 0xffff,
                        block.options.versus.protoss ? aiscript.cursor + 4 + 7 : 0xffff,
                    ];

                    raceAddr.forEach(function (addr, index) {
                        if (addr == 0xffff) {
                            startJumpLocations.push(aiscript.cursor + 1 + ( 2 * index ));
                        }
                    });

                    exports.race_jump(raceAddr[0], raceAddr[1], raceAddr[2]);
                }

                block();
                finishJumpLocations.push(aiscript.cursor + 1);
                exports.goto(0xffff);
            };

            exports.random_jump(5, createBlock(newBlock, true));
        });
    });

    startJumpLocations.forEach(function(address) {
        aiscript.buf.writeUInt16LE(startAddress, address)
    });

    finishJumpLocations.forEach(function(address) {
        aiscript.buf.writeUInt16LE(aiscript.cursor + 4, address)
    });
}

/*
 * Due to a bug in SC, only one return address can be stored at once,
 * meaning that call + multiple threads is completely broken. Call is
 * overloaded here to just inline the function content.
 */
exports.call = function(block) {
    block();
}

/* Helpers */

exports.simple_header = function(race) {
    exports.race = race;

    switch (race) {
        case 'terran':
            append('TMCx(1342, 101, aiscript):\n');
            exports.peon = 'Terran SCV';
            exports.town_hall = 'Terran Command Center';
            exports.gas = 'Terran Refinery';
            break;
    }
}

exports.header = function(race) {
    exports.simple_header(race);

    exports.start_town();
    exports.transports_off();
    exports.farms_notiming();
    exports.defaultbuild_off();
    exports.default_min(7);

    exports.build_start(1, exports.town_hall);
    exports.build_start(4, exports.peon);
}

exports.flush = function (filename) {
    exports.stop();
    fs.writeFileSync(filename, pyaiText);

    var len = new Buffer(4);
    len.writeUInt32LE(aiscript.length + 4, 0);
    fs.appendFileSync(binaryFilename, len);

    var buf = aiscript.buf.slice(0, aiscript.length);
    fs.appendFileSync(binaryFilename, buf);

    switch (exports.race) {
        case 'terran':
            fs.appendFileSync(binaryFilename, 'TMCx\x04\x00\x00\x00\x3f\x05\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00');
    }

    reset();
};<commit_msg>fixed problem with looping<commit_after>var fs = require('fs');
var commands = require('./commands');
var units = require('./units');
var upgrades = require('./upgrades');
var research = require('./research');
var abbrevs = require('./abbrevs.json');

var pyaiText;
var aiscript;
var currentRace;

var binaryFilename = 'build/aiscript.bin';

fs.writeFileSync(binaryFilename, '');

function reset() {
    pyaiText = '';
    aiscript = {
        buf: new Buffer(32000),
        length: 0,
        cursor: 0,
        getAddress: function () {
            return this.cursor + 4;
        }
    };
    currentRace = '';
}
reset();

// Add ai commands
Object.keys(commands).forEach(function (command, i) {
    exports[command] = generateCommandFunction(command, commands[command].params);
});

// Add abbreviations
Object.keys(abbrevs).forEach(function (abbrev, i) {
    function clean(str) {
        str = str.toLowerCase();
        str = str.replace(/ /g, '_');
        return str;
    }

    exports[clean(abbrev)] = abbrev;
    abbrevs[abbrev].forEach(function(shortcut) {
        exports[clean(shortcut)] = abbrev;
    });
});

function checkParams(validParams, params) {
    var ret = [];

    validParams.forEach(function (validParam, i) {
        if(validParam === 'priority' && params[i] === undefined) {
            params[i] = 80;
        }

        ret.push(params[i]);
    });

    return ret;
}

function append(str) {
    pyaiText += str;
}

function binWrite(b) {
    aiscript.buf[aiscript.cursor] = b;
    aiscript.cursor += 1;
    aiscript.length += 1;
}

function binWriteWord(w) {
    aiscript.buf.writeUInt16LE(w, aiscript.cursor)
    aiscript.cursor += 2;
    aiscript.length += 2;
}

function appendCommand(command) {
    pyaiText += command + '(';
    binWrite(commands[command].op);
}

function appendArg(val, type) {
    pyaiText += val + ',';

    switch (type) {
        case 'byte':
        case 'priority':
            binWrite(val);
            break;
        case 'address':
        case 'word':
            binWriteWord(val);
            break;
        case 'building':
        case 'unit':
        case 'military':
            binWriteWord(units[val].id);
            break;
        default:
            console.error('Type not recognized: ' + type);
    }
}

function closeCommand() {
    pyaiText = pyaiText.replace(/,$/, '');
    pyaiText += ')\n';
}

addresses = {};

/* Creates a block and returns its address */
// Blocks are created inline and skipped over using a goto
// If true, isUnique causes the block to be added without a check to see if it already exists
function createBlock(block, isUnique) {
    if (isUnique || !addresses[block]) {
        var skipAddressLocation = aiscript.cursor + 1;
        exports.goto(0);
        addresses[block] = aiscript.cursor + 4;
        block();
        aiscript.buf.writeUInt16LE(aiscript.cursor + 4, skipAddressLocation)
    }

    return addresses[block];
}

function generateCommandFunction(command, validParams) {
    return function () {
        var params = checkParams(validParams, arguments);

        if (params) {
            // Translate functions to addresses and insert contents
            validParams.forEach(function (type, i) {
                if (type == 'address' && typeof(params[i]) == 'function') {
                    params[i] = createBlock(params[i]);
                }
            });

            appendCommand(command);
            validParams.forEach(function addParam(type, i) {
                // Evaluate functions to get a simple value
                if (type != 'address' && typeof(params[i]) == 'function') {
                    params[i] = params[i]();
                }

                appendArg(params[i], type);
            });
            closeCommand();
        }
    }
}

/* Macros */

exports.build_start = function(quantity, building, priority) {
    exports.build(quantity, building, priority);
    exports.wait_buildstart(quantity, building);
}

exports.build_finish = function(quantity, building, priority) {
    exports.build_start(quantity, building, priority);
    exports.wait_build(quantity, building);
}

exports.loop = function(block) {
    var startAddr;
    var gotoAddr;

    var inner = function () {
        block();
        exports.wait(10);
        gotoAddr = aiscript.cursor + 1;
        exports.goto(0xffff);
    };

    startAddr = createBlock(inner, true);
    aiscript.buf.writeUInt16LE(startAddr, gotoAddr)
    exports.goto(startAddr);
}

exports.pick = function(blocks) {
    if (typeof blocks.length == 'undefined') {
        var blocks_obj = blocks;
        blocks = [];
        Object.keys(blocks_obj).forEach(function (key) {
            blocks.push(blocks_obj[key]);
        });
    }

    var startAddress = aiscript.cursor;
    var startJumpLocations = [];
    var finishJumpLocations = [];

    exports.loop(function() {
        blocks.forEach(function(block) {
            var newBlock = function() {
                if (block.options && block.options.versus) {
                    var raceAddr = [
                        block.options.versus.terran ? aiscript.cursor + 4 + 7 : 0xffff,
                        block.options.versus.zerg ? aiscript.cursor + 4 + 7 : 0xffff,
                        block.options.versus.protoss ? aiscript.cursor + 4 + 7 : 0xffff,
                    ];

                    raceAddr.forEach(function (addr, index) {
                        if (addr == 0xffff) {
                            startJumpLocations.push(aiscript.cursor + 1 + ( 2 * index ));
                        }
                    });

                    exports.race_jump(raceAddr[0], raceAddr[1], raceAddr[2]);
                }

                block();
                finishJumpLocations.push(aiscript.cursor + 1);
                exports.goto(0xffff);
            };

            exports.random_jump(5, createBlock(newBlock, true));
        });
    });

    startJumpLocations.forEach(function(address) {
        aiscript.buf.writeUInt16LE(startAddress, address)
    });

    finishJumpLocations.forEach(function(address) {
        aiscript.buf.writeUInt16LE(aiscript.cursor + 4, address)
    });
}

/*
 * Due to a bug in SC, only one return address can be stored at once,
 * meaning that call + multiple threads is completely broken. Call is
 * overloaded here to just inline the function content.
 */
exports.call = function(block) {
    block();
}

/* Helpers */

exports.simple_header = function(race) {
    exports.race = race;

    switch (race) {
        case 'terran':
            append('TMCx(1342, 101, aiscript):\n');
            exports.peon = 'Terran SCV';
            exports.town_hall = 'Terran Command Center';
            exports.gas = 'Terran Refinery';
            break;
    }
}

exports.header = function(race) {
    exports.simple_header(race);

    exports.start_town();
    exports.transports_off();
    exports.farms_notiming();
    exports.defaultbuild_off();
    exports.default_min(7);

    exports.build_start(1, exports.town_hall);
    exports.build_start(4, exports.peon);
}

exports.flush = function (filename) {
    exports.stop();
    fs.writeFileSync(filename, pyaiText);

    var len = new Buffer(4);
    len.writeUInt32LE(aiscript.length + 4, 0);
    fs.appendFileSync(binaryFilename, len);

    var buf = aiscript.buf.slice(0, aiscript.length);
    fs.appendFileSync(binaryFilename, buf);

    switch (exports.race) {
        case 'terran':
            fs.appendFileSync(binaryFilename, 'TMCx\x04\x00\x00\x00\x3f\x05\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00');
    }

    reset();
};<|endoftext|>