<commit_before>import Realm from 'realm';
import { complement } from 'set-manipulator';

import { createRecord, getTotal } from '../utilities';

/**
 * A transaction item.
 *
 * @property  {string}                   id
 * @property  {Item}                     item
 * @property  {Transaction}              transaction
 * @property  {List.<TransactionBatch>}  batches
 */
export class TransactionItem extends Realm.Object {
  /**
   * Delete transaction item associated with unfinalised transaction.
   */
  destructor(database) {
    if (this.transaction.isFinalised) {
      throw new Error('Cannot delete an item from a finalised transaction');
    }
    database.delete('TransactionBatch', this.batches);
  }

  get hasValidDoses() {
    return this.batches.every(({ hasValidDoses }) => hasValidDoses);
  }

  /**
   * Get id of item associated with this transaction item.
   *
   * @return  {string}
   */
  get itemId() {
    return this.item ? this.item.id : '';
  }

  /**
   * Get name of item associated with this transaction item.
   *
   * @return  {string}
   */
  get itemName() {
    return this.item ? this.item.name : '';
  }

  /**
   * Get code of item associated with this transaction item.
   *
   * @return  {string}
   */
  get itemCode() {
    return this.item ? this.item.code : '';
  }

  /**
   * Get total quantity of batches associated with this transaction item.
   *
   * @return  {number}
   */
  get totalQuantity() {
    return getTotal(this.batches, 'totalQuantity');
  }

  /**
   * Get total quantity of batches associated with this transaction item which have been sent.
   *
   * @return  {number}
   */
  get totalQuantitySent() {
    return getTotal(this.batches, 'totalQuantitySent');
  }

  /**
   * Get total price of batches associated with this transaction item.
   *
   * @return  {number}
   */
  get totalPrice() {
    return getTotal(this.batches, 'totalPrice');
  }

  /**
   * Get total number of batches associated with this transaction item.
   *
   * @return  {number}
   */
  get numberOfBatches() {
    return this.batches.length;
  }

  /**
   * Get available quantity of items.
   *
   * For customer invoices, get how much can be issued in total, accounting for the fact that any
   * issued in a confirmed customer invoice has already been taken off the total.
   *
   * @return  {number}
   */
  get availableQuantity() {
    if (
      this.transaction.isOutgoing &&
      (this.transaction.isConfirmed || this.transaction.isFinalised)
    ) {
      return this.item.totalQuantity + this.totalQuantity;
    }
    return this.item.totalQuantity;
  }

  /**
   * Get the batch attached to this transaction item with the given item batch id.
   *
   * @param   {string}            itemId
   * @return  {TransactionBatch}
   */
  getBatch(itemBatchId) {
    return this.batches.find(transactionBatch => transactionBatch.itemBatchId === itemBatchId);
  }

  addBatch(transactionBatch) {
    this.batches.push(transactionBatch);
  }

  /**
   * Sets the quantity for the current item by applying the difference to the
   * shortest expiry batches possible.
   *
   * N.B. for customer invoices, will create and delete transaction batches as appropriate.
   * N.B.  supplier invoices do not take effect on the rest of the stock until they
   * are finalised, whereas customer invoices immediately influence stock levels.
   *
   * @param  {Realm}   database
   * @param  {double}  quantity
   */
  setTotalQuantity(database, quantity) {
    if (this.transaction.isFinalised) {
      throw new Error('Cannot set quantity of an item in a finalised transaction');
    }
    let cappedQuantity = quantity;
    if (this.transaction.isOutgoing) {
      cappedQuantity = Math.min(quantity, this.availableQuantity);
    }
    if (quantity < 0) {
      throw new Error('Cannot set a negative quantity on a transaction item');
    }

    const difference = cappedQuantity - this.totalQuantity; // Positive if new quantity is greater.

    // Apply the difference to make the new quantity.
    this.allocateDifferenceToBatches(database, difference);

    // See if any batches can be pruned, i.e. have a quantity of zero for this invoice.
    this.pruneEmptyBatches(database);
  }

  /**
   * Applies the given difference in quantity to the appropriate batches.
   *
   * If the difference is an increase, it will apply to the shortest expiry batches possible.
   * If a reduction, it will apply to the longest batches possible. In this way it is FEFO for
   * customer invoices, and pessimistic with changes to supplier invoices (assumes more of the
   * shortest batch or less of the longest batch). This has the side effect of also being FEFO
   * for supplier credits made from stocktake inventory adjustments, which is optimistic, but
   * not problematic. Null expiries are treated as absolute shortest, which means they will be
   * issued first.
   *
   * @param {Realm}   database
   * @param {number}  difference  The difference in quantity to set across all batches.
   *                              Positive if greater new quantity, negative if lesser.
   */
  allocateDifferenceToBatches(database, difference) {
    // Sort batches from shortest to longest if increasing, else longest to shortest.
    const batches = this.batches.sorted('expiryDate', difference < 0);

    // First apply as much of the quantity as possible to existing batches.
    let remainder = difference;
    for (let index = 0; remainder !== 0 && index < batches.length; index += 1) {
      remainder = this.allocateDifferenceToBatch(database, remainder, batches[index]);
    }

    // If there is a positive remainder, i.e. more to allocate, add more batches.
    if (remainder > 0) {
      // Use only batches that have some stock on hand (only ones which can be issued
      // from, and also most likely batches to have found more of in stocktake).
      // Sorted shortest to longest expiry date, so that customer invoices issue
      // following a FEFO policy.
      const batchesWithStock = this.item.batchesWithStock.sorted('expiryDate');

      // If there are no batches with stock, start with that which was most likely
      // to be recently in stock, i.e. with the longest expiry date.
      const batchesToUse =
        batchesWithStock.length > 0
          ? batchesWithStock
          : this.item.batches.sorted('expiryDate', true);

      // Get only those batches which are not already in the transaction.
      // TODO: this may actually slow things if most batches not already in transaction
      //       item or all batches already in.
      const itemBatchesToAdd = complement(
        batchesToUse,
        this.batches.map(transactionBatch => ({
          id: transactionBatch.itemBatchId,
        })),
        batch => batch.id
      );

      // Go through item batches, adding transaction batches and allocating remainder
      // until no remainder left.
      for (let index = 0; index < itemBatchesToAdd.length && remainder !== 0; index += 1) {
        // Create the new transaction batch and attach it to this transaction item.
        const newBatch = createRecord(
          database,
          'TransactionBatch',
          this,
          itemBatchesToAdd[index],
          this.transaction.isIncoming
        );
        // Apply as much of the remainder to it as possible.
        remainder = this.allocateDifferenceToBatch(database, remainder, newBatch);
      }
    }

    if (remainder > 0) {
      // Something went wrong...
      throw new Error(`Failed to allocate ${remainder} of ${difference} to ${this.item.name}`);
    }
  }

  /**
   * Allocates as much as possible of the quantity passed in to the given batch.
   *
   * @param   {Realm}    database
   * @param   {number}   difference  The difference in quantity to try to allocate.
   * @param   {object}   batch       The transaction batch to apply the quantity to.
   * @return  {number}               The remainder that could not be applied.
   */
  // eslint-disable-next-line class-methods-use-this
  allocateDifferenceToBatch(database, difference, batch) {
    const batchAddQuantity = batch.getAmountToAllocate(difference);
    batch.setTotalQuantity(database, batch.totalQuantity + batchAddQuantity);
    database.save('TransactionBatch', batch);
    return difference - batchAddQuantity;
  }

  /**
   * Delete any batches from this transaction that do not contribute to the total.
   *
   * E.g. if the quantity being issued in a customer invoice is reduced, do not keep
   * a batch that is no longer being issued in the transaction.
   *
   * @param  {Realm}  database
   */
  pruneEmptyBatches(database) {
    const batchesToDelete = [];
    this.batches.forEach(batch => {
      if (batch.totalQuantity === 0 && batch.totalQuantitySent === 0) {
        batchesToDelete.push(batch);
      }
    });
    database.delete('TransactionBatch', batchesToDelete);
  }

  /**
   * Sets the item direction to be the same for all underlying
   * TransactionBatches.
   */
  setItemDirection = (database, newDirection) => {
    database.write(() => {
      this.note = newDirection;
      this.batches.forEach(batch => {
        batch.note = newDirection;
        database.save('TransactionBatch', batch);
      });
    });
  };
}

TransactionItem.schema = {
  name: 'TransactionItem',
  primaryKey: 'id',
  properties: {
    id: 'string',
    item: 'Item',
    transaction: 'Transaction',
    note: { type: 'string', optional: true },
    batches: { type: 'list', objectType: 'TransactionBatch' },
  },
};

export default TransactionItem;
<commit_msg>Add TransactionItem doses methods<commit_after>import Realm from 'realm';
import { complement } from 'set-manipulator';

import { createRecord, getTotal } from '../utilities';

/**
 * A transaction item.
 *
 * @property  {string}                   id
 * @property  {Item}                     item
 * @property  {Transaction}              transaction
 * @property  {List.<TransactionBatch>}  batches
 */
export class TransactionItem extends Realm.Object {
  /**
   * Delete transaction item associated with unfinalised transaction.
   */
  destructor(database) {
    if (this.transaction.isFinalised) {
      throw new Error('Cannot delete an item from a finalised transaction');
    }
    database.delete('TransactionBatch', this.batches);
  }

  get hasValidDoses() {
    return this.batches.every(({ hasValidDoses }) => hasValidDoses);
  }

  /**
   * Get id of item associated with this transaction item.
   *
   * @return  {string}
   */
  get itemId() {
    return this.item ? this.item.id : '';
  }

  /**
   * Get name of item associated with this transaction item.
   *
   * @return  {string}
   */
  get itemName() {
    return this.item ? this.item.name : '';
  }

  /**
   * Get code of item associated with this transaction item.
   *
   * @return  {string}
   */
  get itemCode() {
    return this.item ? this.item.code : '';
  }

  /**
   * Get total quantity of batches associated with this transaction item.
   *
   * @return  {number}
   */
  get totalQuantity() {
    return getTotal(this.batches, 'totalQuantity');
  }

  /**
   * Get total quantity of batches associated with this transaction item which have been sent.
   *
   * @return  {number}
   */
  get totalQuantitySent() {
    return getTotal(this.batches, 'totalQuantitySent');
  }

  /**
   * Get total price of batches associated with this transaction item.
   *
   * @return  {number}
   */
  get totalPrice() {
    return getTotal(this.batches, 'totalPrice');
  }

  /**
   * Get total number of batches associated with this transaction item.
   *
   * @return  {number}
   */
  get numberOfBatches() {
    return this.batches.length;
  }

  /**
   * Get available quantity of items.
   *
   * For customer invoices, get how much can be issued in total, accounting for the fact that any
   * issued in a confirmed customer invoice has already been taken off the total.
   *
   * @return  {number}
   */
  get availableQuantity() {
    if (
      this.transaction.isOutgoing &&
      (this.transaction.isConfirmed || this.transaction.isFinalised)
    ) {
      return this.item.totalQuantity + this.totalQuantity;
    }
    return this.item.totalQuantity;
  }

  /**
   * Get the batch attached to this transaction item with the given item batch id.
   *
   * @param   {string}            itemId
   * @return  {TransactionBatch}
   */
  getBatch(itemBatchId) {
    return this.batches.find(transactionBatch => transactionBatch.itemBatchId === itemBatchId);
  }

  addBatch(transactionBatch) {
    this.batches.push(transactionBatch);
  }

