<commit_before>'use strict';

var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');
var queryString = require('querystring');
var request = require('request');

function auth() {
  var router = express.Router();

  router.all('/init', function(req, res) {
        var params = req.body; // params.userId params.password
        if (params && params.idToken) {
          console.log('Checking credentials for user ' + params.idToken);
          initSession(idToken, function(err, result){
            if (err) {
              console.log('Invalid credentials for user ' + params.idToken);
              res.status(400);
              res.json({message: 'Invalid credentials'});
              return;
            } else {
              res.json({
                status: 'ok',
                userId: params.idToken,
                sessionToken: params.idToken + '_sessiontoken',
                authResponse: result
              });
              return;
            }
          });

        } else {
          res.status(400);
          res.json({message: 'No Token Provided'});
        }

  });

  /**
   * Validate the user's session info with Google, and create a session object.
   * This will also create a account object if necessary.
   *
   * @param {String} idToken an idToken provided by an Android Client (see : https://developers.google.com/identity/sign-in/android/backend-auth)
   * @param {Callback} nodeCallback a node callback
   */
  function initSession(idToken, nodeCallback) {
      //validate with google
      var options = {

          url: 'https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=' + querystring.escape(idToken),
          method: 'GET'
      };

      request(options, handleGoogleResponse(idToken, nodeCallback)).end();

  }

  /**
   *
   * This callback consumes Google's response, and performs the appropriate
   * actions on the session. (Set session optionally creating the account).
   *
   * @param {type} idToken
   * @param {type} nodeCallback
   * @returns session Data on callback if successful, error on callback otherwise
   */
  function handleGoogleResponse(sessionToken, authResponse, nodeCallback) {
      return function (error, response, body) {

          //the whole response has been recieved, so we just print it out here
          if (error) {
            nodeCallback(e);
          } else {
            var resObject = JSON.parse(body);
            checkAccount(resObject, sessionToken, nodeCallback);
          }

      };
  }

  /**
   * Creates a user if one does not exist
   *
   * @param {Sting}  Google user Token response (see : https://developers.google.com/identity/sign-in/android/backend-auth#calling-the-tokeninfo-endpoint)
   * @param {Sting} sessionToken
   * @param {NodeCallback} nodeCallback
   * @returns session Data on callback if successful, error on callback otherwise
   */
  function checkAccount(googleUserToken, sessionToken, nodeCallback) {
      console.log('checkAccountAndCreateSession');
      var handleResults = function (error, responseData) {
        console.log('checkAccountAndCreateSession_callback');
          if (error) {
              return nodeCallback(error, null);
          } else {
              if (!responseData || responseData.count === 0) {
                  //no account, must create.
                  createAccount(googleUserToken, nodeCallback);
              } else if (responseData.count > 1) {
                  return nodeCallback("error : Too many accounts returned", null);
              } else {
                  //account exists, set session and return it.
                  setSession(sessionToken, responseData.list[0].fields, nodeCallback);
              }
          }
      };

      mbaasApi.db({
          "act": "list",
          "type": 'account',
          "eq": {"id": googleUserToken.sub},
      }, handleResults);
  }

  /**
   *  Creates an account and sets the session to that account.
   * @param {Sting} sessionToken
   * @param {Object} authResponse
   * @param {NodeCallback} nodeCallback
   * @returns session Data on callback if successful, error on callback otherwise
   */
  function createAccountAndSetSession(sessionToken, authResponse, nodeCallback) {
    authResponse.authToken = '';
      mbaasApi.db({
          "act": "create",
          "type": 'account',
          "fields": [authResponse]
      }, function (error, data) {
        console.log('createAccountAndSetSession_cb');
          if (error) {
              return nodeCallback(error);
          } else {
              setSession(sessionToken, authResponse, nodeCallback);

          }
      });
  }

  return router;

}

module.exports = auth;
<commit_msg>update file /lib/auth.js<commit_after>'use strict';

var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');
var queryString = require('querystring');
var request = require('request');

function auth() {
  var router = express.Router();

  router.all('/init', function(req, res) {
        var params = req.body; // params.userId params.password
        if (params && params.idToken) {
          console.log('Checking credentials for user ' + params.idToken);
          initSession(idToken, function(err, result){
            if (err) {
              console.log('Invalid credentials for user ' + params.idToken);
              res.status(400);
              res.json({message: 'Invalid credentials'});
              return;
            } else {
              res.json({
                status: 'ok',
                userId: params.idToken,
                sessionToken: params.idToken + '_sessiontoken',
                authResponse: result
              });
              return;
            }
          });

        } else {
          res.status(400);
          res.json({message: 'No Token Provided'});
        }

  });

  /**
   * Validate the user's session info with Google, and create a session object.
   * This will also create a account object if necessary.
   *
   * @param {String} idToken an idToken provided by an Android Client (see : https://developers.google.com/identity/sign-in/android/backend-auth)
   * @param {Callback} nodeCallback a node callback
   */
  function initSession(idToken, nodeCallback) {
      //validate with google
      var options = {

          url: 'https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=' + querystring.escape(idToken),
          method: 'GET'
      };

      request(options, handleGoogleResponse(idToken, nodeCallback)).end();

  }

  /**
   *
   * This callback consumes Google's response, and performs the appropriate
   * actions on the session. (Set session optionally creating the account).
   *
   * @param {type} idToken
   * @param {type} nodeCallback
   * @returns session Data on callback if successful, error on callback otherwise
   */
  function handleGoogleResponse(sessionToken, authResponse, nodeCallback) {
      return function (error, response, body) {

          //the whole response has been recieved, so we just print it out here
          if (error) {
            nodeCallback(e);
          } else {
            var resObject = JSON.parse(body);
            checkAccount(resObject, sessionToken, nodeCallback);
          }

      };
  }

  /**
   * Creates a user if one does not exist
   *
   * @param {Sting}  Google user Token response (see : https://developers.google.com/identity/sign-in/android/backend-auth#calling-the-tokeninfo-endpoint)
   * @param {Sting} sessionToken
   * @param {NodeCallback} nodeCallback
   * @returns session Data on callback if successful, error on callback otherwise
   */
  function checkAccount(googleUserToken, sessionToken, nodeCallback) {
      console.log('checkAccountAndCreateSession');
      var handleResults = function (error, responseData) {
        console.log('checkAccountAndCreateSession_callback');
          if (error) {
              return nodeCallback(error, null);
          } else {
              if (!responseData || responseData.count === 0) {
                  //no account, must create.
                  createAccount(googleUserToken, nodeCallback);
              } else if (responseData.count > 1) {
                  return nodeCallback("error : Too many accounts returned", null);
              } else {
                  //account exists, set session and return it.
                  setSession(sessionToken, responseData.list[0].fields, nodeCallback);
              }
          }
      };

      mbaasApi.db({
          "act": "list",
          "type": 'account',
          "eq": {"id": googleUserToken.sub},
      }, handleResults);
  }

  /**
   *  Creates an account and sets the session to that account.
   * @param {Object}  Google user Token response (see : https://developers.google.com/identity/sign-in/android/backend-auth#calling-the-tokeninfo-endpoint)
   * @param {NodeCallback} nodeCallback
   * @returns session Data on callback if successful, error on callback otherwise
   */
  function createAccountAndSetSession(sessionToken, authResponse, nodeCallback) {
    authResponse.authToken = '';
      mbaasApi.db({
          "act": "create",
          "type": 'account',
          "fields": [authResponse]
      }, function (error, data) {
        console.log('createAccountAndSetSession_cb');
          if (error) {
              return nodeCallback(error);
          } else {
              setSession(sessionToken, authResponse, nodeCallback);

          }
      });
  }

  return router;

}

module.exports = auth;
<|endoftext|>


<commit_before>export { BoundsArraySet };

import * as ConvBiasActivation from "../ConvBiasActivation.js";
import * as FloatValue from "../../Unpacker/FloatValue.js";
import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as Weights from "../../Unpacker/Weights.js";
import { ChannelPartInfo, FiltersBiasesPartInfo } from  "./Pointwise_ChannelPartInfo.js";

/**
 * The element value bounds for pointwise convolution-bias-activation.
 *
 */
class BoundsArraySet extends ConvBiasActivation.BoundsArraySet {

  /**
   */
  constructor( inputChannelCount, outputChannelCount ) {
    super( inputChannelCount, outputChannelCount );
  }

  /**
   * Set this.bPassThrough[] according to inChannelPartInfoArray.
   *
   * @param {Pointwise.FiltersBiasesPartInfo[]} aFiltersBiasesPartInfoArray
   *   The input channel range array which describe lower/higher half channels index range.
   */
  set_bPassThrough_all_byChannelPartInfoArray( aFiltersBiasesPartInfoArray ) {

    let outChannel = 0;

//!!! ...unfinished... (2022/02/24) aFiltersBiasesPartInfoArray

    InChannelPartIndexLoop:
    for ( let inChannelPartIndex = 0; inChannelPartIndex < inChannelPartInfoArray.length; ++inChannelPartIndex ) {
      let inChannelPartInfo = inChannelPartInfoArray[ inChannelPartIndex ];

      for ( let outChannelSub = 0; outChannelSub < inChannelPartInfo.outputChannelCount; ++outChannelSub, ++outChannel ) {
        if ( outChannel >= this.outputChannelCount )
          break InChannelPartIndexLoop; // Never exceeds the total output channel count.

        if ( inChannelPartInfo.bPassThrough ) { // For pass-through half channels.
          this.bPassThrough[ outChannel ] = true;

        } else { // Non-pass-through half channels. (i.e. input multiply filter weight.)
          this.bPassThrough[ outChannel ] = false;
        }

      } // outChannelSub, outChannel
    } // inChannelPartIndex

  }

//!!! ...unfinished... (2022/01/09)
// Even if ( this.outputChannelCount <= 0 ),
// this function should work correctly and BoundsArraySet should result in pass-through input to output.

}