  /**
   * Sets the quantity for the current item by applying the difference to the
   * shortest expiry batches possible.
   *
   * N.B. for customer invoices, will create and delete transaction batches as appropriate.
   * N.B.  supplier invoices do not take effect on the rest of the stock until they
   * are finalised, whereas customer invoices immediately influence stock levels.
   *
   * @param  {Realm}   database
   * @param  {double}  quantity
   */
  setTotalQuantity(database, quantity) {
    if (this.transaction.isFinalised) {
      throw new Error('Cannot set quantity of an item in a finalised transaction');
    }
    let cappedQuantity = quantity;
    if (this.transaction.isOutgoing) {
      cappedQuantity = Math.min(quantity, this.availableQuantity);
    }
    if (quantity < 0) {
      throw new Error('Cannot set a negative quantity on a transaction item');
    }

    const difference = cappedQuantity - this.totalQuantity; // Positive if new quantity is greater.

    // Apply the difference to make the new quantity.
    this.allocateDifferenceToBatches(database, difference);

    // See if any batches can be pruned, i.e. have a quantity of zero for this invoice.
    this.pruneEmptyBatches(database);
  }

  /**
   * Applies the given difference in quantity to the appropriate batches.
   *
   * If the difference is an increase, it will apply to the shortest expiry batches possible.
   * If a reduction, it will apply to the longest batches possible. In this way it is FEFO for
   * customer invoices, and pessimistic with changes to supplier invoices (assumes more of the
   * shortest batch or less of the longest batch). This has the side effect of also being FEFO
   * for supplier credits made from stocktake inventory adjustments, which is optimistic, but
   * not problematic. Null expiries are treated as absolute shortest, which means they will be
   * issued first.
   *
   * @param {Realm}   database
   * @param {number}  difference  The difference in quantity to set across all batches.
   *                              Positive if greater new quantity, negative if lesser.
   */
  allocateDifferenceToBatches(database, difference) {
    // Sort batches from shortest to longest if increasing, else longest to shortest.
    const batches = this.batches.sorted('expiryDate', difference < 0);

    // First apply as much of the quantity as possible to existing batches.
    let remainder = difference;
    for (let index = 0; remainder !== 0 && index < batches.length; index += 1) {
      remainder = this.allocateDifferenceToBatch(database, remainder, batches[index]);
    }

    // If there is a positive remainder, i.e. more to allocate, add more batches.
    if (remainder > 0) {
      // Use only batches that have some stock on hand (only ones which can be issued
      // from, and also most likely batches to have found more of in stocktake).
      // Sorted shortest to longest expiry date, so that customer invoices issue
      // following a FEFO policy.
      const batchesWithStock = this.item.batchesWithStock.sorted('expiryDate');

      // If there are no batches with stock, start with that which was most likely
      // to be recently in stock, i.e. with the longest expiry date.
      const batchesToUse =
        batchesWithStock.length > 0
          ? batchesWithStock
          : this.item.batches.sorted('expiryDate', true);

      // Get only those batches which are not already in the transaction.
      // TODO: this may actually slow things if most batches not already in transaction
      //       item or all batches already in.
      const itemBatchesToAdd = complement(
        batchesToUse,
        this.batches.map(transactionBatch => ({
          id: transactionBatch.itemBatchId,
        })),
        batch => batch.id
      );

      // Go through item batches, adding transaction batches and allocating remainder
      // until no remainder left.
      for (let index = 0; index < itemBatchesToAdd.length && remainder !== 0; index += 1) {
        // Create the new transaction batch and attach it to this transaction item.
        const newBatch = createRecord(
          database,
          'TransactionBatch',
          this,
          itemBatchesToAdd[index],
          this.transaction.isIncoming
        );
        // Apply as much of the remainder to it as possible.
        remainder = this.allocateDifferenceToBatch(database, remainder, newBatch);
      }
    }

    if (remainder > 0) {
      // Something went wrong...
      throw new Error(`Failed to allocate ${remainder} of ${difference} to ${this.item.name}`);
    }
  }

  /**
   * Allocates as much as possible of the quantity passed in to the given batch.
   *
   * @param   {Realm}    database
   * @param   {number}   difference  The difference in quantity to try to allocate.
   * @param   {object}   batch       The transaction batch to apply the quantity to.
   * @return  {number}               The remainder that could not be applied.
   */
  // eslint-disable-next-line class-methods-use-this
  allocateDifferenceToBatch(database, difference, batch) {
    const batchAddQuantity = batch.getAmountToAllocate(difference);
    batch.setTotalQuantity(database, batch.totalQuantity + batchAddQuantity);
    database.save('TransactionBatch', batch);
    return difference - batchAddQuantity;
  }

  /**
   * Delete any batches from this transaction that do not contribute to the total.
   *
   * E.g. if the quantity being issued in a customer invoice is reduced, do not keep
   * a batch that is no longer being issued in the transaction.
   *
   * @param  {Realm}  database
   */
  pruneEmptyBatches(database) {
    const batchesToDelete = [];
    this.batches.forEach(batch => {
      if (batch.totalQuantity === 0 && batch.totalQuantitySent === 0) {
        batchesToDelete.push(batch);
      }
    });
    database.delete('TransactionBatch', batchesToDelete);
  }

  /**
   * Sets the item direction to be the same for all underlying
   * TransactionBatches.
   */
  setItemDirection = (database, newDirection) => {
    database.write(() => {
      this.note = newDirection;
      this.batches.forEach(batch => {
        batch.note = newDirection;
        database.save('TransactionBatch', batch);
      });
    });
  };

  /**
   * Sets the doses for all underlying transaction batches. Rather than applying
   * all doses in FEFO, apply an even distribution of doses over the transaction
   * batches.
   * @param {Number} value The number of doses to set for this item
   */
  setDoses(database, value) {
    const dosesToSet = Math.min(value, this.totalQuantity * this.dosesPerVial);
    const dosesToAssignToEachBatch = dosesToSet / this.totalQuantity;

    this.resetAllDoses(database);
    this.batches.sorted('expiryDate', false).forEach(batch => {
      const { totalQuantity: thisBatchesQuantity } = batch;
      batch.setDoses(database, Math.floor(dosesToAssignToEachBatch * thisBatchesQuantity));
    });
  }

  get dosesPerVial() {
    return this.isVaccine ? this.item?.doses ?? 0 : 0;
  }

  get doses() {
    return this.batches.sum('doses');
  }

  /**
   * Sets the doses for this TransactionItem to 0.
   */
  resetAllDoses(database) {
    const { batches } = this;
    batches.forEach(batch => {
      batch.doses = 0;

      database.save('TransactionBatch', batch);
    });
  }
}

TransactionItem.schema = {
  name: 'TransactionItem',
  primaryKey: 'id',
  properties: {
    id: 'string',
    item: 'Item',
    transaction: 'Transaction',
    note: { type: 'string', optional: true },
    batches: { type: 'list', objectType: 'TransactionBatch' },
  },
};

export default TransactionItem;
<|endoftext|>


<commit_before>/** map initialisation JS file **/

var initialLoc;
var browserSupportFlag = new Boolean();
var EventID = false;  // used as a flag for the boundary changes

var airportList = new Array();
var airportsLoaded = {};
var flightsLoaded = {};
var flightList = new Array();
var flightPath = null;

function toRad (degrees) {
  radians = (2 * Math.PI * degrees)/360;
  return radians;

}

function toDeg(radians) {
   degrees = 360 * radians/(2 * Math.PI);
   return degrees;
}

function initialize() {
    // this function initialises the map to the starting position and zoom
    // to the div in the page.

    // these are the inline functions

    function noGeoHandler() {
      // this function deals with if the user either does't have or
      // doesn't allow the geolocation to fire.
      // no geolocation data so just go world view

      browserSupportFlag = false;
      var worldView = new google.maps.LatLng(0,150);
      map.setZoom(2);
      map.setCenter(worldView);
    }

    function boundaryChange() {
        // this function deals with a boundary change and will do things based
        // on that event

        //console.log("boundary_change");
       // update the data area with the boundary details:
       var bounds = map.getBounds();
       var sw = bounds.getSouthWest();
       var ne = bounds.getNorthEast()

       // hit the ajax call for the airports and we'll retrieve them:
       var airporturl = '/api/airport/list/' + sw.lat() + '/' + sw.lng() +
                                          '/' + ne.lat() + '/' + ne.lng() + "/";

        var flighturl = '/api/flight/list/' + sw.lat() + '/' + sw.lng() +
                                          '/' + ne.lat() + '/' + ne.lng() + "/";

        $("#map_data").text(flighturl);

       $.getJSON(airporturl, null, DisplayAirports);
       $.getJSON(flighturl, null, DisplayFlights);

        CleanupBounding();

    }

    function DisplayAirports(data) {
      // this function plots the airports on the map.

       for (i=0; i< data.length; i++) {
         item = data[i];

         if (! airportsLoaded[item.pk]) {

           if (item.fields["iata_code"] != null) {
              lat = item.fields["latitude"];
              lng = item.fields["longitude"];
              n = item.fields["name"];

              var marker = new google.maps.Marker({
                  position: new google.maps.LatLng(lat, lng),
                  map: map,
                  title:n,
                  icon: airportimage
              });
           }
           airportsLoaded[item.pk] = marker;
        }

       }

    }

    function DisplayFlights(data) {
      // this function displays the flights on the map.

      for (i=0; i< data.length; i++){
        item = data[i];

        if (! flightsLoaded[item.id]) {

          dept = new google.maps.LatLng(item.airport_from.latitude, item.airport_from.longitude);
          arr = new google.maps.LatLng(item.airport_to.latitude, item.airport_to.longitude);
          flightCoords = [dept, arr];

          flightPath = new google.maps.Polyline({
            path: flightCoords,
            geodesic: true,
            strokeColor: "#b10000",
            strokeOpacity: 0.2,
            strokeWeight: 3
          });

          flightPath.setMap(map);

          midpoint = dept.midpointLocation(arr, distance(dept, arr) * Math.random());

          var marker = new google.maps.Marker({
                      position: midpoint.LatLng,
                      map: map,
                      icon: planeimage
                  });

          var infoMarker = new RichMarker({
            position: midpoint.LatLng,
            map: map,
            anchor: 4,
            flat: true,
            content: GetHTMLForFlightTip(item)

          });

          flightsLoaded[item.id] = true;

        }
      }
    }

    function DisplayFlightsOld(data) {
      // this function plots the flights on the map

      // this is a demo to get it working for the Mel -> BNE flight.

      mel = new google.maps.LatLng(-37.67333333333333, 144.84333333333333);
      lax = new google.maps.LatLng(33.942499999999995, -118.40805555555556);

      var flightCoords = [
        // mel then syd
        mel, lax
      ];

      if (! flightPath) {

          flightPath = new google.maps.Polyline({
            path: flightCoords,
            geodesic: true,
            strokeColor: "#b10000",
            strokeOpacity: 0.2,
            strokeWeight: 3
          });

          flightPath.setMap(map);

          midpoint = mel.midpointLocation(lax, distance(mel, lax) * Math.random());

          var marker = new google.maps.Marker({
                      position: midpoint.LatLng,
                      map: map,
                      icon: planeimage
                  });

          //alert("info");
          var infoMarker = new RichMarker({
            position: midpoint.LatLng,
            map: map,
            anchor: 4,
            flat: true,
            content: '

This is an image
' +
                    '
@ajfisher Mel - LAX. 8*

'

          });
      }

    }

    function distance(point1, point2) {
          lat1 = point1.lat();
          lat2 = point2.lat();
          lon1 = point1.lng();
          lon2 = point2.lng();
	        var R = 6371000; // km (change this constant to get miles)
	        var dLat = (lat2-lat1) * Math.PI / 180;
	        var dLon = (lon2-lon1) * Math.PI / 180;
	        var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
	            Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
	            Math.sin(dLon/2) * Math.sin(dLon/2);
	        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
	        var d = R * c;
	        return d;
    }

    google.maps.LatLng.prototype.midpointLocation = function(point, distance) {
       var lat1 = toRad(this.lat());
       var lon1 = toRad(this.lng());
       var lat2 = toRad(point.lat());
       var lon2 = toRad(point.lng());
       var dLon = (toRad(point.lng()) - toRad(this.lng()));

       // Find the bearing from this point to the next.
       var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
                             Math.cos(lat1) * Math.sin(lat2) -
                             Math.sin(lat1) * Math.cos(lat2) *
                             Math.cos(dLon));

       var angDist = distance / 6371000;  // Earth's radius.

       // Calculate the destination point, given the source and bearing.
       lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) +
                        Math.cos(lat1) * Math.sin(angDist) *
                        Math.cos(brng));

       lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
                                Math.cos(lat1),
                                Math.cos(angDist) - Math.sin(lat1) *
                                Math.sin(lat2));

       if (isNaN(lat2) || isNaN(lon2)) return null;

        midpointObject  = {};
        midpointObject.LatLng = new google.maps.LatLng(toDeg(lat2), toDeg(lon2));
        midpointObject.bearing = toDeg(brng);

       return midpointObject;
    }

    function CleanupBounding() {
      // this function removes all of the items that are outside of the bounding
      // area of the map.

      bounds = map.getBounds();

      for (k in airportsLoaded) {

        if (! bounds.contains(airportsLoaded[k].getPosition())) {
          // remove the point off the map
          airportsLoaded[k].setMap(null);

          // remove the point from the array
          delete airportsLoaded[k]; // = null
        }
      }

      /**allist=0;
       for (k in airportsLoaded){
        allist++;
      }**/
      //$("#map_data").text("Airports: " + allist + " // ");

    }

    // THIS IS WHERE WE START THE ACTUAL INIT OF THE MAP ETC

    var airportimage = new google.maps.MarkerImage(
      "/site_media/img/airport.png",
      new google.maps.Size(24, 24),
      new google.maps.Point(0,0),
      new google.maps.Point(12,12) );
    var planeimage = new google.maps.MarkerImage(
      "/site_media/img/plane.png",
      new google.maps.Size(20, 21),
      new google.maps.Point(0, 0),
      new google.maps.Point(10, 11) );

    var mapOptions = {
        zoom: 4,
        mapTypeControl: false,
        mapTypeId: google.maps.MapTypeId.TERRAIN
    }

    var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

    // Try W3C Geolocation (Preferred)
    if(navigator.geolocation) {
        browserSupportFlag = true;
        // use the geo log and depending and if the user allows the service
        // to work and it returns properly or they choose not to or it fails
        // for whatever reason call one function or the other to set pass or
        // fail.
        navigator.geolocation.getCurrentPosition(
            function(position) {
                initialLoc = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
                map.setCenter(initialLoc);
            },
            function() {
                noGeoHandler();
            });
    } else {
        // if geo log W3C stylee doesn't work then we're not bothering with
        // other styles for the moment. GL W3C has enough coverage.
        noGeoHandler();

    }

    // now we set up event handlers to deal with the changes
    google.maps.event.addListener(map, 'bounds_changed',
      function() {
        if (EventID) {
          clearTimeout(EventID);
          //console.log("cleared");
        }
        EventID = setTimeout(boundaryChange, 1000);
      }
    );

    // add in our additional library for the rich markers
    loadRichMarkerScript();

}