<commit_msg>Update Pointwise_BoundsArraySet.js<commit_after>export { BoundsArraySet };

import * as ConvBiasActivation from "../ConvBiasActivation.js";
import * as FloatValue from "../../Unpacker/FloatValue.js";
import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as Weights from "../../Unpacker/Weights.js";
import { ChannelPartInfo, FiltersBiasesPartInfo } from  "./Pointwise_ChannelPartInfo.js";

/**
 * The element value bounds for pointwise convolution-bias-activation.
 *
 */
class BoundsArraySet extends ConvBiasActivation.BoundsArraySet {

  /**
   */
  constructor( inputChannelCount, outputChannelCount ) {
    super( inputChannelCount, outputChannelCount );
  }

  /**
   * Set this.bPassThrough[] according to inChannelPartInfoArray.
   *
   * @param {Pointwise.FiltersBiasesPartInfo[]} aFiltersBiasesPartInfoArray
   *   The input channel range array which describe lower/higher half channels index range.
   */
  set_bPassThrough_all_byChannelPartInfoArray( aFiltersBiasesPartInfoArray ) {
    let inChannel = 0;

    FiltersBiasesPartIndexLoop:
    for ( let aFiltersBiasesPartIndex = 0; aFiltersBiasesPartIndex < aFiltersBiasesPartInfoArray.length; ++aFiltersBiasesPartIndex ) {
      let aFiltersBiasesPartInfo = aFiltersBiasesPartInfoArray[ aFiltersBiasesPartIndex ];
      let inChannelPartInfoArray = aFiltersBiasesPartInfo.aChannelPartInfoArray;

      for ( let inChannelSub = 0; inChannelSub < aFiltersBiasesPartInfo.inputChannelCount; ++inChannelSub, ++inChannel ) {
        if ( inChannel >= this.inputChannelCount )
          break FiltersBiasesPartIndexLoop; // Never exceeds the total input channel count.

//!!! ...unfinished... (2022/02/24) aFiltersBiasesPartInfoArray

      let outChannel = 0;

      InChannelPartIndexLoop:
      for ( let inChannelPartIndex = 0; inChannelPartIndex < inChannelPartInfoArray.length; ++inChannelPartIndex ) {
        let inChannelPartInfo = inChannelPartInfoArray[ inChannelPartIndex ];

        for ( let outChannelSub = 0; outChannelSub < inChannelPartInfo.outputChannelCount; ++outChannelSub, ++outChannel ) {
          if ( outChannel >= this.outputChannelCount )
            break InChannelPartIndexLoop; // Never exceeds the total output channel count.

          if ( inChannelPartInfo.bPassThrough ) { // For pass-through half channels.
            this.bPassThrough[ outChannel ] = true;

          } else { // Non-pass-through half channels. (i.e. input multiply filter weight.)
            this.bPassThrough[ outChannel ] = false;
          }

        } // outChannelSub, outChannel
      } // inChannelPartIndex
    } // aFiltersBiasesPartIndex
  }

//!!! ...unfinished... (2022/01/09)
// Even if ( this.outputChannelCount <= 0 ),
// this function should work correctly and BoundsArraySet should result in pass-through input to output.

}

<|endoftext|>


<commit_before>"use strict";

// Options
var kShowTimerBarsAtSeconds = 30;
var kKeepExpiredTimerBarsForSeconds = 0.7;
var kBarExpiresSoonSeconds = 8;
var kMaxNumberOfTimerBars = 4;
var kBarWidth = 220;
var kBarHeight = 20;
var kBarFontSize = 14;
var kBarColor = '#88f';
var kBarExpiresSoonColor = '#f88';

class Timeline {
  constructor(zoneRegex, text) {
    /*
    // This needs CefBrowserSettings.web_security_disabled = true.
    var file = new XMLHttpRequest();
    file.open("GET", filename, false);
    file.onreadystatechange = function() {
      console.log("readyState " + file.readyState + " status " + file.status);
      if(file.readyState === 4) {
        if(file.status === 200 || file.status == 0) {
          var text = file.responseText;
          LoadFile(text);
        }
      }
    }
    file.send(null);
    */
    // A regex for what zone(s) to use the timeline for. Can be overridden
    // inside the text data.
    this.zoneRegex = zoneRegex;
    // A set of names which will not be notified about.
    this.ignores = {};
    // Sorted by event occurance time.
    this.events = [];
    // Sorted by sync.start time.
    this.syncStarts = [];
    // Sorted by sync.end time.
    this.syncEnds = [];
    // Not sorted.
    this.activeSyncs = [];
    // Sorted by event occurance time.
    this.activeEvents = [];
    this.LoadFile(text);
    this.Stop();
  }

  LoadFile(text) {
    this.events = [];
    this.syncStarts = [];
    this.syncEnds = [];

    var uniqueid = 1;

    var lines = text.split('\n');
    for (var i = 0; i < lines.length; ++i) {
      var line = lines[i];
      // Drop comments.
      var comment = line.indexOf('#');
      if (comment >= 0)
        line = line.substring(0, comment);
      line = line.trim();

      var match = line.match(/^zone \"([^"]+)\"$/);
      if (match != null) {
        this.zoneRegex = match[1];
        continue;
      }

      match = line.match(/^hideall \"([^"]+)\"$/);
      if (match != null) {
        this.ignores[match[1]] = true;
        continue;
      }

      match = line.match(/^([0-9]+)\s+"(.*?)"(\s+(.*))?/);
      if (match == null) continue;

      var seconds = parseFloat(match[1]);
      var o = {
        id: uniqueid++,
        time: seconds,
        sortTime: seconds,
        name: match[2],
        activeTime: 0,
      };
      var commands = match[3];
      if (commands) {
        var commandMatch = commands.match(/duration ([0-9]+)(\s.*)?$/);
        if (commandMatch)
          o.duration = parseFloat(commandMatch[1]);
        commandMatch = commands.match(/sync \/(.*)\/(\s.*)?$/);
        if (commandMatch) {
          var sync = {
            id: uniqueid,
            regex: new RegExp(commandMatch[1]),
            start: seconds - 2.5,
            end: seconds + 2.5,
            time: seconds,
          }
          if (commandMatch[2]) {
            var argMatch = commandMatch[2].match(/window (([0-9]+),)?([0-9]+)(\s.*)?$/);
            if (argMatch) {
              if (argMatch[2]) {
                sync.start = seconds - parseFloat(argMatch[2]);
              }
              sync.end = seconds + parseFloat(argMatch[3]);
            }
            argMatch = commandMatch[2].match(/jump ([0-9]+)(\s.*)?$/);
            if (argMatch)
              sync.jump = parseFloat(argMatch[1]);
          }
          this.syncStarts.push(sync);
          this.syncEnds.push(sync);
        }
      }
      this.events.push(o);
    }

    this.events.sort(function(a, b) { return a.time - b.time });
    this.syncStarts.sort(function(a, b) { return a.start - b.start });
    this.syncEnds.sort(function(a, b) { return a.end - b.end });
  }

  Stop() {
    this.timebase = null;

    this.nextEvent = 0;
    this.nextSyncStart = 0;
    this.nextSyncEnd = 0;

    var fightNow = 0;
    this._AdvanceTimeTo(fightNow);
    this._CollectActiveSyncs(fightNow);

    this._ClearTimers();
    this._CancelUpdate();
  }

  SyncTo(fightNow) {
   // This records the actual time which aligns with "0" in the timeline.
    this.timebase = new Date(new Date() - fightNow * 1000);

    this.nextEvent = 0;
    this.nextSyncStart = 0;
    this.nextSyncEnd = 0;

    this._AdvanceTimeTo(fightNow);
    this._CollectActiveSyncs(fightNow);

    this._ClearTimers();
    this._AddUpcomingTimers(fightNow);
    this._ScheduleUpdate(fightNow);
  }

  _CollectActiveSyncs(fightNow) {
    this.activeSyncs = [];
    for (var i = this.nextSyncEnd; i < this.syncEnds.length; ++i) {
      if (this.syncEnds[i].start < fightNow)
        this.activeSyncs.push(this.syncEnds[i]);
    }
  }

  OnLogLine(line) {
    for (var i = 0; i < this.activeSyncs.length; ++i) {
      var sync = this.activeSyncs[i];
      if (line.search(sync.regex) >= 0) {
        if ('jump' in sync) {
          if (!sync.jump)
            this.Stop();
          else
            this.SyncTo(sync.jump);
        } else {
          this.SyncTo(sync.time);
        }
        break;
      }
    }
  }

  _AdvanceTimeTo(fightNow) {
    while (this.nextEvent < this.events.length && this.events[this.nextEvent].time <= fightNow)
      ++this.nextEvent;
    while (this.nextSyncStart < this.syncStarts.length && this.syncStarts[this.nextSyncStart].start <= fightNow)
      ++this.nextSyncStart;
    while (this.nextSyncEnd < this.syncEnds.length && this.syncEnds[this.nextSyncEnd].end <= fightNow)
      ++this.nextSyncEnd;
  }

  _ClearTimers() {
    if (this.removeTimerCallback) {
      for (var i = 0; i < this.activeEvents.length; ++i)
        this.removeTimerCallback(this.activeEvents[i], false);
    }
    this.activeEvents = [];
  }

  _RemoveExpiredTimers(fightNow) {
    while (this.activeEvents.length && this.activeEvents[0].time <= fightNow) {
      if (this.removeTimerCallback)
        this.removeTimerCallback(this.activeEvents[0], true);
      this.activeEvents.splice(0, 1);
    }
  }

  _AddDurationTimers(fightNow) {
    var sort = false;
    var events = [];
    for (var i = 0; i < this.activeEvents.length; ++i) {
      var e = this.activeEvents[i];
      if (e.time <= fightNow && e.duration) {
        var durationEvent = {
          id: e.id,
          time: e.time + e.duration,
          sortTime: e.time,
          name: 'Active: ' + e.name,
        };
        events.push(durationEvent);
        this.activeEvents.splice(i, 1);
        if (this.addTimerCallback)
          this.addTimerCallback(fightNow, durationEvent, true);
        sort = true;
        --i;
      }
    }
    if (events.length)
      Array.prototype.push.apply(this.activeEvents, events);
      this.activeEvents.sort(function(a, b) { return a.time - b.time });
  }

  _AddUpcomingTimers(fightNow) {
    while (this.nextEvent < this.events.length && this.activeEvents.length < kMaxNumberOfTimerBars) {
      var e = this.events[this.nextEvent];
      if (e.time - fightNow > kShowTimerBarsAtSeconds)
        break;
      if (fightNow < e.time && !(e.name in this.ignores)) {
        this.activeEvents.push(e);
        if (this.addTimerCallback)
          this.addTimerCallback(fightNow, e, false);
      }
      ++this.nextEvent;
    }
  }

  _CancelUpdate() {
    if (this.updateTimer) {
      window.clearTimeout(this.updateTimer);
      this.updateTimer = null;
    }
  }

  _ScheduleUpdate(fightNow) {
    console.assert(this.timebase, "_ScheduleUpdate called while stopped");

    var kBig = 1000000000; // Something bigger than any fight length in seconds.
    var nextEventStarting = kBig;
    var nextEventEnding = kBig;
    var nextSyncStarting = kBig;
    var nextSyncEnding = kBig;

    if (this.nextEvent < this.events.length) {
      var nextEventEndsAt = this.events[this.nextEvent].time
      console.assert(nextEventStarting > fightNow, "nextEvent wasn't updated before calling _ScheduleUpdate")
      // There might be more events than we can show, so the next event might be in
      // the past. If that happens, then ignore it, as we can't use that for our timer.
      var showNextEventAt = nextEventEndsAt - kShowTimerBarsAtSeconds;
      if (showNextEventAt > fightNow)
        nextEventStarting = showNextEventAt;
    }
    if (this.activeEvents.length > 0) {
      nextEventEnding = this.activeEvents[0].time;
      console.assert(nextEventEnding > fightNow, "Expired activeEvents weren't pruned before calling _ScheduleUpdate")
    }
    if (this.nextSyncStart < this.syncStarts.length) {
      nextSyncStarting = this.syncStarts[this.nextSyncStart].start;
      console.assert(nextSyncStarting > fightNow, "nextSyncStart wasn't updated before calling _ScheduleUpdate")
    }
    if (this.nextSyncEnd < this.syncEnds.length) {
      nextSyncEnding = this.syncEnds[this.nextSyncEnd].end;
      console.assert(nextSyncEnding > fightNow, "nextSyncEnd wasn't updated before calling _ScheduleUpdate")
    }

    var nextTime = Math.min(nextEventStarting, Math.min(nextEventEnding, Math.min(nextSyncStarting, nextSyncEnding)));
    if (nextTime != kBig) {
      console.assert(nextTime > fightNow, "nextTime is in the past")
      this.updateTimer = window.setTimeout(this._OnUpdateTimer.bind(this), (nextTime - fightNow) * 1000);
    }
  }

  _OnUpdateTimer() {
    console.assert(this.timebase, "_OnTimerUpdate called while stopped");

    // This is the number of seconds into the fight (subtracting Dates gives milliseconds).
    var fightNow = (new Date() - this.timebase) / 1000;
    this._AdvanceTimeTo(fightNow);
    this._CollectActiveSyncs(fightNow);

    this._AddDurationTimers(fightNow);
    this._RemoveExpiredTimers(fightNow);
    this._AddUpcomingTimers(fightNow);
    this._ScheduleUpdate(fightNow);
  }

  SetAddTimer(c) { this.addTimerCallback = c; }
  SetRemoveTimer(c) { this.removeTimerCallback = c; }
};

class TimelineUI {
  constructor() {
    this.init = false;
  }

  Init() {
    if (this.init) return;
    this.init = true;

    this.root = document.getElementById('timeline-container');
    this.timerlist = document.getElementById('timeline');
    this.timerlist.maxnumber = kMaxNumberOfTimerBars;
    this.timerlist.rowcolsize = kMaxNumberOfTimerBars;
    this.timerlist.elementwidth = kBarWidth;
    this.timerlist.elementheight = kBarHeight + 2;
    this.timerlist.toward = "down right";
    this.activeBars = {};
  }

  SetTimeline(timeline) {
    this.Init();
    if (this.timeline) {
      this.timeline.SetAddTimer(null);
      this.timeline.SetRemoveTimer(null);
      this.timerlist.clear();
      this.activeBars = {};
    }

    this.timeline = timeline;
    if (this.timeline) {
      this.timeline.SetAddTimer(this.OnAddTimer.bind(this));
      this.timeline.SetRemoveTimer(this.OnRemoveTimer.bind(this));
    }
  }

  OnAddTimer(fightNow, e, channeling) {
    var div = document.createElement('div');
    var bar = document.createElement('timer-bar');
    div.appendChild(bar);
    div.style.fontSize = kBarFontSize;
    bar.width = kBarWidth;
    bar.height = kBarHeight;
    bar.duration = e.time - fightNow;
    bar.righttext = 'remain';
    bar.lefttext = e.name;
    bar.toward = 'right';
    bar.style = !channeling ? 'fill' : 'empty';

    if (!channeling && e.time - fightNow > kBarExpiresSoonSeconds) {
      bar.fg = kBarColor;
      window.setTimeout(this.OnTimerExpiresSoon.bind(this, e.id), (e.time - fightNow - kBarExpiresSoonSeconds) * 1000);
    } else {
      bar.fg = kBarExpiresSoonColor;
    }

    this.timerlist.addElement(e.id, div, e.sortTime);
    this.activeBars[e.id] = bar;
  }

  OnTimerExpiresSoon(id) {
    if (id in this.activeBars)
      this.activeBars[id].fg = kBarExpiresSoonColor;
  }

  OnRemoveTimer(e, expired) {
    if (expired && kKeepExpiredTimerBarsForSeconds) {
      window.setTimeout(this.OnRemoveTimer.bind(this, e, false), kKeepExpiredTimerBarsForSeconds * 1000);
      return;
    }
    this.timerlist.removeElement(e.id);
    delete this.activeBars[e.id];
  }
};

class TimelineController {
  constructor(ui) {
    this.ui = ui;
    this.dataFiles = {};
  }

  OnInCombat(e) {
    if (!e.detail.inCombat && !this.inBossFight)
      this.OnBossFightStop();
  }

  OnBossFightStart() {
    this.inBossFight = true;
  }

  OnBossFightStop() {
    this.inBossFight = false;
    if (this.timeline)
      this.activeTimeline.Stop();
  }

  OnLogEvent(e) {
    if (!this.activeTimeline)
      return;
    for (var i = 0; i < e.detail.logs.length; ++i)
      this.activeTimeline.OnLogLine(e.detail.logs[i]);
  }

  OnZoneChanged(e) {
    this.activeTimeline = null;
    for (var i = 0; i < this.timelines.length; ++i) {
      if (e.detail.zoneName.search(this.timelines[i].zoneRegex) >= 0) {
        this.activeTimeline = this.timelines[i];
        break;
      }
    }
    this.ui.SetTimeline(this.activeTimeline);
  }

  SetDataFiles(files) {
    this.timelines = [];
    for (var f in files) {
      var nameWithoutExtension = f.split('.').slice(0, -1).join('.');
      this.timelines.push(new Timeline(nameWithoutExtension, files[f]));
    }
  }
}

var gTimelineController = new TimelineController(new TimelineUI());

document.addEventListener("onZoneChangedEvent", function(e) {
  gTimelineController.OnZoneChanged(e);
});
document.addEventListener("onInCombatChangedEvent", function (e) {
  gTimelineController.OnInCombat(e);
});
document.addEventListener("onBossFightStart", function(e) {
  gTimelineController.OnBossFightStart();
});
document.addEventListener("onBossFightEnd", function(e) {
  gTimelineController.OnBossFightStop();
});
document.addEventListener("onLogEvent", function(e) {
  gTimelineController.OnLogEvent(e);
});
document.addEventListener("onDataFilesRead", function(e) {
  gTimelineController.SetDataFiles(e.detail.files);
});<commit_msg>document the zone extension what what format the timeline class loads<commit_after>"use strict";

// Options
var kShowTimerBarsAtSeconds = 30;
var kKeepExpiredTimerBarsForSeconds = 0.7;
var kBarExpiresSoonSeconds = 8;
var kMaxNumberOfTimerBars = 4;
var kBarWidth = 220;
var kBarHeight = 20;
var kBarFontSize = 14;
var kBarColor = '#88f';
var kBarExpiresSoonColor = '#f88';

// This class reads the format of ACT Timeline plugin, described here:
// http://dtguilds.enjin.com/forum/m/37032836/viewthread/26353492-act-timeline-plugin
// There are a some extensions to the original format:
//
// # Allows you to specify a regular expression, which when matched the timeline file
// # will be used.  If more than one file has a matching regex for the current zone, an
// # arbitrary one will be used (don't do that). This is useful when the FFXIV plugin
// # does not know the name of the zone yet, but you want to specify the name for once
// # it becomes known. If this isn't specified, the name of the file (excluding the
// # extention) will be used as a regular expression instead.
// zone "zone-regex"
class Timeline {
  constructor(zoneRegex, text) {
    /*
    // This needs CefBrowserSettings.web_security_disabled = true.
    var file = new XMLHttpRequest();
    file.open("GET", filename, false);
    file.onreadystatechange = function() {
      console.log("readyState " + file.readyState + " status " + file.status);
      if(file.readyState === 4) {
        if(file.status === 200 || file.status == 0) {
          var text = file.responseText;
          LoadFile(text);
        }
      }
    }
    file.send(null);
    */
    // A regex for what zone(s) to use the timeline for. Can be overridden
    // inside the text data.
    this.zoneRegex = zoneRegex;
    // A set of names which will not be notified about.
    this.ignores = {};
    // Sorted by event occurance time.
    this.events = [];
    // Sorted by sync.start time.
    this.syncStarts = [];
    // Sorted by sync.end time.
    this.syncEnds = [];
    // Not sorted.
    this.activeSyncs = [];
    // Sorted by event occurance time.
    this.activeEvents = [];
    this.LoadFile(text);
    this.Stop();
  }