function loadGMapScript() {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "http://maps.google.com/maps/api/js?sensor=false&callback=initialize";
    document.body.appendChild(script);

}

function loadRichMarkerScript() {
    // add the other
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "/site_media/js/richmarker-compiled.js";
    document.body.appendChild(script);
}

<commit_msg>changed boundary api calls<commit_after>/** map initialisation JS file **/

var initialLoc;
var browserSupportFlag = new Boolean();
var EventID = false;  // used as a flag for the boundary changes

var airportList = new Array();
var airportsLoaded = {};
var flightsLoaded = {};
var flightList = new Array();
var flightPath = null;

function toRad (degrees) {
  radians = (2 * Math.PI * degrees)/360;
  return radians;

}

function toDeg(radians) {
   degrees = 360 * radians/(2 * Math.PI);
   return degrees;
}

function initialize() {
    // this function initialises the map to the starting position and zoom
    // to the div in the page.

    // these are the inline functions

    function noGeoHandler() {
      // this function deals with if the user either does't have or
      // doesn't allow the geolocation to fire.
      // no geolocation data so just go world view

      browserSupportFlag = false;
      var worldView = new google.maps.LatLng(0,150);
      map.setZoom(2);
      map.setCenter(worldView);
    }

    function boundaryChange() {
        // this function deals with a boundary change and will do things based
        // on that event

        //console.log("boundary_change");
       // update the data area with the boundary details:
       var bounds = map.getBounds();
       var sw = bounds.getSouthWest();
       var ne = bounds.getNorthEast()

       // hit the ajax call for the airports and we'll retrieve them:
       var airporturl = '/api/airport/boundary/' + sw.lat() + '/' + sw.lng() +
                                          '/' + ne.lat() + '/' + ne.lng() + "/";

        var flighturl = '/api/flight/boundary/' + sw.lat() + '/' + sw.lng() +
                                          '/' + ne.lat() + '/' + ne.lng() + "/";

        $("#map_data").text(flighturl);

       $.getJSON(airporturl, null, DisplayAirports);
       $.getJSON(flighturl, null, DisplayFlights);

        CleanupBounding();

    }

    function DisplayAirports(data) {
      // this function plots the airports on the map.

       for (i=0; i< data.length; i++) {
         item = data[i];

         if (! airportsLoaded[item.pk]) {

           if (item.fields["iata_code"] != null) {
              lat = item.fields["latitude"];
              lng = item.fields["longitude"];
              n = item.fields["name"];

              var marker = new google.maps.Marker({
                  position: new google.maps.LatLng(lat, lng),
                  map: map,
                  title:n,
                  icon: airportimage
              });
           }
           airportsLoaded[item.pk] = marker;
        }

       }

    }

    function DisplayFlights(data) {
      // this function displays the flights on the map.

      for (i=0; i< data.length; i++){
        item = data[i];

        if (! flightsLoaded[item.id]) {

          dept = new google.maps.LatLng(item.airport_from.latitude, item.airport_from.longitude);
          arr = new google.maps.LatLng(item.airport_to.latitude, item.airport_to.longitude);
          flightCoords = [dept, arr];

          flightPath = new google.maps.Polyline({
            path: flightCoords,
            geodesic: true,
            strokeColor: "#b10000",
            strokeOpacity: 0.2,
            strokeWeight: 3
          });

          flightPath.setMap(map);

          midpoint = dept.midpointLocation(arr, distance(dept, arr) * Math.random());

          var marker = new google.maps.Marker({
                      position: midpoint.LatLng,
                      map: map,
                      icon: planeimage
                  });

          var infoMarker = new RichMarker({
            position: midpoint.LatLng,
            map: map,
            anchor: 4,
            flat: true,
            content: GetHTMLForFlightTip(item)

          });

          flightsLoaded[item.id] = true;

        }
      }
    }

    function DisplayFlightsOld(data) {
      // this function plots the flights on the map

      // this is a demo to get it working for the Mel -> BNE flight.

      mel = new google.maps.LatLng(-37.67333333333333, 144.84333333333333);
      lax = new google.maps.LatLng(33.942499999999995, -118.40805555555556);

      var flightCoords = [
        // mel then syd
        mel, lax
      ];

      if (! flightPath) {

          flightPath = new google.maps.Polyline({
            path: flightCoords,
            geodesic: true,
            strokeColor: "#b10000",
            strokeOpacity: 0.2,
            strokeWeight: 3
          });

          flightPath.setMap(map);

          midpoint = mel.midpointLocation(lax, distance(mel, lax) * Math.random());

          var marker = new google.maps.Marker({
                      position: midpoint.LatLng,
                      map: map,
                      icon: planeimage
                  });

          //alert("info");
          var infoMarker = new RichMarker({
            position: midpoint.LatLng,
            map: map,
            anchor: 4,
            flat: true,
            content: '

This is an image
' +
                    '
@ajfisher Mel - LAX. 8*

'

          });
      }

    }

    function distance(point1, point2) {
          lat1 = point1.lat();
          lat2 = point2.lat();
          lon1 = point1.lng();
          lon2 = point2.lng();
	        var R = 6371000; // km (change this constant to get miles)
	        var dLat = (lat2-lat1) * Math.PI / 180;
	        var dLon = (lon2-lon1) * Math.PI / 180;
	        var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
	            Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
	            Math.sin(dLon/2) * Math.sin(dLon/2);
	        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
	        var d = R * c;
	        return d;
    }

    google.maps.LatLng.prototype.midpointLocation = function(point, distance) {
       var lat1 = toRad(this.lat());
       var lon1 = toRad(this.lng());
       var lat2 = toRad(point.lat());
       var lon2 = toRad(point.lng());
       var dLon = (toRad(point.lng()) - toRad(this.lng()));

       // Find the bearing from this point to the next.
       var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
                             Math.cos(lat1) * Math.sin(lat2) -
                             Math.sin(lat1) * Math.cos(lat2) *
                             Math.cos(dLon));

       var angDist = distance / 6371000;  // Earth's radius.

       // Calculate the destination point, given the source and bearing.
       lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) +
                        Math.cos(lat1) * Math.sin(angDist) *
                        Math.cos(brng));

       lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
                                Math.cos(lat1),
                                Math.cos(angDist) - Math.sin(lat1) *
                                Math.sin(lat2));

       if (isNaN(lat2) || isNaN(lon2)) return null;

        midpointObject  = {};
        midpointObject.LatLng = new google.maps.LatLng(toDeg(lat2), toDeg(lon2));
        midpointObject.bearing = toDeg(brng);

       return midpointObject;
    }

    function CleanupBounding() {
      // this function removes all of the items that are outside of the bounding
      // area of the map.

      bounds = map.getBounds();

      for (k in airportsLoaded) {

        if (! bounds.contains(airportsLoaded[k].getPosition())) {
          // remove the point off the map
          airportsLoaded[k].setMap(null);

          // remove the point from the array
          delete airportsLoaded[k]; // = null
        }
      }

      /**allist=0;
       for (k in airportsLoaded){
        allist++;
      }**/
      //$("#map_data").text("Airports: " + allist + " // ");

    }

    // THIS IS WHERE WE START THE ACTUAL INIT OF THE MAP ETC

    var airportimage = new google.maps.MarkerImage(
      "/site_media/img/airport.png",
      new google.maps.Size(24, 24),
      new google.maps.Point(0,0),
      new google.maps.Point(12,12) );
    var planeimage = new google.maps.MarkerImage(
      "/site_media/img/plane.png",
      new google.maps.Size(20, 21),
      new google.maps.Point(0, 0),
      new google.maps.Point(10, 11) );

    var mapOptions = {
        zoom: 4,
        mapTypeControl: false,
        mapTypeId: google.maps.MapTypeId.TERRAIN
    }

    var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

    // Try W3C Geolocation (Preferred)
    if(navigator.geolocation) {
        browserSupportFlag = true;
        // use the geo log and depending and if the user allows the service
        // to work and it returns properly or they choose not to or it fails
        // for whatever reason call one function or the other to set pass or
        // fail.
        navigator.geolocation.getCurrentPosition(
            function(position) {
                initialLoc = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
                map.setCenter(initialLoc);
            },
            function() {
                noGeoHandler();
            });
    } else {
        // if geo log W3C stylee doesn't work then we're not bothering with
        // other styles for the moment. GL W3C has enough coverage.
        noGeoHandler();

    }

    // now we set up event handlers to deal with the changes
    google.maps.event.addListener(map, 'bounds_changed',
      function() {
        if (EventID) {
          clearTimeout(EventID);
          //console.log("cleared");
        }
        EventID = setTimeout(boundaryChange, 1000);
      }
    );

    // add in our additional library for the rich markers
    loadRichMarkerScript();

}