  LoadFile(text) {
    this.events = [];
    this.syncStarts = [];
    this.syncEnds = [];

    var uniqueid = 1;

    var lines = text.split('\n');
    for (var i = 0; i < lines.length; ++i) {
      var line = lines[i];
      // Drop comments.
      var comment = line.indexOf('#');
      if (comment >= 0)
        line = line.substring(0, comment);
      line = line.trim();

      var match = line.match(/^zone \"([^"]+)\"$/);
      if (match != null) {
        this.zoneRegex = match[1];
        continue;
      }

      match = line.match(/^hideall \"([^"]+)\"$/);
      if (match != null) {
        this.ignores[match[1]] = true;
        continue;
      }

      match = line.match(/^([0-9]+)\s+"(.*?)"(\s+(.*))?/);
      if (match == null) continue;

      var seconds = parseFloat(match[1]);
      var o = {
        id: uniqueid++,
        time: seconds,
        sortTime: seconds,
        name: match[2],
        activeTime: 0,
      };
      var commands = match[3];
      if (commands) {
        var commandMatch = commands.match(/duration ([0-9]+)(\s.*)?$/);
        if (commandMatch)
          o.duration = parseFloat(commandMatch[1]);
        commandMatch = commands.match(/sync \/(.*)\/(\s.*)?$/);
        if (commandMatch) {
          var sync = {
            id: uniqueid,
            regex: new RegExp(commandMatch[1]),
            start: seconds - 2.5,
            end: seconds + 2.5,
            time: seconds,
          }
          if (commandMatch[2]) {
            var argMatch = commandMatch[2].match(/window (([0-9]+),)?([0-9]+)(\s.*)?$/);
            if (argMatch) {
              if (argMatch[2]) {
                sync.start = seconds - parseFloat(argMatch[2]);
              }
              sync.end = seconds + parseFloat(argMatch[3]);
            }
            argMatch = commandMatch[2].match(/jump ([0-9]+)(\s.*)?$/);
            if (argMatch)
              sync.jump = parseFloat(argMatch[1]);
          }
          this.syncStarts.push(sync);
          this.syncEnds.push(sync);
        }
      }
      this.events.push(o);
    }

    this.events.sort(function(a, b) { return a.time - b.time });
    this.syncStarts.sort(function(a, b) { return a.start - b.start });
    this.syncEnds.sort(function(a, b) { return a.end - b.end });
  }

  Stop() {
    this.timebase = null;

    this.nextEvent = 0;
    this.nextSyncStart = 0;
    this.nextSyncEnd = 0;

    var fightNow = 0;
    this._AdvanceTimeTo(fightNow);
    this._CollectActiveSyncs(fightNow);

    this._ClearTimers();
    this._CancelUpdate();
  }

  SyncTo(fightNow) {
   // This records the actual time which aligns with "0" in the timeline.
    this.timebase = new Date(new Date() - fightNow * 1000);

    this.nextEvent = 0;
    this.nextSyncStart = 0;
    this.nextSyncEnd = 0;

    this._AdvanceTimeTo(fightNow);
    this._CollectActiveSyncs(fightNow);

    this._ClearTimers();
    this._AddUpcomingTimers(fightNow);
    this._ScheduleUpdate(fightNow);
  }

  _CollectActiveSyncs(fightNow) {
    this.activeSyncs = [];
    for (var i = this.nextSyncEnd; i < this.syncEnds.length; ++i) {
      if (this.syncEnds[i].start < fightNow)
        this.activeSyncs.push(this.syncEnds[i]);
    }
  }

  OnLogLine(line) {
    for (var i = 0; i < this.activeSyncs.length; ++i) {
      var sync = this.activeSyncs[i];
      if (line.search(sync.regex) >= 0) {
        if ('jump' in sync) {
          if (!sync.jump)
            this.Stop();
          else
            this.SyncTo(sync.jump);
        } else {
          this.SyncTo(sync.time);
        }
        break;
      }
    }
  }

  _AdvanceTimeTo(fightNow) {
    while (this.nextEvent < this.events.length && this.events[this.nextEvent].time <= fightNow)
      ++this.nextEvent;
    while (this.nextSyncStart < this.syncStarts.length && this.syncStarts[this.nextSyncStart].start <= fightNow)
      ++this.nextSyncStart;
    while (this.nextSyncEnd < this.syncEnds.length && this.syncEnds[this.nextSyncEnd].end <= fightNow)
      ++this.nextSyncEnd;
  }

  _ClearTimers() {
    if (this.removeTimerCallback) {
      for (var i = 0; i < this.activeEvents.length; ++i)
        this.removeTimerCallback(this.activeEvents[i], false);
    }
    this.activeEvents = [];
  }

  _RemoveExpiredTimers(fightNow) {
    while (this.activeEvents.length && this.activeEvents[0].time <= fightNow) {
      if (this.removeTimerCallback)
        this.removeTimerCallback(this.activeEvents[0], true);
      this.activeEvents.splice(0, 1);
    }
  }

  _AddDurationTimers(fightNow) {
    var sort = false;
    var events = [];
    for (var i = 0; i < this.activeEvents.length; ++i) {
      var e = this.activeEvents[i];
      if (e.time <= fightNow && e.duration) {
        var durationEvent = {
          id: e.id,
          time: e.time + e.duration,
          sortTime: e.time,
          name: 'Active: ' + e.name,
        };
        events.push(durationEvent);
        this.activeEvents.splice(i, 1);
        if (this.addTimerCallback)
          this.addTimerCallback(fightNow, durationEvent, true);
        sort = true;
        --i;
      }
    }
    if (events.length)
      Array.prototype.push.apply(this.activeEvents, events);
      this.activeEvents.sort(function(a, b) { return a.time - b.time });
  }

  _AddUpcomingTimers(fightNow) {
    while (this.nextEvent < this.events.length && this.activeEvents.length < kMaxNumberOfTimerBars) {
      var e = this.events[this.nextEvent];
      if (e.time - fightNow > kShowTimerBarsAtSeconds)
        break;
      if (fightNow < e.time && !(e.name in this.ignores)) {
        this.activeEvents.push(e);
        if (this.addTimerCallback)
          this.addTimerCallback(fightNow, e, false);
      }
      ++this.nextEvent;
    }
  }

  _CancelUpdate() {
    if (this.updateTimer) {
      window.clearTimeout(this.updateTimer);
      this.updateTimer = null;
    }
  }

  _ScheduleUpdate(fightNow) {
    console.assert(this.timebase, "_ScheduleUpdate called while stopped");

    var kBig = 1000000000; // Something bigger than any fight length in seconds.
    var nextEventStarting = kBig;
    var nextEventEnding = kBig;
    var nextSyncStarting = kBig;
    var nextSyncEnding = kBig;

    if (this.nextEvent < this.events.length) {
      var nextEventEndsAt = this.events[this.nextEvent].time
      console.assert(nextEventStarting > fightNow, "nextEvent wasn't updated before calling _ScheduleUpdate")
      // There might be more events than we can show, so the next event might be in
      // the past. If that happens, then ignore it, as we can't use that for our timer.
      var showNextEventAt = nextEventEndsAt - kShowTimerBarsAtSeconds;
      if (showNextEventAt > fightNow)
        nextEventStarting = showNextEventAt;
    }
    if (this.activeEvents.length > 0) {
      nextEventEnding = this.activeEvents[0].time;
      console.assert(nextEventEnding > fightNow, "Expired activeEvents weren't pruned before calling _ScheduleUpdate")
    }
    if (this.nextSyncStart < this.syncStarts.length) {
      nextSyncStarting = this.syncStarts[this.nextSyncStart].start;
      console.assert(nextSyncStarting > fightNow, "nextSyncStart wasn't updated before calling _ScheduleUpdate")
    }
    if (this.nextSyncEnd < this.syncEnds.length) {
      nextSyncEnding = this.syncEnds[this.nextSyncEnd].end;
      console.assert(nextSyncEnding > fightNow, "nextSyncEnd wasn't updated before calling _ScheduleUpdate")
    }

    var nextTime = Math.min(nextEventStarting, Math.min(nextEventEnding, Math.min(nextSyncStarting, nextSyncEnding)));
    if (nextTime != kBig) {
      console.assert(nextTime > fightNow, "nextTime is in the past")
      this.updateTimer = window.setTimeout(this._OnUpdateTimer.bind(this), (nextTime - fightNow) * 1000);
    }
  }

  _OnUpdateTimer() {
    console.assert(this.timebase, "_OnTimerUpdate called while stopped");

    // This is the number of seconds into the fight (subtracting Dates gives milliseconds).
    var fightNow = (new Date() - this.timebase) / 1000;
    this._AdvanceTimeTo(fightNow);
    this._CollectActiveSyncs(fightNow);

    this._AddDurationTimers(fightNow);
    this._RemoveExpiredTimers(fightNow);
    this._AddUpcomingTimers(fightNow);
    this._ScheduleUpdate(fightNow);
  }

  SetAddTimer(c) { this.addTimerCallback = c; }
  SetRemoveTimer(c) { this.removeTimerCallback = c; }
};

class TimelineUI {
  constructor() {
    this.init = false;
  }