function loadGMapScript() {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "http://maps.google.com/maps/api/js?sensor=false&callback=initialize";
    document.body.appendChild(script);

}

function loadRichMarkerScript() {
    // add the other
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "/site_media/js/richmarker-compiled.js";
    document.body.appendChild(script);
}

<|endoftext|>


<commit_before>'use strict';

var stringToNum = require( './handle-string-input.js' );

/**
 * Handles URL questy string to turn key-value pairs into an object.
 * @param  {string} queryString - The query string of a url (location.search)
 * @returns {object} - An object containing key-value pairs from the query
 */
function queryHandler( queryString ) {
  var valuePairs = {};
  var parameters = {};
  var numericKeys = [
    'iped', 'pid', 'oid', 'tuit', 'hous', 'book', 'tran', 'othr',
    'pelg', 'schg', 'stag', 'othg', 'mta', 'gib', 'fam', 'wkst', 'parl',
    'perl', 'subl', 'unsl', 'ppl', 'gpl', 'prvl', 'prvi', 'insl', 'insi', 'sav'
  ];
  var keyMaps = {
    iped: 'collegeID',
    pid:  'programID',
    oid:  'offerID',
    tuit: 'tuitionFees',
    hous: 'roomBoard',
    book: 'books',
    tran: 'transportation',
    othr: 'otherExpenses',
    pelg: 'pell',
    schg: 'schoolGrants',
    stag: 'stateGrants',
    othg: 'otherScholarships',
    mta:  'militaryTuitionAssistance',
    gib:  'GIBill',
    fam:  'family',
    wkst: 'workstudy',
    parl: 'parentLoan',
    perl: 'perkins',
    subl: 'directSubsidized',
    unsl: 'directUnsubsidized',
    ppl:  'parentPlus',
    gpl:  'gradPlus',
    prvl: 'privateLoan',
    prvi: 'privateLoanRate',
    insl: 'institutionalLoan',
    insi: 'institutionalLoanRate'
  };

  /**
   * Helper function for checking that expected numeric values are indeed numeric
   * @param {string} key - The key to be checked
   * @param {string|number} value - The value of the key
   */
  function checkValue( key, value ) {
    var newValue = value;

    if ( numericKeys.indexOf( key ) !== -1 ) {
      newValue = stringToNum( value );
    }

    return newValue;
  }

  /**
   * Helper function which decodes key-value pairs from the URL
   * Has no parameters, but relies on the queryString passed to its parent function
   */
  function getPairs() {
    var pair;
    var regex = /[?&]?([^=]+)=([^&]*)/g;

    queryString.split( '+' ).join( ' ' );

    while ( pair = regex.exec( queryString ) ) {
      var key = decodeURIComponent( pair[1] );
      var value = decodeURIComponent( pair[2] );

      value = checkValue( key, value );
      parameters[key] = value || 0;
    }
  }

  /**
   * Helper function which maps the parameters object using the keyMaps
   */
  function remapKeys() {
    for ( var key in parameters ) {

      if ( keyMaps.hasOwnProperty( key ) ) {
        var newKey = keyMaps[key];
        valuePairs[newKey] = parameters[key];
      }
    }
  }

  getPairs();
  remapKeys();
  // family contributions = parent loan + parentPLUS loan
  valuePairs.family = valuePairs.parentLoan + valuePairs.parentPlus;
  // zero parentPlus so that student-debt-calc doesn't use it
  valuePairs.parentPlus = 0;
  return valuePairs;
}

module.exports = queryHandler;
<commit_msg>Quick JSDoc update<commit_after>'use strict';

var stringToNum = require( './handle-string-input.js' );

/**
 * Handles URL questy string to turn key-value pairs into an object.
 * @param  {string} queryString - The query string of a url (location.search)
 * @returns {object} - An object containing key-value pairs from the query
 */
function queryHandler( queryString ) {
  var valuePairs = {};
  var parameters = {};
  var numericKeys = [
    'iped', 'pid', 'oid', 'tuit', 'hous', 'book', 'tran', 'othr',
    'pelg', 'schg', 'stag', 'othg', 'mta', 'gib', 'fam', 'wkst', 'parl',
    'perl', 'subl', 'unsl', 'ppl', 'gpl', 'prvl', 'prvi', 'insl', 'insi', 'sav'
  ];
  var keyMaps = {
    iped: 'collegeID',
    pid:  'programID',
    oid:  'offerID',
    tuit: 'tuitionFees',
    hous: 'roomBoard',
    book: 'books',
    tran: 'transportation',
    othr: 'otherExpenses',
    pelg: 'pell',
    schg: 'schoolGrants',
    stag: 'stateGrants',
    othg: 'otherScholarships',
    mta:  'militaryTuitionAssistance',
    gib:  'GIBill',
    fam:  'family',
    wkst: 'workstudy',
    parl: 'parentLoan',
    perl: 'perkins',
    subl: 'directSubsidized',
    unsl: 'directUnsubsidized',
    ppl:  'parentPlus',
    gpl:  'gradPlus',
    prvl: 'privateLoan',
    prvi: 'privateLoanRate',
    insl: 'institutionalLoan',
    insi: 'institutionalLoanRate'
  };

  /**
   * Helper function for checking that expected numeric values are indeed numeric
   * @param {string} key - The key to be checked
   * @param {string|number} value - The value of the key
   * @returns {string|number} newValue - The corrected value of the key
   */
  function checkValue( key, value ) {
    var newValue = value;

    if ( numericKeys.indexOf( key ) !== -1 ) {
      newValue = stringToNum( value );
    }

    return newValue;
  }

  /**
   * Helper function which decodes key-value pairs from the URL
   * Has no parameters, but relies on the queryString passed to its parent function
   */
  function getPairs() {
    var pair;
    var regex = /[?&]?([^=]+)=([^&]*)/g;

    queryString.split( '+' ).join( ' ' );

    while ( pair = regex.exec( queryString ) ) {
      var key = decodeURIComponent( pair[1] );
      var value = decodeURIComponent( pair[2] );

      value = checkValue( key, value );
      parameters[key] = value || 0;
    }
  }

  /**
   * Helper function which maps the parameters object using the keyMaps
   */
  function remapKeys() {
    for ( var key in parameters ) {

      if ( keyMaps.hasOwnProperty( key ) ) {
        var newKey = keyMaps[key];
        valuePairs[newKey] = parameters[key];
      }
    }
  }

  getPairs();
  remapKeys();
  // family contributions = parent loan + parentPLUS loan
  valuePairs.family = valuePairs.parentLoan + valuePairs.parentPlus;
  // zero parentPlus so that student-debt-calc doesn't use it
  valuePairs.parentPlus = 0;
  return valuePairs;
}

module.exports = queryHandler;
<|endoftext|>


<commit_before>const fs = require('fs')
    , path = require('path')