  Init() {
    if (this.init) return;
    this.init = true;

    this.root = document.getElementById('timeline-container');
    this.timerlist = document.getElementById('timeline');
    this.timerlist.maxnumber = kMaxNumberOfTimerBars;
    this.timerlist.rowcolsize = kMaxNumberOfTimerBars;
    this.timerlist.elementwidth = kBarWidth;
    this.timerlist.elementheight = kBarHeight + 2;
    this.timerlist.toward = "down right";
    this.activeBars = {};
  }

  SetTimeline(timeline) {
    this.Init();
    if (this.timeline) {
      this.timeline.SetAddTimer(null);
      this.timeline.SetRemoveTimer(null);
      this.timerlist.clear();
      this.activeBars = {};
    }

    this.timeline = timeline;
    if (this.timeline) {
      this.timeline.SetAddTimer(this.OnAddTimer.bind(this));
      this.timeline.SetRemoveTimer(this.OnRemoveTimer.bind(this));
    }
  }

  OnAddTimer(fightNow, e, channeling) {
    var div = document.createElement('div');
    var bar = document.createElement('timer-bar');
    div.appendChild(bar);
    div.style.fontSize = kBarFontSize;
    bar.width = kBarWidth;
    bar.height = kBarHeight;
    bar.duration = e.time - fightNow;
    bar.righttext = 'remain';
    bar.lefttext = e.name;
    bar.toward = 'right';
    bar.style = !channeling ? 'fill' : 'empty';

    if (!channeling && e.time - fightNow > kBarExpiresSoonSeconds) {
      bar.fg = kBarColor;
      window.setTimeout(this.OnTimerExpiresSoon.bind(this, e.id), (e.time - fightNow - kBarExpiresSoonSeconds) * 1000);
    } else {
      bar.fg = kBarExpiresSoonColor;
    }

    this.timerlist.addElement(e.id, div, e.sortTime);
    this.activeBars[e.id] = bar;
  }

  OnTimerExpiresSoon(id) {
    if (id in this.activeBars)
      this.activeBars[id].fg = kBarExpiresSoonColor;
  }

  OnRemoveTimer(e, expired) {
    if (expired && kKeepExpiredTimerBarsForSeconds) {
      window.setTimeout(this.OnRemoveTimer.bind(this, e, false), kKeepExpiredTimerBarsForSeconds * 1000);
      return;
    }
    this.timerlist.removeElement(e.id);
    delete this.activeBars[e.id];
  }
};

class TimelineController {
  constructor(ui) {
    this.ui = ui;
    this.dataFiles = {};
  }

  OnInCombat(e) {
    if (!e.detail.inCombat && !this.inBossFight)
      this.OnBossFightStop();
  }

  OnBossFightStart() {
    this.inBossFight = true;
  }

  OnBossFightStop() {
    this.inBossFight = false;
    if (this.timeline)
      this.activeTimeline.Stop();
  }

  OnLogEvent(e) {
    if (!this.activeTimeline)
      return;
    for (var i = 0; i < e.detail.logs.length; ++i)
      this.activeTimeline.OnLogLine(e.detail.logs[i]);
  }

  OnZoneChanged(e) {
    this.activeTimeline = null;
    for (var i = 0; i < this.timelines.length; ++i) {
      if (e.detail.zoneName.search(this.timelines[i].zoneRegex) >= 0) {
        this.activeTimeline = this.timelines[i];
        break;
      }
    }
    this.ui.SetTimeline(this.activeTimeline);
  }

  SetDataFiles(files) {
    this.timelines = [];
    for (var f in files) {
      var nameWithoutExtension = f.split('.').slice(0, -1).join('.');
      this.timelines.push(new Timeline(nameWithoutExtension, files[f]));
    }
  }
}

var gTimelineController = new TimelineController(new TimelineUI());

document.addEventListener("onZoneChangedEvent", function(e) {
  gTimelineController.OnZoneChanged(e);
});
document.addEventListener("onInCombatChangedEvent", function (e) {
  gTimelineController.OnInCombat(e);
});
document.addEventListener("onBossFightStart", function(e) {
  gTimelineController.OnBossFightStart();
});
document.addEventListener("onBossFightEnd", function(e) {
  gTimelineController.OnBossFightStop();
});
document.addEventListener("onLogEvent", function(e) {
  gTimelineController.OnLogEvent(e);
});
document.addEventListener("onDataFilesRead", function(e) {
  gTimelineController.SetDataFiles(e.detail.files);
});<|endoftext|>


<commit_before>var main = function () {

    $('.showTooltip').tooltipster( {
        animation: 'fall',
        offsetX: 0,
        offsetY: 0,
        touchDevices: false,
        onlyOne: true,
        theme: 'tooltipster-default'
    });

    changeAnimation();

    hideBelowFold();

};

function changeAnimation() {

    // Get current url
    var url = window.location.href;

    // Process which class
    if (url.search('about') > 0) {
        $(".navAbout > a").toggleClass("animateAboutMeColor");
        $(".navAbout > a > img").toggleClass("animateAboutMe");
    } else if (url.search('blog') > 0) {
        $(".navBlog > a").toggleClass("animateBlogColor");
        $(".navBlog > a > img").toggleClass("animateBlog");
    } else if (url.search('research') > 0 ) {
        $(".navResearch > a").toggleClass("animateResearchColor");
        $(".navResearch > a > img").toggleClass("animateResearch");
    } else if (url.search('contact') > 0 ) {
        $(".navContact > a").toggleClass("animateContactColor");
        $(".navContact > a > img").toggleClass("animateContact");
    } else {
        $(".navAbout > a").toggleClass("animateAboutMeColor");
        $(".navAbout > a > img").toggleClass("animateAboutMe");
    }

}

function hideBelowFold() {
    // Get current url
    var url = window.location.href;

    if (url.slice(url.length-1,url.length) == '/') {
        url = url.slice(0,url.length-1);
    }

    if ('/blog' == url.slice(url.length-5,url.length) ) {
        $('div#breakStart').nextUntil('div#breakEnd').hide();
    }
}

$(document).ready(main);<commit_msg>Updated hide query to work in safari, chrome, and firefox<commit_after>var main = function () {

    $('.showTooltip').tooltipster( {
        animation: 'fall',
        offsetX: 0,
        offsetY: 0,
        touchDevices: false,
        onlyOne: true,
        theme: 'tooltipster-default'
    });

    changeAnimation();

    hideBelowFold();

};

function changeAnimation() {

    // Get current url
    var url = window.location.href;

    // Process which class
    if (url.search('about') > 0) {
        $(".navAbout > a").toggleClass("animateAboutMeColor");
        $(".navAbout > a > img").toggleClass("animateAboutMe");
    } else if (url.search('blog') > 0) {
        $(".navBlog > a").toggleClass("animateBlogColor");
        $(".navBlog > a > img").toggleClass("animateBlog");
    } else if (url.search('research') > 0 ) {
        $(".navResearch > a").toggleClass("animateResearchColor");
        $(".navResearch > a > img").toggleClass("animateResearch");
    } else if (url.search('contact') > 0 ) {
        $(".navContact > a").toggleClass("animateContactColor");
        $(".navContact > a > img").toggleClass("animateContact");
    } else {
        $(".navAbout > a").toggleClass("animateAboutMeColor");
        $(".navAbout > a > img").toggleClass("animateAboutMe");
    }

}

function hideBelowFold() {
    // Get current url
    var url = window.location.href;

    if (url.slice(url.length-1,url.length) == '/') {
        url = url.slice(0,url.length-1);
    }

    if ('/blog' == url.slice(url.length-5,url.length) ) {
        $('div#breakStart').nextUntil('div#breakEnd').css('display', 'none');
        $('div#breakStart').nextUntil('div#breakEnd').hide();
    }
}

$(document).ready(main);<|endoftext|>


<commit_before>/*
 * The OnCore Consulting LLC License
 *
 * Copyright 2016 OnCore Consulting LLC, All Rights Reserved.
 *
 * Permission IS NOT GRANTED to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, unless the following conditions are met:
 *
 * Written permission is obtained from
 * OnCore Consulting LLC and the above copyright
 * notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * The ServiceEndPoints object defines all Service End points used
 * by the application.  This file should be altered on deployment
 * by the CM scripts to alter the endpoints based on target environment.
 *
 * @author Royce Owens
 *
 * @returns {ServiceEndPoints}
 */
'use strict';
function ServiceEndPoints()
{

}

ServiceEndPoints.prototype = {

    /**
     * Given a service name, return the fully
     * qualified service URL.
     *
     * @param {type} key a service name
     * @returns {String} a fully qualified URL
     */
    getEndPoint: function (key)
    {
        // ====== CM TOUCH POINT =================
        var calOrdersHost = "http://localhost:8080";
        // =======================================

        if (key === "findNavBarPrivilegesByPartyId")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findNavBarPrivilegesByPartyId";
        } else if (key === "findNavMenuPrivilegesByPartyId")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findNavMenuPrivilegesByPartyId";
        } else if (key === "findAllPrivilegesByPartyId")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findAllPrivilegesByPartyId";
        } else if (key === "findPartyByUserIdAndPassword")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findPartyByUserIdAndPassword";
        } else if (key === "findActiveProductsByProductType")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/findActiveProductsByProductType";
        } else if (key === "findProductsByProductType")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/findProductsByProductType";
        } else if (key === "createOrder")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/createOrder";
        } else if (key === "findAllVendors")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.vendor";
        } else if (key === "findAllCategories")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.prdcategorycd";
        } else if (key === "doesProductNameExist")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/doesProductNameExist";
        } else if (key === "createProduct")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/createProduct";
        } else if (key === "updateProduct")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/updateProduct";
        } else if (key === "findAllUnitCodes")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.prdunitcd";
        } else if (key === "findProductById")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product";
        } else if (key === "findActiveProductsByProductTypeAndVendor")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/findActiveProductsByProductTypeAndVendor";
        } else if (key === "fetchOrdersByQuarter")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/fetchOrdersByQuarter";
        } else if (key === "fetchOrderStatusSummary")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/fetchOrderStatusSummary";
        } else if (key === "findAllOrderHistoryByPartyUid")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/findAllOrderHistoryByPartyUid";
        } else
        {
            return "UNDEFINED";
        }

    }
};
<commit_msg>[#139517893] - Initial checkin for Order Detail<commit_after>/*
 * The OnCore Consulting LLC License
 *
 * Copyright 2016 OnCore Consulting LLC, All Rights Reserved.
 *
 * Permission IS NOT GRANTED to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, unless the following conditions are met:
 *
 * Written permission is obtained from
 * OnCore Consulting LLC and the above copyright
 * notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * The ServiceEndPoints object defines all Service End points used
 * by the application.  This file should be altered on deployment
 * by the CM scripts to alter the endpoints based on target environment.
 *
 * @author Royce Owens
 *
 * @returns {ServiceEndPoints}
 */
'use strict';
function ServiceEndPoints()
{

}

ServiceEndPoints.prototype = {

    /**
     * Given a service name, return the fully
     * qualified service URL.
     *
     * @param {type} key a service name
     * @returns {String} a fully qualified URL
     */
    getEndPoint: function (key)
    {
        // ====== CM TOUCH POINT =================
        var calOrdersHost = "http://localhost:8080";
        // =======================================

        if (key === "findNavBarPrivilegesByPartyId")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findNavBarPrivilegesByPartyId";
        } else if (key === "findNavMenuPrivilegesByPartyId")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findNavMenuPrivilegesByPartyId";
        } else if (key === "findAllPrivilegesByPartyId")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findAllPrivilegesByPartyId";
        } else if (key === "findPartyByUserIdAndPassword")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.party/findPartyByUserIdAndPassword";
        } else if (key === "findActiveProductsByProductType")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/findActiveProductsByProductType";
        } else if (key === "findProductsByProductType")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/findProductsByProductType";
        } else if (key === "createOrder")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/createOrder";
        } else if (key === "findAllVendors")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.vendor";
        } else if (key === "findAllCategories")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.prdcategorycd";
        } else if (key === "doesProductNameExist")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/doesProductNameExist";
        } else if (key === "createProduct")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/createProduct";
        } else if (key === "updateProduct")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/updateProduct";
        } else if (key === "findAllUnitCodes")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.prdunitcd";
        } else if (key === "findProductById")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product";
        } else if (key === "findActiveProductsByProductTypeAndVendor")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.product/findActiveProductsByProductTypeAndVendor";
        } else if (key === "fetchOrdersByQuarter")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/fetchOrdersByQuarter";
        } else if (key === "fetchOrderStatusSummary")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/fetchOrderStatusSummary";
        } else if (key === "findAllOrderHistoryByPartyUid")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/findAllOrderHistoryByPartyUid";
        } else if (key === "findOrderDetailById")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/findOrderDetailById";
        } else if (key === "cancelOrderHistory")
        {
            return calOrdersHost + "/CalOrdersRest/webresources/com.oncore.calorders.rest.orderHistory/cancelOrderDetail";
        } else
        {
            return "UNDEFINED";
        }

    }
};
<|endoftext|>


<commit_before>var db = null;

angular.module('cat5scouting', ['ionic', 'cat5scouting.controllers', 'ngCordova'])

.run(function($ionicPlatform, $cordovaSQLite) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);

    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

    var db = $cordovaSQLite.openDB("cat5scouting.db");
    $cordovaSQLite.execute(db, "CREATE TABLE IF NOT EXISTS people (id integer primary key, firstname text, lastname text)");
  });
})

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider

  .state('app', {
    url: '/app',
    abstract: true,
    templateUrl: 'templates/menu.html',
    controller: 'AppCtrl'
  })

  .state('app.home', {
    url: '/home',
    views: {
      'menuContent': {
        templateUrl: 'templates/home.html',
        controller: 'HomeCtrl'
      }
    }
  })

  .state('app.pit', {
    url: '/pit',
    views: {
      'menuContent': {
        templateUrl: 'templates/pit.html',
        controller: 'PitCtrl'
      }
    }
  })

  .state('app.match', {
    url: '/match',
    views: {
      'menuContent': {
        templateUrl: '/templates/match.html',
        controller: 'MatchCtrl'
      }
    }
  })

  .state('app.sync', {
    url: '/sync',
    views: {
      'menuContent': {
        templateUrl: '/templates/sync.html',
        controller: 'SyncCtrl'
      }
    }
  })

  .state('app.config', {
    url: '/config',
    views: {
      'menuContent': {
        templateUrl: '/templates/settings.html',
        controller: 'SettingsCtrl'
      }
    }
  });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/app/home');
});
<commit_msg>Updated app.js to resolve issue with templateUrl values<commit_after>var db = null;

angular.module('cat5scouting', ['ionic', 'cat5scouting.controllers', 'ngCordova'])

.run(function($ionicPlatform, $cordovaSQLite) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);

    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

    if (window.cordova) {
      db = $cordovaSQLite.openDB("cat5scouting.db");
    } else {
      db = window.openDatabase("cat5scouting.db", "1.0", "cat5scouting", -1);
    }

    $cordovaSQLite.execute(db, "CREATE TABLE IF NOT EXISTS event (ID INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT, Name TEXT UNIQUE NOT NULL)");
  });
})

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider

  .state('app', {
    url: '/app',
    abstract: true,
    templateUrl: 'templates/menu.html',
    controller: 'AppCtrl'
  })

  .state('app.home', {
    url: '/home',
    views: {
      'menuContent': {
        templateUrl: 'templates/home.html',
        controller: 'HomeCtrl'
      }
    }
  })

  .state('app.pit', {
    url: '/pit',
    views: {
      'menuContent': {
        templateUrl: 'templates/pit.html',
        controller: 'PitCtrl'
      }
    }
  })

  .state('app.match', {
    url: '/match',
    views: {
      'menuContent': {
        templateUrl: 'templates/match.html',
        controller: 'MatchCtrl'
      }
    }
  })

  .state('app.sync', {
    url: '/sync',
    views: {
      'menuContent': {
        templateUrl: 'templates/sync.html',
        controller: 'SyncCtrl'
      }
    }
  })

  .state('app.config', {
    url: '/config',
    views: {
      'menuContent': {
        templateUrl: 'templates/settings.html',
        controller: 'SettingsCtrl'
      }
    }
  });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/app/home');
});
<|endoftext|>


<commit_before>//========================================================================================
// Globals
//========================================================================================
var util = require('util');

var Parser = function() {
    this.varName = '';
    this.type = '';
    this.options = {};
    this.next = null;
    this.head = null;
    this.compiled = null;
};

var PRIMITIVE_TYPES = {
    'UInt8'    : 1,
    'UInt16LE' : 2,
    'UInt16BE' : 2,
    'UInt32LE' : 4,
    'UInt32BE' : 4,
    'Int8'     : 1,
    'Int16LE'  : 2,
    'Int16BE'  : 2,
    'Int32LE'  : 4,
    'Int32BE'  : 4,
    'FloatLE'  : 4,
    'FloatBE'  : 4,
    'DoubleLE' : 8,
    'DoubleBE' : 8
};

var SPECIAL_TYPES = {
    'String'   : null,
    'Array'    : null,
    'Skip'     : null,
    'Choice'   : null
};

// Converts Parser's method names to internal type names
var NAME_MAP = {};
Object.keys(PRIMITIVE_TYPES)
    .concat(Object.keys(SPECIAL_TYPES))
    .forEach(function(type) {
        NAME_MAP[type.toLowerCase()] = type;
    });

//========================================================================================
// Parser builder functions
//========================================================================================

Parser.start = function() {
    return new Parser();
};

Parser.prototype.setNextParser = function(type, varName, options) {
    var parser = new Parser();

    parser.type = NAME_MAP[type];
    parser.varName = varName;
    parser.options = options || parser.options;

    if (this.head) {
        this.head.next = parser;
    } else {
        this.next = parser;
    }
    this.head = parser;

    return this;
};

Object.keys(PRIMITIVE_TYPES)
    .forEach(function(type) {
        Parser.prototype[type.toLowerCase()] = function(varName, options) {
            return this.setNextParser(type.toLowerCase(), varName, options);
        };
    });

Parser.prototype.skip = function(length) {
    return this.setNextParser('skip', '', {length: length});
};

Parser.prototype.string = function(varName, options) {
    if (!options.length) {
        throw new Error('Length option of string is not defined.');
    }
    options.encoding = options.encoding || 'utf8';

    return this.setNextParser('string', varName, options);
};

Parser.prototype.array = function(varName, options) {
    if (!options.length) {
        throw new Error('Length option of array is not defined.');
    }
    if (!options.type) {
        throw new Error('Type option of array is not defined.');
    }
    if (typeof options.type === 'string' && Object.keys(PRIMITIVE_TYPES).indexOf(NAME_MAP[options.type]) < 0) {
        throw new Error('Specified primitive type "' + options.type + '" is not supported.');
    }

    return this.setNextParser('array', varName, options);
};

Parser.prototype.choice = function(varName, options) {
    if (!options.tag) {
        throw new Error('Tag option of array is not defined.');
    }
    if (!options.choices) {
        throw new Error('Choices option of array is not defined.');
    }
    Object.keys(options.choices).forEach(function(key) {
        if (isNaN(parseInt(key, 10))) {
            throw new Error('Key of choices must be a number.');
        }
        if (!options.choices[key]) {
            throw new Error('Choice ' + key + ' of ' + varName + ' is not defined.');
        }

        if (typeof options.choices[key] === 'string' && Object.keys(PRIMITIVE_TYPES).indexOf(NAME_MAP[options.choices[key]]) < 0) {
            throw new Error('Specified primitive type "' +  options.choices[key] + '" is not supported.');
        }
    });

    return this.setNextParser('choice', varName, options);
};