const linkRe = /(?:\{([^\{]+)\})/g
    , termRe = /^:(.+):/
    , patternLineRe = /^\t([\.\*]+)$/
    , mainSectionDividerRe = /^(\-)+$/
    , periodRe = /\(p(\d+)\)/
    , emptyLineRe = /^\s*$/

const findSections = (dividerRe, keepDividerLine) => lines => {
  return lines
    .reduce((sections, line) => {
      if (dividerRe.test(line)) {
        const newSection = [ keepDividerLine ? [ line ] : [ ] ]
        return sections.concat(newSection)
      }
      last(sections).push(line)
      return sections
    }, [[]])
    .filter(nonEmptySection)
}

const findMainSections = findSections(mainSectionDividerRe)
    , findContentSections = findSections(termRe, true)
    , findSimpleSections = findSections(emptyLineRe)

module.exports.parse = lines => {
  const [ introLines, termLines, biblioLines ] = findMainSections(lines)
      , terms = findTerms(termLines)

  return {
    introduction: findSimpleSections(introLines)
  , terms: terms
  , patterns: terms.filter(isPattern)
  , bibliography: findSimpleSections(biblioLines)
  }
}

function findTerms(lines) {
  return findContentSections(lines)
    .map(parseTerm)
    .filter(({ term }) => !!term )
}

function parseTerm(lines) {
  return lines.reduce((term, line) => {
    addTerm(term, line)
    addPeriod(term, line)
    addDescription(term, line)
    addLinks(term, line)
    addPatternLine(term, line)
    return term
  }, {})
}

function addTerm(term, line) {
  const matches = termRe.exec(line)
  if (!matches) return
  term.term = matches[1]
}

function addPeriod(term, line) {
  const matches = periodRe.exec(line)
  if (!matches) return
  term.period = parseInt(matches[1])
}

function addDescription(term, line) {
  const isEmptyLine = emptyLineRe.test(line)
      , isPatternLine = patternLineRe.test(line)

  if (isEmptyLine || isPatternLine) return
  term.description = (term.description || '') + cleanDescriptionLine(line) + ' '
}

function cleanDescriptionLine(line) {
  return line
    .replace(/\{/g, '')
    .replace(/\}/g, '')
    .replace(periodRe, '')
    .replace(termRe, '')
    .replace(/  +/g, ' ')
    .replace(/^ /, '')
    .replace(/ $/, '')
}

function addLinks(term, line) {
  const links = findLinks(line)
  if (!links.length) return
  term.links = (term.links || []).concat(links)
}

function findLinks(line) {
  let matches
  const links = []
  while ((matches = linkRe.exec(line)) != null) links.push(matches[1])
  return links
}

function addPatternLine(term, line) {
  const matches = patternLineRe.exec(line)
  if (!matches) return
  term.pattern = (term.pattern || []).concat(toPatternLine(matches))
  term.width = term.pattern[0].length
  term.height = term.pattern.length
}

function toPatternLine(matches) {
  return [ matches[1].split('').map( toBinary ) ]
}

function toBinary(char) {
  return { '.': 0, '*': 1 }[char]
}

function last(array) {
  return array[array.length - 1]
}

function nonEmptySection(sectionLines) {
  return !!sectionLines.length
}

function isPattern(term) {
  return !!term.pattern
}
<commit_msg>Cleanup<commit_after>const fs = require('fs')
    , path = require('path')

const linkRe = /(?:\{([^\{]+)\})/g
    , termRe = /^:(.+):/
    , patternLineRe = /^\t([\.\*]+)$/
    , mainSectionDividerRe = /^(\-)+$/
    , periodRe = /\(p(\d+)\)/
    , emptyLineRe = /^\s*$/

const findSections = (dividerRe, keepDividerLine) => lines => {
  return lines
    .reduce((sections, line) => {
      if (dividerRe.test(line)) return sections.concat(newSection(line))
      last(sections).push(line)
      return sections
    }, [[ ]])
    .filter(nonEmptySection)

    function newSection(line) {
      return keepDividerLine ? [[ line ]] : [[ ]]
    }
}

const findMainSections = findSections(mainSectionDividerRe)
    , findContentSections = findSections(termRe, true)
    , findSimpleSections = findSections(emptyLineRe)

module.exports.parse = lines => {
  const [ introLines, termLines, biblioLines ] = findMainSections(lines)
      , terms = findTerms(termLines)

  return {
    terms: terms
  , patterns: terms.filter(isPattern)
  , introduction: findSimpleSections(introLines)
  , bibliography: findSimpleSections(biblioLines)
  }
}

function findTerms(lines) {
  return findContentSections(lines)
    .map(parseTerm)
    .filter(({ term }) => !!term )
}

function parseTerm(lines) {
  return lines.reduce((term, line) => {
    addTerm(term, line)
    addPeriod(term, line)
    addDescription(term, line)
    addLinks(term, line)
    addPatternLine(term, line)
    return term
  }, {})
}

function addTerm(term, line) {
  const matches = termRe.exec(line)
  if (!matches) return
  term.term = matches[1]
}

function addPeriod(term, line) {
  const matches = periodRe.exec(line)
  if (!matches) return
  term.period = parseInt(matches[1])
}

function addDescription(term, line) {
  const isEmptyLine = emptyLineRe.test(line)
      , isPatternLine = patternLineRe.test(line)
      , description = term.description || ''

  if (isEmptyLine || isPatternLine) return
  term.description = description + cleanDescriptionLine(line)
}

function cleanDescriptionLine(line) {
  return line
    .replace(/\{/g, '')
    .replace(/\}/g, '')
    .replace(periodRe, '')
    .replace(termRe, '')
    .replace(/  +/g, ' ')
    .replace(/^ /, '')
    .replace(/ $/, '')
    + ' '
}

function addLinks(term, line) {
  const links = findLinks(line)
  if (!links.length) return
  term.links = (term.links || []).concat(links)
}

function findLinks(line) {
  let matches
  const links = []
  while ((matches = linkRe.exec(line)) != null) links.push(matches[1])
  return links
}

function addPatternLine(term, line) {
  const matches = patternLineRe.exec(line)
  if (!matches) return
  term.pattern = (term.pattern || []).concat(toPatternLine(matches))
  term.width = term.pattern[0].length
  term.height = term.pattern.length
}

function toPatternLine(matches) {
  return [ matches[1].split('').map( toBinary ) ]
}

function toBinary(char) {
  return { '.': 0, '*': 1 }[char]
}

function last(array) {
  return array[array.length - 1]
}

function nonEmptySection(sectionLines) {
  return !!sectionLines.length
}

function isPattern(term) {
  return !!term.pattern
}
<|endoftext|>


<commit_before>var superagent = require('superagent');
var request = require('request');
var fs = require("fs");

function trigger(message, threadID, api) {
  console.log("here");
    api.sendTypingIndicator(threadID, function() {
    });
    superagent
      .get('https://www.reddit.com/r/spaceporn.json')
      .set('Accept', 'application/json')
      .end(function(err, res) {
      var index = Math.floor(Math.random() * 22);
      while(true) {
        var url = res.body['data']['children'][index]['data']['url'];
        if (url.indexOf("jpg") >= 0 || url.indexOf("png") >= 0) {
          break;
        } else {
          index = Math.floor(Math.random() * 22);
        }
      }
      var picStream = fs.createWriteStream('imgs/space/' + index + ".png");
      picStream.on('close', function() {
        console.log("here");
        var msg = {
                    body: res.body['data']['children'][index]['data']['title'],
                    attachment: fs.createReadStream('imgs/space/' + index + ".png")
                  }
        api.sendMessage(msg, threadID);
      });
      request(res.body['data']['children'][index]['data']['url']).pipe(picStream);
  });
}

module.exports = {
  trigger: trigger
}
<commit_msg>remove console.log<commit_after>var superagent = require('superagent');
var request = require('request');
var fs = require("fs");

function trigger(message, threadID, api) {
    api.sendTypingIndicator(threadID, function() {
    });
    superagent
      .get('https://www.reddit.com/r/spaceporn.json')
      .set('Accept', 'application/json')
      .end(function(err, res) {
      var index = Math.floor(Math.random() * 22);
      // Skip links that do not directly link to an image
      while(true) {
        var url = res.body['data']['children'][index]['data']['url'];
        if (url.indexOf("jpg") >= 0 || url.indexOf("png") >= 0) {
          break;
        } else {
          index = Math.floor(Math.random() * 22);
        }
      }
      var picStream = fs.createWriteStream('imgs/space/' + index + ".png");
      picStream.on('close', function() {
        var msg = {
                    body: res.body['data']['children'][index]['data']['title'],
                    attachment: fs.createReadStream('imgs/space/' + index + ".png")
                  }
        api.sendMessage(msg, threadID);
      });
      request(res.body['data']['children'][index]['data']['url']).pipe(picStream);
  });
}

module.exports = {
  trigger: trigger
}
<|endoftext|>


<commit_before>const fs = require('fs')
    , path = require('path')
    , mainSectionDividerRe = /^(\-)+$/
    , keyRe = /^:(.*):/
    , patternLineRe = /^\t([\.\*]+)$/

const findSections = dividerRe => lines => {
  return lines.reduce((sections, line) => {
    if (dividerRe.test(line)) return sections.concat([[ line ]])
    last(sections).push(line)
    return sections
  }, [[]])
}

const findMainSections = findSections(mainSectionDividerRe)
    , findContentSections = findSections(keyRe)

module.exports.parse = parse

function findTerms(lines) {
  const contentLines = findMainSections(lines)[1]
  return findContentSections(contentLines)
}

function parse(lines) {
  return lines.reduce((parsed, line, index) => {
    const matches = keyRe.exec(line)
    if (!matches) return parsed
    const name = matches[1]
        , pattern = findPattern(lines.slice(index + 1))
        , width = pattern[0] ? pattern[0].length : undefined
        , height = pattern.length ? pattern.length : undefined
    return parsed.concat({ name, pattern, width, height })
  }, [])
}

function findPattern(lines, pattern = []) {
  if (!lines.length) return pattern

  const [line, ...remainingLines] = lines
  const matches = patternLineRe.exec(line)

  if (!matches && pattern.length) return pattern
  if (!matches && !pattern.length) return findPattern(remainingLines, pattern)

  return findPattern(remainingLines, pattern.concat( toPatternLine(matches) ))
}

function toPatternLine(matches) {
  return [ matches[1].split('').map( toBinary ) ]
}

function toBinary(char) {
  return { '.': 0, '*': 1 }[char]
}

function last(array) {
  return array[array.length - 1]
}
<commit_msg>Cleanup<commit_after>const fs = require('fs')
    , path = require('path')
    , mainSectionDividerRe = /^(\-)+$/
    , keyRe = /^:(.*):/
    , patternLineRe = /^\t([\.\*]+)$/

const findSections = dividerRe => lines => {
  return lines.reduce((sections, line) => {
    if (dividerRe.test(line)) return sections.concat([[ line ]])
    last(sections).push(line)
    return sections
  }, [[]])
}

const findMainSections = findSections(mainSectionDividerRe)
    , findContentSections = findSections(keyRe)

module.exports.parse = parse

function findTerms(lines) {
  const contentLines = findMainSections(lines)[1]
  return findContentSections(contentLines)
}

function parse(lines) {
  return lines.reduce((parsed, line, index) => {
    const matches = keyRe.exec(line)
    if (!matches) return parsed
    const name = matches[1]
        , pattern = findPattern(lines.slice(index + 1))
        , width = pattern[0] ? pattern[0].length : undefined
        , height = pattern.length ? pattern.length : undefined
    return parsed.concat({ name, pattern, width, height })
  }, [])
}

function findPattern(lines, pattern = []) {
  if (!lines.length) return pattern

  const [line, ...remainingLines] = lines
  const matches = patternLineRe.exec(line)

  if (!matches && pattern.length) return pattern
  if (!matches && !pattern.length) return findPattern(remainingLines, pattern)

  return findPattern(remainingLines, pattern.concat( toPatternLine(matches) ))
}

function toPatternLine(matches) {
  return [ matches[1].split('').map( toBinary ) ]
}

function toBinary(char) {
  return { '.': 0, '*': 1 }[char]
}

function last(array) {
  return array[array.length - 1]
}
<|endoftext|>


<commit_before>(function () {
    'use strikt';

    var dropdown = function dropdown() {
        return {
            restrict: 'A',
            templateUrl: '/app/common/dropdown-directive.html',
            scope: {
                options: '=',
                selected: '='
            },
            link: function (scope) {

            }
        };
    };

    angular
        .module('showcaseSystem.directives')
        .directive('dropdown', [dropdown]);
}());<commit_msg>Fixed typo in dropdown-directive.js<commit_after>(function () {
    'use strict';

    var dropdown = function dropdown() {
        return {
            restrict: 'A',
            templateUrl: '/app/common/dropdown-directive.html',
            scope: {
                options: '=',
                selected: '='
            }
        };
    };

    angular
        .module('showcaseSystem.directives')
        .directive('dropdown', [dropdown]);
}());<|endoftext|>


<commit_before>var request = require('request');
var cheerio = require('cheerio');

module.exports = function (from, to, url) {
    if (url.length === 1) {
        url = url[0];
    }else{
        url = url[1];
    }
    var options = {
        url: url,
        headers: {
            'User-Agent': 'chrome32 on win8 Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36',
            'Cookie': 'over18=1'
        },
        timeout: 1500
    };
    request(options, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            $ = cheerio.load(body);
            var title =$('title').text();
            if (title !== undefined) {
                /*global oktw*/
                oktw.say(from, to, '[Title] ' + title);
            }
        }
    });
};

module.exports.info = {name:'title', example:'.title https://www.google.com/', command:'title', rawcommand:/https?:\/\/\S*/i};
<commit_msg>fix title<commit_after>var request = require('request');
var cheerio = require('cheerio');

module.exports = function (from, to, url) {
    if (url.length === 1) {
        url = url[0];
    }else{
        url = url[1];
    }
    var options = {
        url: url,
        headers: {
            'User-Agent': 'chrome32 on win8 Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36',
            'Cookie': 'over18=1'
        },
        timeout: 1500
    };
    request(options, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            $ = cheerio.load(body);
            var title =$('title').text();
            if (title != '') {
                /*global oktw*/
                oktw.say(from, to, '[Title] ' + title);
            }
        }
    });
};

module.exports.info = {name:'title', example:'.title https://www.google.com/', command:'title', rawcommand:/https?:\/\/\S*/i};
<|endoftext|>


<commit_before>var util = require('util')
var exec = require('child_process').exec;
var Q  = require('q');

module.exports = {

    convert: function(){

        var that        = this;
        var sources     = './exports/merge/%05d.jpg';
        var sources_big = './exports/merge_big/%05d.jpg';
        var destMP4     = './exports/video.mp4';
        var destMP4_big = './exports/video_big.mp4';
        var destOGG     = './exports/video.webm';
        var destOGG_big = './exports/video_big.webm';

        console.log('start video encoding'.cyan);
        /*
        that.doMP4(sources, destMP4).then(function(){
            return that.doOGG(sources, destOGG, "1M");
        }).then(function(){
            return that.doMP4(sources_big, destMP4_big);
        }).then(function(){
            return that.doOGG(sources_big, destOGG_big, "10M");
        }).done();
       */
        that.doOGG(sources_big, destOGG_big, "3900k");
    },

    doMP4: function(sources, dest){
        var defer = Q.defer();
        //compiled version
        exec("ffmpeg -r 10 -y -i "+sources+" -vcodec libx264 -preset slow -crf 24 -pix_fmt yuv420p "+dest+"", function(error, stdout, stderr){
            console.log('MP4 video encoded'.green+" "+dest);
            if (error !== null) {
                console.log('exec error: '.red + error);
                defer.reject();
            }

            defer.resolve();
        });

        return defer.promise;

    },

    doOGG: function(sources, dest, bitrate){
        var defer = Q.defer();
        //ubuntu version
        exec("ffmpeg -r 10 -y -i "+sources+" -qscale 15 -c:v libvpx -c:a libvorbis "+dest, function(error, stdout, stderr){
            console.log('webM video encoded'.green+" "+dest);
            if (error !== null) {
                console.log('exec error: '.red + error);
                defer.reject();
            }

            defer.resolve();
        });

        return defer.promise;

    }
};