Parser.prototype.endianess = function(endianess) {
    if (endianess !== 'little' && endianess !== 'big') {
        throw new Error('Invalid endianess: ' + endianess);
    }
    var re = endianess === 'little' ? /(.+)LE/ : /(.+)BE/;

    Object.keys(PRIMITIVE_TYPES).forEach(function(type) {
        var matched = type.match(re);
        if (matched) {
            var funcName = matched[1].toLowerCase();
            Parser.prototype[funcName] = Parser.prototype[type.toLowerCase()];
        }
    });

    return this;
};

//========================================================================================
// Parsers
//========================================================================================

// Follow the parser chain till the root and start parsing from there
Parser.prototype.parse = function(buffer) {
    if (!Buffer.isBuffer(buffer)) {
        throw new Error('argument "buffer" is not a Buffer object');
    }

    if (this.compiled) {
        return this.compiled(buffer);
    }

    return this.next._parse({
        buffer: buffer,
        iterator: 0,
        vars: {}
    }).vars;
};

// Start parsing from this parser
Parser.prototype._parse = function(ctx) {
    return this['_parse' + this.type](ctx);
};

Parser.prototype.parseNext = function(ctx) {
    return this.next ? this.next._parse(ctx) : ctx;
};

Object.keys(PRIMITIVE_TYPES).forEach(function(type) {
    Parser.prototype['_parse' + type] = function(ctx) {
        ctx.vars[this.varName] = ctx.buffer['read' + type](ctx.iterator);
        ctx.iterator += PRIMITIVE_TYPES[type];

        return this.parseNext(ctx);
    };
});

Parser.prototype._parseSkip = function(ctx) {
    ctx.iterator += this.options.length;

    return this.parseNext(ctx);
};

Parser.prototype.evalField = function(val, ctx) {
    if (typeof val === 'number') {
        return val;
    } else if (typeof val === 'string') {
        if (val in ctx.vars) {
            return ctx.vars[val];
        } else {
            throw new Error('Field ' + val + ' is not yet defined.');
        }
    } else if (typeof val === 'function') {
        return val.call(ctx.vars);
    }
};

Parser.prototype._parseString = function(ctx) {
    var encoding = this.options.encoding;
    var length = this.evalField(this.options.length, ctx);

    ctx.vars[this.varName] = ctx.buffer.toString(encoding, ctx.iterator, ctx.iterator + length);
    ctx.iterator += length;

    return this.parseNext(ctx);
};

Parser.prototype._parseArray = function(ctx) {
    var length = this.evalField(this.options.length, ctx);
    var type = this.options.type;
    var i, data, tmp;

    ctx.vars[this.varName] = [];
    if (typeof type === 'string') {
        for (i = 0; i < length ; i++) {
            tmp = this['_parse' + NAME_MAP[type]].call(
                new Parser(), {
                buffer: ctx.buffer,
                iterator: ctx.iterator,
                vars: {}
            });
            ctx.iterator = tmp.iterator;
            ctx.vars[this.varName].push(tmp.vars['']);
        }
    } else if (type instanceof Parser) {
        for (i = 0; i < length ; i++) {
            tmp = type.next._parse({
                buffer: ctx.buffer,
                iterator: ctx.iterator,
                vars: {}
            });
            ctx.iterator = tmp.iterator;
            ctx.vars[this.varName].push(tmp.vars);
        }
    }

    return this.parseNext(ctx);
};

Parser.prototype._parseChoice = function(ctx) {
    var tag = this.evalField(this.options.tag, ctx);
    var type = this.options.choices[tag];
    var tmp;

    if (typeof type === 'string') {
        tmp = this['_parse' + NAME_MAP[type]].call(
            new Parser(), {
            buffer: ctx.buffer,
            iterator: ctx.iterator,
            vars: {}
        });
        ctx.iterator = tmp.iterator;
        ctx.vars[this.varName] = tmp.vars[''];
    } else if (type instanceof Parser) {
        tmp = type.next._parse({
            buffer: ctx.buffer,
            iterator: ctx.iterator,
            vars: {}
        });
        ctx.iterator = tmp.iterator;
        ctx.vars[this.varName] = tmp.vars;
    }

    return this.parseNext(ctx);
};

//========================================================================================
// JIT code generators
//========================================================================================

Parser.prototype.compile = function() {
    var code = util.format(
                'var vars = {};\n' +
                'var iterator = 0;\n' +
                '%s' +
                'return vars;',
             this.next.generate({
                code: 0,
                forDepth: 0,
                context: []
             }));

    console.log();
    console.log(code);

    this.compiled = new Function('buffer', code);
};

// Call code generator for this parser
Parser.prototype.generate = function(ctx) {
    return this['generate' + this.type]();
};

// Recursively call code generators and append results
Parser.prototype.generateNextParser = function(code) {
    if (this.next) {
        code += this.next.generate();
    }

    return code;
};

Object.keys(PRIMITIVE_TYPES).forEach(function(type) {
    Parser.prototype['generate' + type] = function() {
        var code = '';

        code += util.format('vars.%s = buffer.read%s(iterator);\n', this.varName, type);
        code += util.format('iterator += %d;\n', PRIMITIVE_TYPES[type]);

        return this.generateNextParser(code);
    };
});

Parser.prototype.generateField = function(val) {
    if (typeof val === 'number') {
        return val.toString();
    } else if (typeof val === 'string') {
        return util.format('vars.%s', val);
    } else if (typeof val === 'function') {
        return util.format('(%s)(vars)', val);
    }
};

Parser.prototype.generateSkip = function() {
    var code = util.format('iterator += %d;\n', this.options.length);

    return this.generateNextParser(code);
};

Parser.prototype.generateString = function() {
    var code = '';
    code += util.format('vars.%s = buffer.toString(\'%s\', iterator, iterator + %s);\n',
                                this.varName,
                                this.options.encoding,
                                this.generateField(this.options.length)
                            );
    code += util.format('iterator += %s;\n', this.generateField(this.options.length));

    return this.generateNextParser(code);
};

Parser.prototype.generateArray = function() {
    var length = this.generateField(this.options.length);
    var type = this.options.type;
    var code = '';

    if (typeof type === 'string') {
        code += util.format('vars.%s = [];\n', this.varName);
        code += util.format('for (var i = 0; i < %s; i++) {\n', length);
        code += util.format('\tvars.%s.push(buffer.read%s(iterator));\n', this.varName, NAME_MAP[type]);
        code += util.format('\titerator += %d;\n', PRIMITIVE_TYPES[NAME_MAP[type]]);
        code += '}\n';
    } else if (type instanceof Parser) {
        for (i = 0; i < length ; i++) {
            ctx = type.next._parse({
                buffer: context.buffer,
                iterator: context.iterator,
                vars: {}
            });
            context.iterator = ctx.iterator;
            context.vars[this.varName].push(ctx.vars);
        }
    }
    return this.generateNextParser(code);
};

//========================================================================================
// Utilities
//========================================================================================

Parser.prototype.sizeOf = function() {
    var size = NaN;

    if (Object.keys(PRIMITIVE_TYPES).indexOf(this.type) >= 0) {
        size = PRIMITIVE_TYPES[this.type];

    // if this is a fixed length string
    } else if (this.type === 'String' && typeof this.options.length === 'number') {
        size = this.options.length;

    // if this is a fixed length array
    } else if (this.type === 'Array' && typeof this.options.length === 'number') {
        var elementSize = NaN;
        if (typeof this.options.type === 'string'){
            elementSize = PRIMITIVE_TYPES[NAME_MAP[this.options.type]];
        } else if (this.options.type instanceof Parser) {
            elementSize = this.options.type.sizeOf();
        }
        size = this.options.length * elementSize;

    // if this a skip
    } else if (this.type === 'Skip') {
        size = this.options.length;

    } else if (!this.type) {
        size = 0;
    }

    if (this.next) {
        size += this.next.sizeOf();
    }

    return size;
};

//========================================================================================
// Exports
//========================================================================================

// TODO skip should be also variable length
// TODO nestable arrays

exports.Parser = Parser;
<commit_msg>Introduced context object which is passed through code generators<commit_after>//========================================================================================
// Globals
//========================================================================================
var util = require('util');

var Parser = function() {
    this.varName = '';
    this.type = '';
    this.options = {};
    this.next = null;
    this.head = null;
    this.compiled = null;
};

var PRIMITIVE_TYPES = {
    'UInt8'    : 1,
    'UInt16LE' : 2,
    'UInt16BE' : 2,
    'UInt32LE' : 4,
    'UInt32BE' : 4,
    'Int8'     : 1,
    'Int16LE'  : 2,
    'Int16BE'  : 2,
    'Int32LE'  : 4,
    'Int32BE'  : 4,
    'FloatLE'  : 4,
    'FloatBE'  : 4,
    'DoubleLE' : 8,
    'DoubleBE' : 8
};

var SPECIAL_TYPES = {
    'String'   : null,
    'Array'    : null,
    'Skip'     : null,
    'Choice'   : null
};

// Converts Parser's method names to internal type names
var NAME_MAP = {};
Object.keys(PRIMITIVE_TYPES)
    .concat(Object.keys(SPECIAL_TYPES))
    .forEach(function(type) {
        NAME_MAP[type.toLowerCase()] = type;
    });

//========================================================================================
// Parser builder functions
//========================================================================================

Parser.start = function() {
    return new Parser();
};

Parser.prototype.setNextParser = function(type, varName, options) {
    var parser = new Parser();

    parser.type = NAME_MAP[type];
    parser.varName = varName;
    parser.options = options || parser.options;

    if (this.head) {
        this.head.next = parser;
    } else {
        this.next = parser;
    }
    this.head = parser;

    return this;
};

Object.keys(PRIMITIVE_TYPES)
    .forEach(function(type) {
        Parser.prototype[type.toLowerCase()] = function(varName, options) {
            return this.setNextParser(type.toLowerCase(), varName, options);
        };
    });