//ubuntu version (installed wit apt-get)
//  /usr/bin/ffmpeg -r 10 -y  -i ./exports/merge/%05d.jpg -qscale 1 ./exports/video.mp4
//  /usr/bin/ffmpeg -r 10 -y  -i ./exports/merge/%05d.jpg -qscale 15 ./exports/video.ogg

//compiled version (https://trac.ffmpeg.org/wiki/UbuntuCompilationGuide)
// ~/bin/ffmpeg -r 10 -y -i ./exports/merge/%05d.jpg ./test.ogv
//~/bin/ffmpeg -r 10 -y -i ./exports/merge/%05d.jpg -vcodec libx264 -preset slow -crf 24 -pix_fmt yuv420p ./test.mp4
<commit_msg>Webm bitrate<commit_after>var util = require('util')
var exec = require('child_process').exec;
var Q  = require('q');

module.exports = {

    convert: function(){

        var that        = this;
        var sources     = './exports/merge/%05d.jpg';
        var sources_big = './exports/merge_big/%05d.jpg';
        var destMP4     = './exports/video.mp4';
        var destMP4_big = './exports/video_big.mp4';
        var destOGG     = './exports/video.webm';
        var destOGG_big = './exports/video_big.webm';

        console.log('start video encoding'.cyan);
        /*
        that.doMP4(sources, destMP4).then(function(){
            return that.doOGG(sources, destOGG, "1M");
        }).then(function(){
            return that.doMP4(sources_big, destMP4_big);
        }).then(function(){
            return that.doOGG(sources_big, destOGG_big, "10M");
        }).done();
       */
        that.doOGG(sources_big, destOGG_big, "10M");
    },

    doMP4: function(sources, dest){
        var defer = Q.defer();
        //compiled version
        exec("ffmpeg -r 10 -y -i "+sources+" -vcodec libx264 -preset slow -crf 24 -pix_fmt yuv420p "+dest+"", function(error, stdout, stderr){
            console.log('MP4 video encoded'.green+" "+dest);
            if (error !== null) {
                console.log('exec error: '.red + error);
                defer.reject();
            }

            defer.resolve();
        });

        return defer.promise;

    },

    doOGG: function(sources, dest, bitrate){
        var defer = Q.defer();
        //ubuntu version
        exec("ffmpeg -r 10 -y -i "+sources+" -c:v libvpx -b:v "+bitrate+" -qscale 15 -qmin 40 -qmax 63 -c:a libvorbis "+dest, function(error, stdout, stderr){
            console.log('webM video encoded'.green+" "+dest);
            if (error !== null) {
                console.log('exec error: '.red + error);
                defer.reject();
            }

            defer.resolve();
        });

        return defer.promise;

    }
};

//ubuntu version (installed wit apt-get)
//  /usr/bin/ffmpeg -r 10 -y  -i ./exports/merge/%05d.jpg -qscale 1 ./exports/video.mp4
//  /usr/bin/ffmpeg -r 10 -y  -i ./exports/merge/%05d.jpg -qscale 15 ./exports/video.ogg

//compiled version (https://trac.ffmpeg.org/wiki/UbuntuCompilationGuide)
// ~/bin/ffmpeg -r 10 -y -i ./exports/merge/%05d.jpg ./test.ogv
//~/bin/ffmpeg -r 10 -y -i ./exports/merge/%05d.jpg -vcodec libx264 -preset slow -crf 24 -pix_fmt yuv420p ./test.mp4
<|endoftext|>


<commit_before>
// @require ./NTA.Action.js
// @require ./NTA.Group.js
// @require core/svelto/svelto.js

(function ( $, _, Svelto, NTA ) {

  /* DEFAULTS */

  let defaults = {
    group: 'nta', // The cookie name that holds the actions, a namespace for related actions basically
    action: false, // The action name
    times: Infinity, // The times an action can be executed
    expiry: false, // When a single action will expire and will then get removed from its group
    fn: false, // The function to execute
    cookie: { // Values that will get passed to `Cookie` when appropriate
      end: Infinity,
      path: undefined,
      domain: undefined,
      secure: undefined
    }
  };

  /* N TIMES ACTION */

  $.nTimesAction = function ( options ) {

    /* OPTIONS */

    options = _.merge ( {}, $.nTimesAction.defaults, options );

    /* N TIMES ACTION */

    if ( options.action ) {

      let action = new NTA.Action ({ group: options.group, name: options.action, expiry: options.expiry, cookie: options.cookie }),
          actionTimes = action.get ();

      /* EXECUTE */

      if ( options.fn && actionTimes < options.times ) {

        let returnValue = options.fn ( options.group, options.action, actionTimes + 1 );

        /* INCREMENT */

        if ( returnValue !== false ) {

          action.set ( actionTimes + 1 );

        }

      }

      return action;

    } else if ( options.group ) {

      return new NTA.Group ({ name: options.group, cookie: options.cookie });

    }

  };

  /* BINDING */

  $.nTimesAction.defaults = defaults;

}( Svelto.$, Svelto._, Svelto, Svelto.NTA ));
<commit_msg>NTA: setting path to `/` by default<commit_after>
// @require ./NTA.Action.js
// @require ./NTA.Group.js
// @require core/svelto/svelto.js

(function ( $, _, Svelto, NTA ) {

  /* DEFAULTS */

  let defaults = {
    group: 'nta', // The cookie name that holds the actions, a namespace for related actions basically
    action: false, // The action name
    times: Infinity, // The times an action can be executed
    expiry: false, // When a single action will expire and will then get removed from its group
    fn: false, // The function to execute
    cookie: { // Values that will get passed to `Cookie` when appropriate
      end: Infinity,
      path: '/',
      domain: undefined,
      secure: undefined
    }
  };

  /* N TIMES ACTION */

  $.nTimesAction = function ( options ) {

    /* OPTIONS */

    options = _.merge ( {}, $.nTimesAction.defaults, options );

    /* N TIMES ACTION */

    if ( options.action ) {

      let action = new NTA.Action ({ group: options.group, name: options.action, expiry: options.expiry, cookie: options.cookie }),
          actionTimes = action.get ();

      /* EXECUTE */

      if ( options.fn && actionTimes < options.times ) {

        let returnValue = options.fn ( options.group, options.action, actionTimes + 1 );

        /* INCREMENT */

        if ( returnValue !== false ) {

          action.set ( actionTimes + 1 );

        }

      }

      return action;

    } else if ( options.group ) {

      return new NTA.Group ({ name: options.group, cookie: options.cookie });

    }

  };

  /* BINDING */

  $.nTimesAction.defaults = defaults;

}( Svelto.$, Svelto._, Svelto, Svelto.NTA ));
<|endoftext|>


<commit_before>function last(ar) {
	return ar[ar.length - 1];
}

function changePlaying(value) {
	playing = value;
	document.getElementById('playLink' + getNextPlayerIndex()).appendChild(document.getElementById('playLink'));
	for (var i = 0, field; field = fields[i]; i++) {
		if (field.bettable) {
			field.updateEarns();
		}
	}
}

function getNextPlayerIndex() {
	if (!players.length) {
		return 3;
	}
	var i = playing;
	do {
		i = (i + 1) % players.length;
	} while (!players[i]);
	return i;
}

/** @this {Place|Rail|Service} */
function offerBuying(player) {
	ask('buy ' + this.name + ' for ' + this.price + '?', player, buy.bind(this));
}

/** @this {Place|Rail|Service} */
function buy(player) {
	if (!player.tryPaying(this.price)) {
		return false;
	}
	changeOwner.call(this, player);
}

/** @this {Place|Rail|Service} */
function changeOwner(owner) {
	if (this.owner) {
		this.div.classList.remove('owner' + this.owner.index);
	}
	this.owner = owner;
	if (owner) {
		this.div.classList.add('owner' + owner.index);
		this.div.classList.add('owned');
		this.div.onclick = offerSelling.bind(this);
	} else {
		this.div.classList.remove('owned');
		this.div.onclick = undefined;
	}
	if (this.updateEarns) {
		this.updateEarns();
	}
}

/** @this {Place|Rail|Service} */
function offerSelling() {
	var input = '<input class=price type=number step=10 min=0 value=' + (this.price + (this.upgrades * this.upgradePrice || 0)) + '>';
	var options = [];
	if (this.owner.money < 0) {
		options.push('<option value=-1>bank');
	}
	for (var i = 0; i < 4; i++) {
		var player = players[i];
		if (player && player != this.owner) {
			options.push('<option value=' + i + '>' + escape(player.name));
		}
	}
	if (!options.length) {
		say('nobody to sell to.', this.owner);
		return;
	}
	// TODO: Disable selling if there are upgrades with the same color.
	ask('sell ' + this.name + ' for ' + input + ' to <select class=buyer size=' + options.length + '>' + options.join('') + '</select>?', this.owner, sell.bind(this));
	last(document.getElementsByClassName('price')).focus();
	if (this.owner.money < 0) {
		var element = last(document.getElementsByClassName('buyer'));
		element.onchange = buyerChange.bind(element, (this.price + (this.upgrades * this.upgradePrice / 2 || 0)));
	}
}

/** @this {HTMLSelectElement} */
function buyerChange(bankPrice) {
	var element = this.parentNode.querySelector('.price');
	if (element.disabled != (this.value == -1)) {
		element.disabled = (this.value == -1);
		if (this.value == -1) {
			element.lastValue = element.value;
			element.value = bankPrice;
		} else if (element.lastValue) {
			element.value = element.lastValue;
		}
	}
}

/** @this {Place|Rail|Service} */
function sell() {
	var price = +last(document.getElementsByClassName('price')).value;
	var buyerIndex = last(document.getElementsByClassName('buyer')).value;
	if (!price || price < 0) { // price might be NaN.
		say('input a valid price.', this.owner);
		return false;
	}
	if (!buyerIndex) {
		say('select a buyer.', this.owner);
		return false;
	}
	var buyer = players[buyerIndex];
	if (!buyer) {
		earn(price, this.owner);
	} else if (!buyer.tryPaying(price, this.owner)) {
		return false;
	}
	changeOwner.call(this, buyer);
}

function escape(s) {
	return s.replace(/&/g, '&').replace(/</g, '<');
}

function say(message, player) {
	var p = document.createElement('p');
	p.innerHTML = (player ? escape(player.name) + ', ' : '') + message;
	document.getElementById('message').appendChild(p);
	p.scrollIntoView();
}

function ask(message, player, callback) {
	var question = '' + message + '';
	if (!questions.length || last(questions).message != question) {
		say(question, player);
		var index = questions.length && questions[0].primary ? 1 : 0;
		questions[index] = {message: question, player: player, callback: callback};
		document.querySelector('.cancel').disabled = questions.length < 2;
	}
}

function position(i) {
	return {
		top: 10 + 66 * (i < 10 ? 10 - i : i < 20 ? 0 : i < 30 ? i - 20 : 10),
		left: 10 + 128 * (i < 10 ? 0 : i < 20 ? i - 10 : i < 30 ? 10 : 40 - i)
	};
}

for (var i = 0, field; field = fields[i]; i++) {
	field.index = i;
	var div = document.createElement('div');
	div.className = 'field';
	div.innerHTML = field.name + (field.price ? ' (' + field.price + ')' : '') + '
' + (field.getEarns ? field.getEarns() : field.earns || '') + '';
	div.style.borderTop = '10px solid ' + (field.color || 'silver');
	var pos = position(i);
	div.style.top = pos.top + 'px';
	div.style.left = pos.left + 'px';
	field.div = div;
	document.body.appendChild(div);
}

var players = [];
var playing = -1;
<commit_msg>Monopoly: Increase step of sell price<commit_after>function last(ar) {
	return ar[ar.length - 1];
}

function changePlaying(value) {
	playing = value;
	document.getElementById('playLink' + getNextPlayerIndex()).appendChild(document.getElementById('playLink'));
	for (var i = 0, field; field = fields[i]; i++) {
		if (field.bettable) {
			field.updateEarns();
		}
	}
}

function getNextPlayerIndex() {
	if (!players.length) {
		return 3;
	}
	var i = playing;
	do {
		i = (i + 1) % players.length;
	} while (!players[i]);
	return i;
}

/** @this {Place|Rail|Service} */
function offerBuying(player) {
	ask('buy ' + this.name + ' for ' + this.price + '?', player, buy.bind(this));
}

/** @this {Place|Rail|Service} */
function buy(player) {
	if (!player.tryPaying(this.price)) {
		return false;
	}
	changeOwner.call(this, player);
}

/** @this {Place|Rail|Service} */
function changeOwner(owner) {
	if (this.owner) {
		this.div.classList.remove('owner' + this.owner.index);
	}
	this.owner = owner;
	if (owner) {
		this.div.classList.add('owner' + owner.index);
		this.div.classList.add('owned');
		this.div.onclick = offerSelling.bind(this);
	} else {
		this.div.classList.remove('owned');
		this.div.onclick = undefined;
	}
	if (this.updateEarns) {
		this.updateEarns();
	}
}

/** @this {Place|Rail|Service} */
function offerSelling() {
	var input = '<input class=price type=number step=100 min=0 value=' + (this.price + (this.upgrades * this.upgradePrice || 0)) + '>';
	var options = [];
	if (this.owner.money < 0) {
		options.push('<option value=-1>bank');
	}
	for (var i = 0; i < 4; i++) {
		var player = players[i];
		if (player && player != this.owner) {
			options.push('<option value=' + i + '>' + escape(player.name));
		}
	}
	if (!options.length) {
		say('nobody to sell to.', this.owner);
		return;
	}
	// TODO: Disable selling if there are upgrades with the same color.
	ask('sell ' + this.name + ' for ' + input + ' to <select class=buyer size=' + options.length + '>' + options.join('') + '</select>?', this.owner, sell.bind(this));
	last(document.getElementsByClassName('price')).focus();
	if (this.owner.money < 0) {
		var element = last(document.getElementsByClassName('buyer'));
		element.onchange = buyerChange.bind(element, (this.price + (this.upgrades * this.upgradePrice / 2 || 0)));
	}
}

/** @this {HTMLSelectElement} */
function buyerChange(bankPrice) {
	var element = this.parentNode.querySelector('.price');
	if (element.disabled != (this.value == -1)) {
		element.disabled = (this.value == -1);
		if (this.value == -1) {
			element.lastValue = element.value;
			element.value = bankPrice;
		} else if (element.lastValue) {
			element.value = element.lastValue;
		}
	}
}

/** @this {Place|Rail|Service} */
function sell() {
	var price = +last(document.getElementsByClassName('price')).value;
	var buyerIndex = last(document.getElementsByClassName('buyer')).value;
	if (!price || price < 0) { // price might be NaN.
		say('input a valid price.', this.owner);
		return false;
	}
	if (!buyerIndex) {
		say('select a buyer.', this.owner);
		return false;
	}
	var buyer = players[buyerIndex];
	if (!buyer) {
		earn(price, this.owner);
	} else if (!buyer.tryPaying(price, this.owner)) {
		return false;
	}
	changeOwner.call(this, buyer);
}

function escape(s) {
	return s.replace(/&/g, '&').replace(/</g, '<');
}

function say(message, player) {
	var p = document.createElement('p');
	p.innerHTML = (player ? escape(player.name) + ', ' : '') + message;
	document.getElementById('message').appendChild(p);
	p.scrollIntoView();
}

function ask(message, player, callback) {
	var question = '' + message + '';
	if (!questions.length || last(questions).message != question) {
		say(question, player);
		var index = questions.length && questions[0].primary ? 1 : 0;
		questions[index] = {message: question, player: player, callback: callback};
		document.querySelector('.cancel').disabled = questions.length < 2;
	}
}

function position(i) {
	return {
		top: 10 + 66 * (i < 10 ? 10 - i : i < 20 ? 0 : i < 30 ? i - 20 : 10),
		left: 10 + 128 * (i < 10 ? 0 : i < 20 ? i - 10 : i < 30 ? 10 : 40 - i)
	};
}

for (var i = 0, field; field = fields[i]; i++) {
	field.index = i;
	var div = document.createElement('div');
	div.className = 'field';
	div.innerHTML = field.name + (field.price ? ' (' + field.price + ')' : '') + '
' + (field.getEarns ? field.getEarns() : field.earns || '') + '';
	div.style.borderTop = '10px solid ' + (field.color || 'silver');
	var pos = position(i);
	div.style.top = pos.top + 'px';
	div.style.left = pos.left + 'px';
	field.div = div;
	document.body.appendChild(div);
}

var players = [];
var playing = -1;
<|endoftext|>


<commit_before>/**
 * @author sunag / http://www.sunag.com.br/
 */

import { TempNode } from '../core/TempNode.js';
import { TextureCubeUVNode } from './TextureCubeUVNode.js';

function TextureCubeNode( value, uv ) {

	TempNode.call( this, 'v4' );

	this.value = value;
	this.uv = uv || new TextureCubeUVNode();

}

TextureCubeNode.prototype = Object.create( TempNode.prototype );
TextureCubeNode.prototype.constructor = TextureCubeNode;
TextureCubeNode.prototype.nodeType = "TextureCube";

TextureCubeNode.prototype.generate = function ( builder, output ) {

	if ( builder.isShader( 'fragment' ) ) {

		var uv_10 = this.uv.build( builder ) + '.uv_10',
			uv_20 = this.uv.build( builder ) + '.uv_20',
			t = this.uv.build( builder ) + '.t';

		var color10 = builder.getTexelDecodingFunctionFromTexture( 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_10 + ' )', this.value.value ),
			color20 = builder.getTexelDecodingFunctionFromTexture( 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_20 + ' )', this.value.value );

		return builder.format( 'vec4( mix( ' + color10 + ', ' + color20 + ', ' + t + ' ).rgb, 1.0 )', this.getType( builder ), output );

	} else {

		console.warn( "THREE.TextureCubeNode is not compatible with " + builder.shader + " shader." );

		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );

	}

};

TextureCubeNode.prototype.toJSON = function ( meta ) {

	var data = this.getJSONNode( meta );

	if ( ! data ) {

		data = this.createJSONNode( meta );

		data.uv = this.uv.toJSON( meta ).uuid;
		data.textureSize = this.textureSize.toJSON( meta ).uuid;
		data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid;

		if ( this.roughness ) data.roughness = this.roughness.toJSON( meta ).uuid;

	}

	return data;

};

export { TextureCubeNode };
<commit_msg>Fixed TextureCubeNode<commit_after>/**
 * @author sunag / http://www.sunag.com.br/
 */

import { TempNode } from '../core/TempNode.js';
import { TextureCubeUVNode } from './TextureCubeUVNode.js';

function TextureCubeNode( value, uv ) {

	TempNode.call( this, 'v4' );

	this.value = value;
	this.uv = uv || new TextureCubeUVNode();

}

TextureCubeNode.prototype = Object.create( TempNode.prototype );
TextureCubeNode.prototype.constructor = TextureCubeNode;
TextureCubeNode.prototype.nodeType = "TextureCube";

TextureCubeNode.prototype.generate = function ( builder, output ) {

	if ( builder.isShader( 'fragment' ) ) {

		var uv_10 = this.uv.build( builder ) + '.uv_10',
			uv_20 = this.uv.build( builder ) + '.uv_20',
			t = this.uv.build( builder ) + '.t';

		builder.addContext( { encoding: builder.getTextureEncodingFromMap( this.value ), include: builder.isShader( 'vertex' ) } );

		var color10 = 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_10 + ' )',
			color20 = 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_20 + ' )';

		builder.removeContext();

		return builder.format( 'vec4( mix( ' + color10 + ', ' + color20 + ', ' + t + ' ).rgb, 1.0 )', this.getType( builder ), output );

	} else {

		console.warn( "THREE.TextureCubeNode is not compatible with " + builder.shader + " shader." );

		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );

	}

};

TextureCubeNode.prototype.toJSON = function ( meta ) {

	var data = this.getJSONNode( meta );

	if ( ! data ) {

		data = this.createJSONNode( meta );

		data.uv = this.uv.toJSON( meta ).uuid;
		data.textureSize = this.textureSize.toJSON( meta ).uuid;
		data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid;

		if ( this.roughness ) data.roughness = this.roughness.toJSON( meta ).uuid;

	}

	return data;

};

export { TextureCubeNode };
<|endoftext|>


<commit_before>
var fs       = require('promised-io/fs'),
    promise  = require('promised-io/promise'),
    sys      = require('sys'),
    proton   = require('proton/proton');
//    Spectrum = ;

var types = {
    'png'  : 'image/png',
    'jpg'  : 'image/jpeg',
    'jpeg' : 'image/jpeg',
    'gif'  : 'image/gif',
    'css'  : 'text/css',
    'js'   : 'text/javascript',
    'swf'  : 'application/x-shockwave-flash'
};

var Response = function (webapp) {
    this.webapp = webapp;
    this._response = {
        status: 404,
        headers: { 'Content-Type' : 'text/plain' }
    };
    this._handled = false;
};

Response.prototype.setStatus = function (status) {
    this._response.status = status;
    this._handled = true;
};

Response.prototype.setType = function (type) {
    this._response.headers['Content-Type'] = type;
};

Response.prototype.ok = function (type) {
    this.setStatus(200);
    this.setType(type);
};

Response.prototype.addToBody = function (body) {
    if (this._response.body) {
        this._response.body.push(body);
    }
    else {
        this._response.body = [body];
    }
};

function quotemeta (input) {
    return input.replace(/([\\\/^$*+?.()|{}\[\]])/g, '\\$1');
}

function makeNamedMatcher (parts) {
    var re    = '',
        names = [];
    for (var i = 0, l = parts.length; i < l; i += 3) {
        re += quotemeta(parts[i]);
        if (i + 1 < l) {
            re += '(' + (typeof(parts[i + 2]) !== 'undefined' ? parts[i + 2] : '[^\\/]+') + ')';
            names.push(parts[i + 1]);
        }
    }
    var regex = new RegExp('^' + re + '$');
    return function (path) {
        var match = path.match(regex);
        if (match) {
            var vals = {};
            for (var i = 0, l = names.length; i < l; i++) {
                vals[names[i]] = match[i + 1];
            }
            return [vals];
        }
    };
}