Parser.prototype.skip = function(length) {
    return this.setNextParser('skip', '', {length: length});
};

Parser.prototype.string = function(varName, options) {
    if (!options.length) {
        throw new Error('Length option of string is not defined.');
    }
    options.encoding = options.encoding || 'utf8';

    return this.setNextParser('string', varName, options);
};

Parser.prototype.array = function(varName, options) {
    if (!options.length) {
        throw new Error('Length option of array is not defined.');
    }
    if (!options.type) {
        throw new Error('Type option of array is not defined.');
    }
    if (typeof options.type === 'string' && Object.keys(PRIMITIVE_TYPES).indexOf(NAME_MAP[options.type]) < 0) {
        throw new Error('Specified primitive type "' + options.type + '" is not supported.');
    }

    return this.setNextParser('array', varName, options);
};

Parser.prototype.choice = function(varName, options) {
    if (!options.tag) {
        throw new Error('Tag option of array is not defined.');
    }
    if (!options.choices) {
        throw new Error('Choices option of array is not defined.');
    }
    Object.keys(options.choices).forEach(function(key) {
        if (isNaN(parseInt(key, 10))) {
            throw new Error('Key of choices must be a number.');
        }
        if (!options.choices[key]) {
            throw new Error('Choice ' + key + ' of ' + varName + ' is not defined.');
        }

        if (typeof options.choices[key] === 'string' && Object.keys(PRIMITIVE_TYPES).indexOf(NAME_MAP[options.choices[key]]) < 0) {
            throw new Error('Specified primitive type "' +  options.choices[key] + '" is not supported.');
        }
    });

    return this.setNextParser('choice', varName, options);
};

Parser.prototype.endianess = function(endianess) {
    if (endianess !== 'little' && endianess !== 'big') {
        throw new Error('Invalid endianess: ' + endianess);
    }
    var re = endianess === 'little' ? /(.+)LE/ : /(.+)BE/;

    Object.keys(PRIMITIVE_TYPES).forEach(function(type) {
        var matched = type.match(re);
        if (matched) {
            var funcName = matched[1].toLowerCase();
            Parser.prototype[funcName] = Parser.prototype[type.toLowerCase()];
        }
    });

    return this;
};

//========================================================================================
// Parsers
//========================================================================================

// Follow the parser chain till the root and start parsing from there
Parser.prototype.parse = function(buffer) {
    if (!Buffer.isBuffer(buffer)) {
        throw new Error('argument "buffer" is not a Buffer object');
    }

    if (this.compiled) {
        return this.compiled(buffer);
    }

    return this.next._parse({
        buffer: buffer,
        iterator: 0,
        vars: {}
    }).vars;
};

// Start parsing from this parser
Parser.prototype._parse = function(ctx) {
    return this['_parse' + this.type](ctx);
};

Parser.prototype.parseNext = function(ctx) {
    return this.next ? this.next._parse(ctx) : ctx;
};

Object.keys(PRIMITIVE_TYPES).forEach(function(type) {
    Parser.prototype['_parse' + type] = function(ctx) {
        ctx.vars[this.varName] = ctx.buffer['read' + type](ctx.iterator);
        ctx.iterator += PRIMITIVE_TYPES[type];

        return this.parseNext(ctx);
    };
});

Parser.prototype._parseSkip = function(ctx) {
    ctx.iterator += this.options.length;

    return this.parseNext(ctx);
};

Parser.prototype.evalField = function(val, ctx) {
    if (typeof val === 'number') {
        return val;
    } else if (typeof val === 'string') {
        if (val in ctx.vars) {
            return ctx.vars[val];
        } else {
            throw new Error('Field ' + val + ' is not yet defined.');
        }
    } else if (typeof val === 'function') {
        return val.call(ctx.vars);
    }
};

Parser.prototype._parseString = function(ctx) {
    var encoding = this.options.encoding;
    var length = this.evalField(this.options.length, ctx);

    ctx.vars[this.varName] = ctx.buffer.toString(encoding, ctx.iterator, ctx.iterator + length);
    ctx.iterator += length;

    return this.parseNext(ctx);
};

Parser.prototype._parseArray = function(ctx) {
    var length = this.evalField(this.options.length, ctx);
    var type = this.options.type;
    var i, data, tmp;

    ctx.vars[this.varName] = [];
    if (typeof type === 'string') {
        for (i = 0; i < length ; i++) {
            tmp = this['_parse' + NAME_MAP[type]].call(
                new Parser(), {
                buffer: ctx.buffer,
                iterator: ctx.iterator,
                vars: {}
            });
            ctx.iterator = tmp.iterator;
            ctx.vars[this.varName].push(tmp.vars['']);
        }
    } else if (type instanceof Parser) {
        for (i = 0; i < length ; i++) {
            tmp = type.next._parse({
                buffer: ctx.buffer,
                iterator: ctx.iterator,
                vars: {}
            });
            ctx.iterator = tmp.iterator;
            ctx.vars[this.varName].push(tmp.vars);
        }
    }

    return this.parseNext(ctx);
};

Parser.prototype._parseChoice = function(ctx) {
    var tag = this.evalField(this.options.tag, ctx);
    var type = this.options.choices[tag];
    var tmp;

    if (typeof type === 'string') {
        tmp = this['_parse' + NAME_MAP[type]].call(
            new Parser(), {
            buffer: ctx.buffer,
            iterator: ctx.iterator,
            vars: {}
        });
        ctx.iterator = tmp.iterator;
        ctx.vars[this.varName] = tmp.vars[''];
    } else if (type instanceof Parser) {
        tmp = type.next._parse({
            buffer: ctx.buffer,
            iterator: ctx.iterator,
            vars: {}
        });
        ctx.iterator = tmp.iterator;
        ctx.vars[this.varName] = tmp.vars;
    }

    return this.parseNext(ctx);
};

//========================================================================================
// JIT code generators
//========================================================================================

Parser.prototype.compile = function() {
    var code =  'var vars = {};\n' +
                'var iterator = 0;\n' +
                this.next.generate({code: '', scopes: []}).code +
                'return vars;';

    console.log();
    console.log(code);

    this.compiled = new Function('buffer', code);
};

// Call code generator for this parser
Parser.prototype.generate = function(ctx) {
    return this['generate' + this.type](ctx);
};

// Recursively call code generators and append results
Parser.prototype.generateNextParser = function(ctx) {
    if (this.next) {
        ctx = this.next.generate(ctx);
    }

    return ctx;
};

Object.keys(PRIMITIVE_TYPES).forEach(function(type) {
    Parser.prototype['generate' + type] = function(ctx) {
        ctx.code += util.format('vars.%s = buffer.read%s(iterator);\n', this.varName, type);
        ctx.code += util.format('iterator += %d;\n', PRIMITIVE_TYPES[type]);

        return this.generateNextParser(ctx);
    };
});

Parser.prototype.generateField = function(val, ctx) {
    if (typeof val === 'number') {
        return val.toString();
    } else if (typeof val === 'string') {
        return util.format('vars.%s', val);
    } else if (typeof val === 'function') {
        return util.format('(%s)(vars)', val);
    }
};

Parser.prototype.generateSkip = function(ctx) {
    var length = this.generateField(this.options.length, ctx);
    ctx.code += util.format('iterator += %s;\n', length);

    return this.generateNextParser(ctx);
};

Parser.prototype.generateString = function(ctx) {
    ctx.code += util.format('vars.%s = buffer.toString(\'%s\', iterator, iterator + %s);\n',
                                this.varName,
                                this.options.encoding,
                                this.generateField(this.options.length, ctx)
                            );
    ctx.code += util.format('iterator += %s;\n', this.generateField(this.options.length, ctx));

    return this.generateNextParser(ctx);
};

Parser.prototype.generateArray = function(ctx) {
    var length = this.generateField(this.options.length, ctx);
    var type = this.options.type;

    if (typeof type === 'string') {
        ctx.code += util.format('vars.%s = [];\n', this.varName);
        ctx.code += util.format('for (var i = 0; i < %s; i++) {\n', length);
        ctx.code += util.format('\tvars.%s.push(buffer.read%s(iterator));\n', this.varName, NAME_MAP[type]);
        ctx.code += util.format('\titerator += %d;\n', PRIMITIVE_TYPES[NAME_MAP[type]]);
        ctx.code += '}\n';
    } else if (type instanceof Parser) {
        for (i = 0; i < length ; i++) {
            ctx = type.next._parse({
                buffer: context.buffer,
                iterator: context.iterator,
                vars: {}
            });
            context.iterator = ctx.iterator;
            context.vars[this.varName].push(ctx.vars);
        }
    }
    return this.generateNextParser(ctx);
};

//========================================================================================
// Utilities
//========================================================================================

Parser.prototype.sizeOf = function() {
    var size = NaN;

    if (Object.keys(PRIMITIVE_TYPES).indexOf(this.type) >= 0) {
        size = PRIMITIVE_TYPES[this.type];

    // if this is a fixed length string
    } else if (this.type === 'String' && typeof this.options.length === 'number') {
        size = this.options.length;

    // if this is a fixed length array
    } else if (this.type === 'Array' && typeof this.options.length === 'number') {
        var elementSize = NaN;
        if (typeof this.options.type === 'string'){
            elementSize = PRIMITIVE_TYPES[NAME_MAP[this.options.type]];
        } else if (this.options.type instanceof Parser) {
            elementSize = this.options.type.sizeOf();
        }
        size = this.options.length * elementSize;

    // if this a skip
    } else if (this.type === 'Skip') {
        size = this.options.length;

    } else if (!this.type) {
        size = 0;
    }

    if (this.next) {
        size += this.next.sizeOf();
    }

    return size;
};

//========================================================================================
// Exports
//========================================================================================

// TODO skip should be also variable length
// TODO nestable arrays

exports.Parser = Parser;
<|endoftext|>