function makePositionalMatcher (parts) {
    var re      = '',
        matches = 0;
    for (var i = 0, l = parts.length; i < l; i += 3) {
        re += quotemeta(parts[i]);
        if (i + 1 < l) {
            re += quotemeta(parts[i + 1]);
            matches++;
            re += '(' + (typeof(parts[i + 2]) !== 'undefined' ? parts[i + 2] : '[^\\/]+') + ')';
        }
    }
    var regex = new RegExp('^' + re + '$');
    return function (path) {
        var match = path.match(regex);
        if (match) {
            var vals = [];
            for (var i = 0; i < matches; i++) {
                vals.push(match[i + 1]);
            }
            return vals;
        }
    };
}

var namedPattern = /:(\w+)(?:\[((?:[^\[\]]|\[(?:[^\]]|\\])+?\])+?)\])?/,
    positionalPattern = /(^|\/)\*(?:\[((?:[^\[\]]|\[(?:[^\]]|\\])+?\])+?)\])?(?:$|(?=\/))/;

function makeMatcher (route) {
    if (route instanceof RegExp || typeof(route) === 'function') {
        return route;
    }
    var named = route.split(namedPattern),
        positional = route.split(positionalPattern);
    if (named.length > 1 && positional.length > 1) {
        throw new Error('cannot have route with both named (:name) and positional (*) parameters ("' + route + '")');
    }
    else if (named.length > 1) {
        return makeNamedMatcher(named);
    }
    else if (positional.length > 1) {
        return makePositionalMatcher(positional);
    }
    return route;
}

var WebApp = exports.WebApp = proton.framework(function (setup) {
    this.handlers = {
        'GET'    : [],
        'POST'   : [],
        'PUT'    : [],
        'DELETE' : []
    };
//    this.io = io.listen(this.server);

    var webapp = this;
    setup.call(
        this,
        function () { return webapp.get.apply(webapp, arguments); },
        function () { return webapp.post.apply(webapp, arguments); },
        function () { return webapp.put.apply(webapp, arguments); },
        function () { return webapp.del.apply(webapp, arguments); }
    );
});

WebApp.prototype.get = function (path, handler) {
    this.handlers.GET.push([makeMatcher(path), handler]);
};

WebApp.prototype.post = function (path, handler) {
    this.handlers.POST.push([makeMatcher(path), handler]);
};

WebApp.prototype.put = function (path, handler) {
    this.handlers.PUT.push([makeMatcher(path), handler]);
};

WebApp.prototype.del = function (path, handler) {
    this.handlers.DELETE.push([makeMatcher(path), handler]);
};

WebApp.prototype.handleStatic = function (root, prefix) {
    if (! root) {
        throw new Error('missing root directory for static files');
    }
    if (! prefix) {
        prefix = '';
    }
    prefix = prefix.replace(/([^\w])/g, '\\$1');
    var realRoot  = fs.realpath(root),
        realPaths = {},
        webapp    = this,
        notFound  = function (err) {
            response.setStatus(404);
            response.setType('text/plain');
            return 'not found';
        };
    this.context.beforeStart(realRoot.then(
        function (root) {
            webapp.get(new RegExp('^' + prefix + '(.+\\.(css|js|jpe?g|gif|png|swf|spv))$'), function (request, path, type) {
                var path = root + path,
                    response = this;
                if (! (path in realPaths)) {
                    realPaths[path] = fs.realpath(path);
                }
                return realPaths[path].then(
                    function (assetPath) {
                        return fs.readFile(assetPath).then(
                            function (contents) {
                                response.setStatus(200);
                                response.setType(types[type]);
                                return contents;
                            },
                            notFound
                        );
                    },
                    notFound
                );
            });
        },
        function (err) {
            throw new Error('TODO handle cannot find real root: ' + err);
        }
    ));
};

WebApp.prototype.handle = function (request) {
    var handlers = this.handlers[request.method],
        body,
        matchAgainst = request.pathInfo,
        args,
        response = new Response(this);
    for (var i = 0, l = handlers.length; i < l; i++) {
        if ((handlers[i][0] instanceof RegExp)) {
            if (args = matchAgainst.match(handlers[i][0])) {
                args.shift();
                args.unshift(request);
                body = handlers[i][1].apply(response, args);
            }
        }
        else if (typeof(handlers[i][0]) === 'function' && (args = handlers[i][0].call(request, matchAgainst))) {
            args.unshift(request);
            body = handlers[i][1].apply(response, args);
        }
        else if (handlers[i][0] === matchAgainst) {
            body = handlers[i][1].call(response, request);
        }
        if (body && body.then) {
            // TODO capture the routing continuation in case of it being rejected
            return body.then(function (body) {
                response.addToBody(body);
                return response._response;
            });
        }
        else if (response._handled) {
            response.addToBody(body);
            return response._response;
        }
    }
    throw new Error('request not handled');
    return response._response;
};

exports.run = proton.run;
<commit_msg>correct path for proton<commit_after>
var fs       = require('promised-io/fs'),
    promise  = require('promised-io/promise'),
    sys      = require('sys'),
    proton   = require('proton');
//    Spectrum = ;

var types = {
    'png'  : 'image/png',
    'jpg'  : 'image/jpeg',
    'jpeg' : 'image/jpeg',
    'gif'  : 'image/gif',
    'css'  : 'text/css',
    'js'   : 'text/javascript',
    'swf'  : 'application/x-shockwave-flash'
};

var Response = function (webapp) {
    this.webapp = webapp;
    this._response = {
        status: 404,
        headers: { 'Content-Type' : 'text/plain' }
    };
    this._handled = false;
};

Response.prototype.setStatus = function (status) {
    this._response.status = status;
    this._handled = true;
};

Response.prototype.setType = function (type) {
    this._response.headers['Content-Type'] = type;
};

Response.prototype.ok = function (type) {
    this.setStatus(200);
    this.setType(type);
};

Response.prototype.addToBody = function (body) {
    if (this._response.body) {
        this._response.body.push(body);
    }
    else {
        this._response.body = [body];
    }
};

function quotemeta (input) {
    return input.replace(/([\\\/^$*+?.()|{}\[\]])/g, '\\$1');
}

function makeNamedMatcher (parts) {
    var re    = '',
        names = [];
    for (var i = 0, l = parts.length; i < l; i += 3) {
        re += quotemeta(parts[i]);
        if (i + 1 < l) {
            re += '(' + (typeof(parts[i + 2]) !== 'undefined' ? parts[i + 2] : '[^\\/]+') + ')';
            names.push(parts[i + 1]);
        }
    }
    var regex = new RegExp('^' + re + '$');
    return function (path) {
        var match = path.match(regex);
        if (match) {
            var vals = {};
            for (var i = 0, l = names.length; i < l; i++) {
                vals[names[i]] = match[i + 1];
            }
            return [vals];
        }
    };
}

function makePositionalMatcher (parts) {
    var re      = '',
        matches = 0;
    for (var i = 0, l = parts.length; i < l; i += 3) {
        re += quotemeta(parts[i]);
        if (i + 1 < l) {
            re += quotemeta(parts[i + 1]);
            matches++;
            re += '(' + (typeof(parts[i + 2]) !== 'undefined' ? parts[i + 2] : '[^\\/]+') + ')';
        }
    }
    var regex = new RegExp('^' + re + '$');
    return function (path) {
        var match = path.match(regex);
        if (match) {
            var vals = [];
            for (var i = 0; i < matches; i++) {
                vals.push(match[i + 1]);
            }
            return vals;
        }
    };
}

var namedPattern = /:(\w+)(?:\[((?:[^\[\]]|\[(?:[^\]]|\\])+?\])+?)\])?/,
    positionalPattern = /(^|\/)\*(?:\[((?:[^\[\]]|\[(?:[^\]]|\\])+?\])+?)\])?(?:$|(?=\/))/;

function makeMatcher (route) {
    if (route instanceof RegExp || typeof(route) === 'function') {
        return route;
    }
    var named = route.split(namedPattern),
        positional = route.split(positionalPattern);
    if (named.length > 1 && positional.length > 1) {
        throw new Error('cannot have route with both named (:name) and positional (*) parameters ("' + route + '")');
    }
    else if (named.length > 1) {
        return makeNamedMatcher(named);
    }
    else if (positional.length > 1) {
        return makePositionalMatcher(positional);
    }
    return route;
}

var WebApp = exports.WebApp = proton.framework(function (setup) {
    this.handlers = {
        'GET'    : [],
        'POST'   : [],
        'PUT'    : [],
        'DELETE' : []
    };
//    this.io = io.listen(this.server);

    var webapp = this;
    setup.call(
        this,
        function () { return webapp.get.apply(webapp, arguments); },
        function () { return webapp.post.apply(webapp, arguments); },
        function () { return webapp.put.apply(webapp, arguments); },
        function () { return webapp.del.apply(webapp, arguments); }
    );
});

WebApp.prototype.get = function (path, handler) {
    this.handlers.GET.push([makeMatcher(path), handler]);
};

WebApp.prototype.post = function (path, handler) {
    this.handlers.POST.push([makeMatcher(path), handler]);
};

WebApp.prototype.put = function (path, handler) {
    this.handlers.PUT.push([makeMatcher(path), handler]);
};

WebApp.prototype.del = function (path, handler) {
    this.handlers.DELETE.push([makeMatcher(path), handler]);
};

WebApp.prototype.handleStatic = function (root, prefix) {
    if (! root) {
        throw new Error('missing root directory for static files');
    }
    if (! prefix) {
        prefix = '';
    }
    prefix = prefix.replace(/([^\w])/g, '\\$1');
    var realRoot  = fs.realpath(root),
        realPaths = {},
        webapp    = this,
        notFound  = function (err) {
            response.setStatus(404);
            response.setType('text/plain');
            return 'not found';
        };
    this.context.beforeStart(realRoot.then(
        function (root) {
            webapp.get(new RegExp('^' + prefix + '(.+\\.(css|js|jpe?g|gif|png|swf|spv))$'), function (request, path, type) {
                var path = root + path,
                    response = this;
                if (! (path in realPaths)) {
                    realPaths[path] = fs.realpath(path);
                }
                return realPaths[path].then(
                    function (assetPath) {
                        return fs.readFile(assetPath).then(
                            function (contents) {
                                response.setStatus(200);
                                response.setType(types[type]);
                                return contents;
                            },
                            notFound
                        );
                    },
                    notFound
                );
            });
        },
        function (err) {
            throw new Error('TODO handle cannot find real root: ' + err);
        }
    ));
};

WebApp.prototype.handle = function (request) {
    var handlers = this.handlers[request.method],
        body,
        matchAgainst = request.pathInfo,
        args,
        response = new Response(this);
    for (var i = 0, l = handlers.length; i < l; i++) {
        if ((handlers[i][0] instanceof RegExp)) {
            if (args = matchAgainst.match(handlers[i][0])) {
                args.shift();
                args.unshift(request);
                body = handlers[i][1].apply(response, args);
            }
        }
        else if (typeof(handlers[i][0]) === 'function' && (args = handlers[i][0].call(request, matchAgainst))) {
            args.unshift(request);
            body = handlers[i][1].apply(response, args);
        }
        else if (handlers[i][0] === matchAgainst) {
            body = handlers[i][1].call(response, request);
        }
        if (body && body.then) {
            // TODO capture the routing continuation in case of it being rejected
            return body.then(function (body) {
                response.addToBody(body);
                return response._response;
            });
        }
        else if (response._handled) {
            response.addToBody(body);
            return response._response;
        }
    }
    throw new Error('request not handled');
    return response._response;
};

exports.run = proton.run;
<|endoftext|>