<commit_before>/*global require, exports */

////////////////////////////////////////////////////////////////////////////////
/// @brief Foxx Preprocessor
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Lucas Dohmen
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var Preprocessor,
  preprocess,
  ArrayIterator,
  extend = require("underscore").extend,
  coffeeScript = require("coffee-script");

ArrayIterator = function (arr) {
  'use strict';
  this.array = arr;
  this.currentLineNumber = -1;
};

extend(ArrayIterator.prototype, {
  next: function () {
    'use strict';
    this.currentLineNumber += 1;
    return this.array[this.currentLineNumber];
  },

  current: function () {
    'use strict';
    return this.array[this.currentLineNumber];
  },

  hasNext: function () {
    'use strict';
    return this.currentLineNumber < (this.array.length - 1);
  },

  replaceWith: function (newLine) {
    'use strict';
    this.array[this.currentLineNumber] = newLine;
  },

  entireString: function () {
    'use strict';
    return this.array.join("\n");
  },

  getCurrentLineNumber: function () {
    'use strict';
    if (this.hasNext()) {
      return this.currentLineNumber;
    }
  }
});

Preprocessor = function (input, type) {
  'use strict';

  if (type === 'coffee') {
    input = coffeeScript.compile(input, {bare: true});
  }

  this.iterator = new ArrayIterator(input.replace('\r', '').split("\n"));
  this.inJSDoc = false;
};

extend(Preprocessor.prototype, {
  result: function () {
    'use strict';
    return this.iterator.entireString();
  },

  convert: function () {
    'use strict';
    while (this.searchNext()) {
      this.convertLine();
    }
    return this;
  },

  searchNext: function () {
    'use strict';
    while (this.iterator.hasNext()) {
      if (this.isJSDoc(this.iterator.next())) {
        return true;
      }
    }
  },

  convertLine: function () {
    'use strict';
    this.iterator.replaceWith(
      "applicationContext.comment(\"" + this.stripComment(this.iterator.current()) + "\");"
    );
  },

  getCurrentLineNumber: function () {
    'use strict';
    return this.iterator.getCurrentLineNumber();
  },

  // helper

  stripComment: function (str) {
    'use strict';
    return str.match(/^\s*\/?\*\*?\/?\s*(.*)$/)[1];
  },

  isJSDoc: function (str) {
    'use strict';
    var matched;

    if (this.inJSDoc && str.match(/^\s*\*/)) {
      matched = true;
      if (str.match(/^\s*\*\//)) {
        this.inJSDoc = false;
      }
    } else if ((!this.inJSDoc) && str.match(/^\s*\/\*\*/)) {
      matched = true;
      this.inJSDoc = true;
    }

    return matched;
  }
});

preprocess = function (input, type) {
  'use strict';
  var processer = new Preprocessor(input, type);
  return processer.convert().result();
};

// Only Exported for Tests, please use `process`
exports.Preprocessor = Preprocessor;

// process(str) returns the processed String
exports.preprocess = preprocess;

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

/// Local Variables:
/// mode: outline-minor
/// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
/// End:
<commit_msg>fix comment parsing in Foxx controllers<commit_after>/*global require, exports */

////////////////////////////////////////////////////////////////////////////////
/// @brief Foxx Preprocessor
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Lucas Dohmen
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var Preprocessor,
  preprocess,
  ArrayIterator,
  extend = require("underscore").extend,
  coffeeScript = require("coffee-script");

ArrayIterator = function (arr) {
  'use strict';
  this.array = arr;
  this.currentLineNumber = -1;
};

extend(ArrayIterator.prototype, {
  next: function () {
    'use strict';
    this.currentLineNumber += 1;
    return this.array[this.currentLineNumber];
  },

  current: function () {
    'use strict';
    return this.array[this.currentLineNumber];
  },

  hasNext: function () {
    'use strict';
    return this.currentLineNumber < (this.array.length - 1);
  },

  replaceWith: function (newLine) {
    'use strict';
    this.array[this.currentLineNumber] = newLine;
  },

  entireString: function () {
    'use strict';
    return this.array.join("\n");
  },

  getCurrentLineNumber: function () {
    'use strict';
    if (this.hasNext()) {
      return this.currentLineNumber;
    }
  }
});

Preprocessor = function (input, type) {
  'use strict';

  if (type === 'coffee') {
    input = coffeeScript.compile(input, {bare: true});
  }

  this.iterator = new ArrayIterator(input.replace('\r', '').split("\n"));
  this.inJSDoc = false;
};

extend(Preprocessor.prototype, {
  result: function () {
    'use strict';
    return this.iterator.entireString();
  },

  convert: function () {
    'use strict';
    while (this.searchNext()) {
      this.convertLine();
    }
    return this;
  },

  searchNext: function () {
    'use strict';
    while (this.iterator.hasNext()) {
      if (this.isJSDoc(this.iterator.next())) {
        return true;
      }
    }
  },

  convertLine: function () {
    'use strict';
    this.iterator.replaceWith(
      "applicationContext.comment(\"" + this.stripComment(this.iterator.current()) + "\");"
    );
  },

  getCurrentLineNumber: function () {
    'use strict';
    return this.iterator.getCurrentLineNumber();
  },

  // helper

  stripComment: function (str) {
    'use strict';
    return str.replace(/^\s*\/\*\*/, ''). // start of JSDoc comment
               replace(/^\s*\*/, '').     // continuation of JSDoc comment
               replace(/^.*?\*\//, '').   // end of JSDoc comment
               replace(/\\/g, '\\\\').    // replace backslashes
               replace(/"/g, '\\"');      // replace quotes
  },

  isJSDoc: function (str) {
    'use strict';
    var matched;

    if (this.inJSDoc) {
      if (str.match(/\*\//)) {
        this.inJSDoc = false;
        matched = true;
      }
      else {
        matched = true;
      }
    } else if ((!this.inJSDoc) && str.match(/^\s*\/\*\*/)) {
      matched = true;
      this.inJSDoc = true;
    }

    return matched;
  }
});

preprocess = function (input, type) {
  'use strict';
  var processer = new Preprocessor(input, type);
  return processer.convert().result();
};

// Only Exported for Tests, please use `process`
exports.Preprocessor = Preprocessor;

// process(str) returns the processed String
exports.preprocess = preprocess;

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

/// Local Variables:
/// mode: outline-minor
/// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
/// End:
<|endoftext|>


<commit_before>var transit = (function () {
    return {
        initMap : function () {
            var mapDet = {
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };

            var map = new google.maps.Map(document.getElementById('transitMap'), mapDet);
            return map;
        },

        initMarker : function (coords, mouseoverText, map) {
            mouseoverText = (typeof mouseoverText == 'undefined') ? 'Marker' : mouseoverText;
            var markerPos = new google.maps.LatLng(coords[0], coords[1]);

            var markerIcon = {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: 'red',
                fillOpacity: 0.8,
                scale: 5
            };

            var mouseoverInfo = new google.maps.InfoWindow({
                content: mouseoverText,
                map: map
            });

            var marker = {
                position: markerPos,
                title: mouseoverText,
                icon: markerIcon
            };

            marker = new google.maps.Marker(marker);

            google.maps.event.addListener(marker, 'mouseover', function() {
            	mouseoverInfo.open(map, this);
            });

            google.maps.event.addListener(marker, 'mouseout', function() {
            	mouseoverInfo.close();
            });

            return marker;
        },

        moveMarkers : function (markerSet, interval, map) {
            interval = (typeof interval == 'undefined') ? 1000 : interval;
            var transition = setInterval(
                    function () {
                        for (var counter = 0; counter < markerSet.length; counter++) {
                            for (var i = 0; i < markerSet.length; i++) {
                                var curPos = new google.maps.LatLng(markerSet[i].coordSet[counter][0],
                                    markerSet[i].coordSet[counter][1]);
                                markerSet[i].marker.position = curPos;
                                markerSet[i].marker.setMap(map);
                            }
                        }
                    },
                    interval);
        },

        constructMarkerSet : function (markers) {
            var markerSet = new Array();
            for (var counter = 0; counter < markers.length; counter++) {
                var markerObj = transit.initMarker(markers[counter].coords[0], markers[counter].title);
                var coordList = markers[counter].coords.slice(1);

                markerSet.push({
                    marker: markerObj,
                    coordSet: coordList
                });
            }
            return markerSet;
        },

        overlayKml : function (kmlUrl, map) {
            var kmlOptions = {
                map: map
            };
            var kmlLayer = new google.maps.KmlLayer(kmlUrl, kmlOptions);
        },

        init : function (kmlUrl, markerList, interval) {
            google.maps.event.addDomListener(window, 'load',
                    function () {
                        var map = transit.initMap();
                        transit.overlayKml(kmlUrl, map);
                        var markerSet = transit.constructMarkerSet(markerList);
                        transit.moveMarkers(markerSet, interval, map);
                    });
        },

        routeParser : function (xmlUrl) {
            $.ajax({
                url: xmlUrl,
                dataType: 'xml',
                success : function (data) {
                    var xmlNode = $('Document', data);
                    var lines = {};
                    var points = {};

                    xmlNode.find('Placemark > LineString > coordinates').each(function () {
                        var simPts = transit.trim($(this).text()).split(' ');
                        var grpPts = new Array();
                        var routeName = $(this).closest('Placemark').find('name').text().toLowerCase();
                        for (eachPt in simPts) {
                            var xy = transit.strip(simPts[eachPt]).split(',');
                            grpPts.push({ x: xy[0], y: xy[1] });
                        }
                        lines[routeName] = grpPts;
                    });

                    xmlNode.find('Point').each(function () {
                        var parentTag = $(this).closest('Placemark');

                        var xy = transit.strip(parentTag.find('Point').text()).split(',');
                        points[parentTag.find('name').text().toLowerCase()] = { x: xy[0], y: xy[1] };
                    });

                    return {
                        "lines": lines,
                        "points": points
                    };
                },
                error : function (data) {
                    console.log('Error');
                }
            });
        },

        vehicleParser : function (jsonUrl) {
            $.getJSON(jsonUrl).success(function (data) {
                return {
                    "timezone": data.timezone,
                    "vehicles": data.vehicles
                };
            });
        },

        schedule : function (vehicleObj, routes, timezone) {
            var vehicleArrivals = {};
            var vehicleDepartures = {};
            var vehicleTravelTimes = [];
            var vehicleRoute = vehicleObj.route;
            var stopsObj = vehicleObj.stops;
            var noOfStops = vehicleObj.stops.length;
            var firstStop = stopsObj[0];
            var firstStopName = firstStop.name.toLowerCase();
            var startTime = transit.parseTime(firstStop.departure, firstStop.day, timezone);
            var vehicleStopCoords = {};
            var points = routes.points;

            vehicleDepartures[startTime] = firstStopName;
            vehicleTravelTimes.push(startTime);
            vehicleStopCoords[firstStopName] = points[firstStopName];

            for (var eachStop = 1; eachStop < noOfStops - 1; eachStop++) {
                var temp = stopsObj[eachStop];
                var tempName = temp.name.toLowerCase();
                var currArrivalTime = transit.parseTime(temp.arrival, temp.day, timezone) - startTime;
                var currDepartureTime = transit.parseTime(temp.departure, temp.day, timezone) - startTime;
                vehicleArrivals[currArrivalTime] = tempName;
                vehicleDepartures[currDepartureTime] = tempName;
                vehicleTravelTimes.push(currArrivalTime, currDepartureTime);
                vehicleStopCoords[tempName] = points[tempName];
            }

            var lastStop = stopsObj[noOfStops];
            var lastStopName = lastStop.name.toLowerCase();
            var endTime = transit.parseTime(lastStop.arrival, lastStop.day, timezone) - startTime;
            vehicleArrivals[endTime] = lastStopName;
            vehicleTravelTimes.push(endTime);
            vehicleStopCoords[lastStopName] = points[lastStopName];
            var line = transit.pointsBetweenStops(routes.lines[vehicleRoute], points[firstStopName],
                                                  points[lastStopName]);
            var percentStopDists = transit.hashOfPercentDists(line);

            return {
                "name": vehicleObj.name,
                "info": vehicleObj.info,
                "route": line,
                "stops": vehicleStopCoords,
                "ppoints": percentStopDists,
                "days": lastStop.day - firstStop.day,
                "arrivals": vehicleArrivals,
                "departures": vehicleDepartures,
                "traveltimes": vehicleTravelTimes
            };
        },

        strip : function (string) {
            return string.replace(/\s+/g, '').replace(/\n/g, '');
        },

        trim : function (string) {
            return string.replace(/^\s+|\s+$/g, '');
        },

        // Reimplemented from http://www.movable-type.co.uk/scripts/latlong.html
        haversine : function (sourceCoords, targetCoords) {
            var R = 6371; // km

            /** Converts numeric degrees to radians */
            if (typeof(Number.prototype.toRad) === "undefined") {
              Number.prototype.toRad = function() {
                return this * Math.PI / 180;
              }
            }

            var dLat = (targetCoords.x - sourceCoords.x).toRad();
            var dLon = (targetCoords.y - sourceCoords.y).toRad();
            var lat1 = sourceCoords.x.toRad();
            var lat2 = targetCoords.x.toRad();

            var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
            var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            var d = R * c;
            return d;
        },

        linearDist : function (sourceCoords, targetCoords) {
            return Math.sqrt(Math.pow((targetCoords.x - sourceCoords.x), 2),
                             Math.pow((targetCoords.y - sourceCoords.y), 2));
        },

        percentDist : function (sourceCoords, targetCoords, percentage) {
            var newCoords = {};
            var ratio = percentage / 100;
            newCoords.x = (1 - ratio) * sourceCoords.x + ratio * targetCoords.x;
            newCoords.y = (1 - ratio) * sourceCoords.y + ratio * targetCoords.y;
            return newCoords;
        },

        percentInRange : function (lower, upper, target) {
            return ((target - lower) / (upper - lower)) * 100;
        },

        pointsBetweenStops: function (route, start, end) {
            return route.slice(route.indexOf(start), route.indexOf(end) + 1);
        },

        hashOfPercentDists : function (points) {
            var start = points[0];
            var routeLength = points.length;
            var end = points[routeLength - 1];
            var distanceHash = {
                0 : points[0]
            };
            var distances = new Array();
            var totalDist = 0;

            for (var x = 0; x < routeLength - 1; x++) {
                totalDist += transit.haversine(points[x], points[x + 1]);
                distances.push(totalDist);
            }

            for (var x = 0; x < distances.length; x++) {
                distanceHash[transit.percentInRange(0, totalDist, distances[x])] = points[x + 1];
            }

            return distanceHash;
        },

        // Variant of binary search that returns enclosing elements of searchElement in array.
        enclosure : function (searchElement) {
            'use strict';

            var minIndex = 0;
            var maxIndex = this.length - 1;
            var currentIndex;
            var currentElement;

            while (minIndex <= maxIndex) {
                currentIndex = (minIndex + maxIndex) / 2 | 0;
                currentElement = this[currentIndex];

                if (currentElement < searchElement) {
                    minIndex = currentIndex + 1;
                }
                else if (currentElement > searchElement) {
                    maxIndex = currentIndex - 1;
                }
                else {
                    return currentIndex;
                }
            }

            if (searchElement > this[currentIndex]) {
                if (typeof this[currentIndex + 1] != 'undefined')
                    return [currentIndex, currentIndex + 1];
                else
                    return currentIndex;
            } else {
                if (typeof this[currentIndex - 1] !=  'undefined')
                    return [currentIndex - 1, currentIndex];
                else
                    return 0;
            }
        },

        parseTime : function (timeString, day, timezone) {
            var hms = timeString.split(':');
            hms = hms.map(function (x) { return parseInt(x, 10); });

            if (hms.length < 3)
                hms[2] = 0;

            return hms[0] * 3600 + hms[1] * 60 + hms[2] + (day - 1) * 86400 + timezone * 60;
        },

        currTime : function () {
            var t = new Date();
            return t.getHours().toString() + ":" +
                   t.getMinutes().toString() + ":" +
                   t.getSeconds().toString();
        },

        estimateCurrentPosition : function (vehicleObj, timezone) {
            var arrivals = vehicleObj.arrivals;
            var departures = vehicleObj.departures;
            var travelTimes = vehicleObj.traveltimes;
            var noOfDays = vehicleObj.days;
            var ppoints = vehicleObj.ppoints;

            var route = vehicleObj.route;
            var stops = vehicleObj.stops;
            var percentDists = transit.hashOfPercentDists(stops);

            var time = transit.currTime();
            var range = transit.enclosure.call(travelTimes, time);
            var coords = new Array();

            if (range[0] % 2 == 0 && range.length == 2) {
                var leavingStop = departures[range[0]];
                var approachingStop = arrivals[range[1]];
                var leavingStopCoords = stops[leavingStop];
                var approachingStop = stops[approachingStop];
                var timePercentArray = new Array();

                for (var i = 1; i <= noOfDays + 1; i++) {
                    timePercentArray.push(transit.percentInRange(travelTimes[range[0]], travelTimes[range[1]],
                                                                 transit.parseTime(currTime, i, timezone)));
                }

                for (var i = 0; i < timePercentArray.length; i++) {
                    var timeRange = transit.enclosure.call(ppoints, timePercentArray[i]);
                    var percent = transit.percentInRange(ppoints[timeRange[0]],
                                                         ppoints[timeRange[1]], timePercentArray[i]);
                    coords.push(transit.percentDist(ppoints[timeRange[0]], ppoints[timeRange[1]], percent));
                }
            } else {
                if (typeof range[1] != 'undefined')
                    coords.push(stops[departures[range[1]]]);
            }

            return coords;
        }
    };
})();
<commit_msg>Calculate current time just before estimation<commit_after>var transit = (function () {
    return {
        initMap : function () {
            var mapDet = {
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };

            var map = new google.maps.Map(document.getElementById('transitMap'), mapDet);
            return map;
        },

        initMarker : function (coords, mouseoverText, map) {
            mouseoverText = (typeof mouseoverText == 'undefined') ? 'Marker' : mouseoverText;
            var markerPos = new google.maps.LatLng(coords[0], coords[1]);

            var markerIcon = {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: 'red',
                fillOpacity: 0.8,
                scale: 5
            };

            var mouseoverInfo = new google.maps.InfoWindow({
                content: mouseoverText,
                map: map
            });

            var marker = {
                position: markerPos,
                title: mouseoverText,
                icon: markerIcon
            };

            marker = new google.maps.Marker(marker);

            google.maps.event.addListener(marker, 'mouseover', function() {
            	mouseoverInfo.open(map, this);
            });

            google.maps.event.addListener(marker, 'mouseout', function() {
            	mouseoverInfo.close();
            });

            return marker;
        },

        moveMarkers : function (markerSet, interval, map) {
            interval = (typeof interval == 'undefined') ? 1000 : interval;
            var transition = setInterval(
                    function () {
                        for (var counter = 0; counter < markerSet.length; counter++) {
                            for (var i = 0; i < markerSet.length; i++) {
                                var curPos = new google.maps.LatLng(markerSet[i].coordSet[counter][0],
                                    markerSet[i].coordSet[counter][1]);
                                markerSet[i].marker.position = curPos;
                                markerSet[i].marker.setMap(map);
                            }
                        }
                    },
                    interval);
        },

        constructMarkerSet : function (markers) {
            var markerSet = new Array();
            for (var counter = 0; counter < markers.length; counter++) {
                var markerObj = transit.initMarker(markers[counter].coords[0], markers[counter].title);
                var coordList = markers[counter].coords.slice(1);

                markerSet.push({
                    marker: markerObj,
                    coordSet: coordList
                });
            }
            return markerSet;
        },

        overlayKml : function (kmlUrl, map) {
            var kmlOptions = {
                map: map
            };
            var kmlLayer = new google.maps.KmlLayer(kmlUrl, kmlOptions);
        },

        init : function (kmlUrl, markerList, interval) {
            google.maps.event.addDomListener(window, 'load',
                    function () {
                        var map = transit.initMap();
                        transit.overlayKml(kmlUrl, map);
                        var markerSet = transit.constructMarkerSet(markerList);
                        transit.moveMarkers(markerSet, interval, map);
                    });
        },

        routeParser : function (xmlUrl) {
            $.ajax({
                url: xmlUrl,
                dataType: 'xml',
                success : function (data) {
                    var xmlNode = $('Document', data);
                    var lines = {};
                    var points = {};

                    xmlNode.find('Placemark > LineString > coordinates').each(function () {
                        var simPts = transit.trim($(this).text()).split(' ');
                        var grpPts = new Array();
                        var routeName = $(this).closest('Placemark').find('name').text().toLowerCase();
                        for (eachPt in simPts) {
                            var xy = transit.strip(simPts[eachPt]).split(',');
                            grpPts.push({ x: xy[0], y: xy[1] });
                        }
                        lines[routeName] = grpPts;
                    });

                    xmlNode.find('Point').each(function () {
                        var parentTag = $(this).closest('Placemark');

                        var xy = transit.strip(parentTag.find('Point').text()).split(',');
                        points[parentTag.find('name').text().toLowerCase()] = { x: xy[0], y: xy[1] };
                    });

                    return {
                        "lines": lines,
                        "points": points
                    };
                },
                error : function (data) {
                    console.log('Error');
                }
            });
        },

        vehicleParser : function (jsonUrl) {
            $.getJSON(jsonUrl).success(function (data) {
                return {
                    "timezone": data.timezone,
                    "vehicles": data.vehicles
                };
            });
        },

        schedule : function (vehicleObj, routes, timezone) {
            var vehicleArrivals = {};
            var vehicleDepartures = {};
            var vehicleTravelTimes = [];
            var vehicleRoute = vehicleObj.route;
            var stopsObj = vehicleObj.stops;
            var noOfStops = vehicleObj.stops.length;
            var firstStop = stopsObj[0];
            var firstStopName = firstStop.name.toLowerCase();
            var startTime = transit.parseTime(firstStop.departure, firstStop.day, timezone);
            var vehicleStopCoords = {};
            var points = routes.points;

            vehicleDepartures[startTime] = firstStopName;
            vehicleTravelTimes.push(startTime);
            vehicleStopCoords[firstStopName] = points[firstStopName];

            for (var eachStop = 1; eachStop < noOfStops - 1; eachStop++) {
                var temp = stopsObj[eachStop];
                var tempName = temp.name.toLowerCase();
                var currArrivalTime = transit.parseTime(temp.arrival, temp.day, timezone) - startTime;
                var currDepartureTime = transit.parseTime(temp.departure, temp.day, timezone) - startTime;
                vehicleArrivals[currArrivalTime] = tempName;
                vehicleDepartures[currDepartureTime] = tempName;
                vehicleTravelTimes.push(currArrivalTime, currDepartureTime);
                vehicleStopCoords[tempName] = points[tempName];
            }

            var lastStop = stopsObj[noOfStops];
            var lastStopName = lastStop.name.toLowerCase();
            var endTime = transit.parseTime(lastStop.arrival, lastStop.day, timezone) - startTime;
            vehicleArrivals[endTime] = lastStopName;
            vehicleTravelTimes.push(endTime);
            vehicleStopCoords[lastStopName] = points[lastStopName];
            var line = transit.pointsBetweenStops(routes.lines[vehicleRoute], points[firstStopName],
                                                  points[lastStopName]);
            var percentStopDists = transit.hashOfPercentDists(line);

            return {
                "name": vehicleObj.name,
                "info": vehicleObj.info,
                "route": line,
                "stops": vehicleStopCoords,
                "ppoints": percentStopDists,
                "days": lastStop.day - firstStop.day,
                "arrivals": vehicleArrivals,
                "departures": vehicleDepartures,
                "traveltimes": vehicleTravelTimes
            };
        },

        strip : function (string) {
            return string.replace(/\s+/g, '').replace(/\n/g, '');
        },

        trim : function (string) {
            return string.replace(/^\s+|\s+$/g, '');
        },

        // Reimplemented from http://www.movable-type.co.uk/scripts/latlong.html
        haversine : function (sourceCoords, targetCoords) {
            var R = 6371; // km

            /** Converts numeric degrees to radians */
            if (typeof(Number.prototype.toRad) === "undefined") {
              Number.prototype.toRad = function() {
                return this * Math.PI / 180;
              }
            }

            var dLat = (targetCoords.x - sourceCoords.x).toRad();
            var dLon = (targetCoords.y - sourceCoords.y).toRad();
            var lat1 = sourceCoords.x.toRad();
            var lat2 = targetCoords.x.toRad();

            var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
            var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            var d = R * c;
            return d;
        },

        linearDist : function (sourceCoords, targetCoords) {
            return Math.sqrt(Math.pow((targetCoords.x - sourceCoords.x), 2),
                             Math.pow((targetCoords.y - sourceCoords.y), 2));
        },

        percentDist : function (sourceCoords, targetCoords, percentage) {
            var newCoords = {};
            var ratio = percentage / 100;
            newCoords.x = (1 - ratio) * sourceCoords.x + ratio * targetCoords.x;
            newCoords.y = (1 - ratio) * sourceCoords.y + ratio * targetCoords.y;
            return newCoords;
        },

        percentInRange : function (lower, upper, target) {
            return ((target - lower) / (upper - lower)) * 100;
        },

        pointsBetweenStops: function (route, start, end) {
            return route.slice(route.indexOf(start), route.indexOf(end) + 1);
        },

        hashOfPercentDists : function (points) {
            var start = points[0];
            var routeLength = points.length;
            var end = points[routeLength - 1];
            var distanceHash = {
                0 : points[0]
            };
            var distances = new Array();
            var totalDist = 0;

            for (var x = 0; x < routeLength - 1; x++) {
                totalDist += transit.haversine(points[x], points[x + 1]);
                distances.push(totalDist);
            }

            for (var x = 0; x < distances.length; x++) {
                distanceHash[transit.percentInRange(0, totalDist, distances[x])] = points[x + 1];
            }

            return distanceHash;
        },

        // Variant of binary search that returns enclosing elements of searchElement in array.
        enclosure : function (searchElement) {
            'use strict';

            var minIndex = 0;
            var maxIndex = this.length - 1;
            var currentIndex;
            var currentElement;

            while (minIndex <= maxIndex) {
                currentIndex = (minIndex + maxIndex) / 2 | 0;
                currentElement = this[currentIndex];

                if (currentElement < searchElement) {
                    minIndex = currentIndex + 1;
                }
                else if (currentElement > searchElement) {
                    maxIndex = currentIndex - 1;
                }
                else {
                    return currentIndex;
                }
            }

            if (searchElement > this[currentIndex]) {
                if (typeof this[currentIndex + 1] != 'undefined')
                    return [currentIndex, currentIndex + 1];
                else
                    return currentIndex;
            } else {
                if (typeof this[currentIndex - 1] !=  'undefined')
                    return [currentIndex - 1, currentIndex];
                else
                    return 0;
            }
        },

        parseTime : function (timeString, day, timezone) {
            var hms = timeString.split(':');
            hms = hms.map(function (x) { return parseInt(x, 10); });

            if (hms.length < 3)
                hms[2] = 0;

            return hms[0] * 3600 + hms[1] * 60 + hms[2] + (day - 1) * 86400 + timezone * 60;
        },

        currTime : function () {
            var t = new Date();
            return t.getHours().toString() + ":" +
                   t.getMinutes().toString() + ":" +
                   t.getSeconds().toString();
        },

        estimateCurrentPosition : function (vehicleObj, timezone) {
            var arrivals = vehicleObj.arrivals;
            var departures = vehicleObj.departures;
            var travelTimes = vehicleObj.traveltimes;
            var noOfDays = vehicleObj.days;
            var ppoints = vehicleObj.ppoints;

            var route = vehicleObj.route;
            var stops = vehicleObj.stops;
            var percentDists = transit.hashOfPercentDists(stops);

            var coords = new Array();
            var time = transit.currTime();
            var range = transit.enclosure.call(travelTimes, time);

            if (range[0] % 2 == 0 && range.length == 2) {
                var leavingStop = departures[range[0]];
                var approachingStop = arrivals[range[1]];
                var leavingStopCoords = stops[leavingStop];
                var approachingStop = stops[approachingStop];
                var timePercentArray = new Array();

                for (var i = 1; i <= noOfDays + 1; i++) {
                    timePercentArray.push(transit.percentInRange(travelTimes[range[0]], travelTimes[range[1]],
                                                                 transit.parseTime(currTime, i, timezone)));
                }

                for (var i = 0; i < timePercentArray.length; i++) {
                    var timeRange = transit.enclosure.call(ppoints, timePercentArray[i]);
                    var percent = transit.percentInRange(ppoints[timeRange[0]],
                                                         ppoints[timeRange[1]], timePercentArray[i]);
                    coords.push(transit.percentDist(ppoints[timeRange[0]], ppoints[timeRange[1]], percent));
                }
            } else {
                if (typeof range[1] != 'undefined')
                    coords.push(stops[departures[range[1]]]);
            }

            return coords;
        }
    };
})();
<|endoftext|>


<commit_before>define(function () {
	'use strict';

	// TODO
	var is_eng = false;

	var TYPO_PATTERNS = {
			fixManyWhsps: [/[ \t]+/g, ' '], // replace unnecessary whitespace sequences with one whitespace
			fixWhspsInDots: [/\.\s\.\s\./g, '...'], // remove whitespaces between dots
			fixMore3Dots: [/(\.){4,}/g, '$1$1$1'], // replace sequence of more than three dots with three ones
			fixWhspsInMarks: [/(\?|!) (?=\?|!)/g, '$1'], // remove whitespaces between question and exclamation marks
			fixMore3Marks: [/[!?]{4,}/g, s => s.slice(0, 3)], // replace three or more question or exclamation marks with three ones
			fixHyphenDash: [/\s-(\s)/g, '\u00A0\u2014$1'], // replace hyphen with a dash with non-breaking space before
			fixLeftQuotes: [/(^|\s)"/g, (s, $1) => $1 + (is_eng ? '“' : '«')], // replace left-side double quotes
			fixRightQuotes: [/"(\s|[-.,:;?!]|$)/g, (s, $1) => $1 + (is_eng ? '”' : '»')], // replace right-side double quotes
			fixWhspsAfterMarks0: [/([,:;])(?=[^ ])/gi, '$1 '], // adding single whitespace after comma, colon and semicolon
			fixThinWhsps: [/( [a-zа-яё]\.)\s?([a-zа-яё]\.)/gi, (s, $1, $2) => $1 + '\u2009' + $2], // adding a thin whitespaces in initials and reductions
			fixWhspsBeforeSentences: [/(\.)(?=[a-zа-яё][^.])/gi, '$1 '], // adding whitespace before each sentence in the given text
			fixWhspsAfterMarks1: [/([!?])(?=[^!?”» ])/g, '$1 '], // adding single whitespace after single ore more question or exclamation marks
			fixCopyright: [/\([c?]\)/gi, '\u00A9'], // inserting real copyright symbol
			fixTradeMark: [/\(r\)/gi, '\u00AE'], // inserting real trade mark symbol
			fixTextFirstChar: [/^([a-zа-яё])/, (s, $1) => $1.toUpperCase()], // capitalize first letter in the text
			fixSentenceFirstChar: [/([.?!])(\s?)([a-zа-яё])(?=[a-zа-яё])/g, (s, $1, $2, $3) => $1 + $2 + $3.toUpperCase()], // capitalize sentence first letter
		};

	Object.freeze(TYPO_PATTERNS);

	var propVal;

	function fixText(txt) {
		Object.keys(TYPO_PATTERNS).forEach(function (key) {
			propVal = TYPO_PATTERNS[key];
			txt = txt.replace(propVal[0], propVal[1]);
		});

		return txt;
	}

	/**
	 *	@exports
	 */
	 return {
		 fixText: fixText
	 };
});<commit_msg>Hot fix to regexp base.<commit_after>define(function () {
	'use strict';

	// TODO
	var is_eng = false;

	var TYPO_PATTERNS = {
			fixManyWhsps: [/[ \t]+/g, ' '], // replace unnecessary whitespace sequences with one whitespace
			fixWhspsInDots: [/\.\s\.\s\.|(\.){4,}/g, '...'], // remove whitespaces between dots or replace more than three dots with three ones
			fixWhspsInMarks: [/(\?|!) (?=\?|!)/g, '$1'], // remove whitespaces between question and exclamation marks
			fixMore3Marks: [/[!?]{4,}/g, s => s.slice(0, 3)], // replace three or more question or exclamation marks with three ones
			fixHyphenDash0: [/\s-(\s)/g, '\u00A0\u2014$1'], // replace hyphen with a dash with non-breaking space before
			fixHyphenDash1: [/^-(\s)/gm, '\u2014$1'], // replace hyphen with a dash at the beginning of each line
			fixLeftQuotes: [/(^|\s)"/g, (s, $1) => $1 + (is_eng ? '“' : '«')], // replace left-side double quotes
			fixRightQuotes: [/"(\s|[-.,:;?!]|$)/g, (s, $1) => (is_eng ? '”' : '»') + $1], // replace right-side double quotes
			fixWhspsAfterMarks0: [/([,:;])(?=[^ ])/gi, '$1 '], // adding single whitespace after comma, colon and semicolon
			fixThinWhsps: [/( [a-zа-яё]\.)\s?([a-zа-яё]\.)/gi, (s, $1, $2) => $1 + '\u2009' + $2], // adding a thin whitespaces in initials and reductions
			fixWhspsBeforeSentences: [/(\.)(?=[a-zа-яё][^.])/gi, '$1 '], // adding whitespace before each sentence in the given text
			fixWhspsAfterMarks1: [/([!?])(?=[^!?”» ])/g, '$1 '], // adding single whitespace after single ore more question or exclamation marks
			fixCopyright: [/\([c?]\)/gi, '\u00A9'], // inserting real copyright symbol
			fixTradeMark: [/\(r\)/gi, '\u00AE'], // inserting real trade mark symbol
			fixTextFirstChar: [/^([a-zа-яё])/, (s, $1) => $1.toUpperCase()], // capitalize first letter in the text
			fixSentenceFirstChar: [/([.?!])(\s?)([a-zа-яё])(?=[a-zа-яё])/g, (s, $1, $2, $3) => $1 + $2 + $3.toUpperCase()], // capitalize sentence first letter
		};

	Object.freeze(TYPO_PATTERNS);

	var propVal;

	function fixText(txt) {
		Object.keys(TYPO_PATTERNS).forEach(function (key) {
			propVal = TYPO_PATTERNS[key];
			txt = txt.replace(propVal[0], propVal[1]);
		});

		return txt;
	}

	/**
	 *	@exports
	 */
	 return {
		 fixText: fixText
	 };
});<|endoftext|>


<commit_before>'use strict'

module.exports = {}<commit_msg>message<commit_after>'use strict';

var util = require('@tencent/fns')
var outdatedMsgs = {}

function Message () {
    this._evtObjs = {};
}
Message.prototype.on = function (evtType, handler, _once) {
    if (!this._evtObjs[evtType]) {
        this._evtObjs[evtType] = [];
    }
    this._evtObjs[evtType].push({
        handler: handler,
        once: _once
    })
    var that = this
    return function () {
        that.off(evtType, handler)
    }
}
Message.prototype.wait = function (evtType, handler) {
    if (outdatedMsgs[evtType]) {
        handler.apply(null, outdatedMsgs[evtType])
        return noop
    } else {
        // call once
        return this.on(evtType, handler, true)
    }
}
Message.prototype.off = function (evtType, handler) {
    var that = this
    var types;
    if (evtType) {
        types = [evtType];
    } else {
        types = util.keys(this._evtObjs)
    }
    util.forEach(types, function (type) {
        if (!handler) {
            // remove all
            that._evtObjs[type] = [];
        } else {
            var handlers = that._evtObjs[type] || [],
                nextHandlers = [];

            util.forEach(handlers, function (evtObj) {
                if (evtObj.handler !== handler) {
                    nextHandlers.push(evtObj)
                }
            })
            that._evtObjs[type] = nextHandlers;
        }
    })

    return this;
}
Message.prototype.emit = function (evtType) {
    var args = Array.prototype.slice.call(arguments, 1)

    outdatedMsgs[evtType] = args
    var handlers = this._evtObjs[evtType] || [];
    util.forEach(handlers, function (evtObj) {
        if (evtObj.once && evtObj.called) return
        evtObj.called = true
        evtObj.handler && evtObj.handler.apply(null, args);
    })
}

/**
 *  Global Message Central
 **/
var msg = new Message();
Message.on = function () {
    return msg.on.apply(msg, arguments);
}
Message.off = function () {
    return msg.off.apply(msg, arguments);
}
Message.emit = function () {
    return msg.emit.apply(msg, arguments);
}
Message.wait = function () {
    return msg.wait.apply(msg, arguments);
}
function noop(){}

module.exports = Message;<|endoftext|>


<commit_before>// Features

var Feature = Backbone.Model.extend({});

var FeatureList = Backbone.Collection.extend({});

var FeatureItemView = Backbone.View.extend({

  className: 'feature-item draggable',

  attributes: function() {
    return {
      id: this.model.id,
      'data-name': this.model.get('name'),
      'data-description': this.model.get('description'),
      'data-type': this.model.get('type'),
      'data-targets': '[' + this.model.get('targets') + ']',
    }
  },

  initialize: function() {
    this.model.on({
      'hide': function() { this.$el.hide(); },
      'show': function() { this.$el.show(); },
    }, this);
  },

  render: function() {
    this.$el.text(this.model.get('name'));
    this.$el.draggable({
      helper: 'clone',
      revert: 'invalid',
    });
    return this;
  }

});

var FeatureListView = Backbone.View.extend({

  render: function() {
    this.$el.empty();
    this.collection.forEach(this._addFeatureItem, this);
    return this;
  },

  _addFeatureItem: function(featureItem) {
    var featureItemView = new FeatureItemView({ model: featureItem });
    this.$el.append(featureItemView.render().$el);
  },

  events: {
    'mouseenter .feature-item': '_highlight',
    'mouseleave .feature-item': '_unhighlight',
  },

  _highlight: function(e) {
    $(e.currentTarget).addClass('highlighted');
  },

  _unhighlight: function(e) {
    $(e.currentTarget).removeClass('highlighted');
  },

  filterItems: function(input) {
    this.collection.each(function(i) {
      if (!$.matches(i.get('name').toLowerCase(), input)) {
        i.trigger('hide');
      } else {
        i.trigger('show');
      }
    });
  },

});

// Rules

var Rule = Backbone.Model.extend({

  initialize: function() {
    this.urlRoot = '/rules';
  },

  _update: function(field, attrs, success) {
    this.save(attrs,
              { url: this.url() + '/' + field,
                wait: true,
                success: success,
                error: function(model, xhr, options) {
                  var response = $.parseJSON(xhr.responseText);
                  model.trigger('update-error:' + field, response.message);
                },
              });
  },

  updateName: function(newName) {
    var success = function(model, response, options) {
      model.id = newName;
    };
    this._update('name', { name: newName }, success);
  },

  updateDescription: function(newDescription) {
    var success = function(model, response, options) {};
    this._update('description', { description: newDescription }, success);
  },

});

var RuleView = Backbone.View.extend({

  initialize: function() {
    this.model.on({
      'change:name': function() {
        this._updateURL();
      },
      'change:description': function() {
        this._removeEditControls('description');
        this._renderDescription();
      },
      'update-error:name': function(msg) {
        this._renderAlert('button.name', msg);
      },
      'update-error:description': function(msg) {
        this._renderAlert('button.description', msg);
      },
    }, this);
  },

  render: function() {
    this.$el.empty();
    this.$el.append($.h3('').attr('id', 'rule-name'));
    this.$el.append($.p('').attr('id', 'rule-description'));
    this._renderName();
    this._renderDescription();
    this._renderLHS();
    return this;
  },

  _renderName: function() {
    this.$('#rule-name').text('@' + this.model.get('name'));
  },

  _renderDescription: function() {
    this.$('#rule-description').text(this.model.get('description'));
  },

  _renderLHS: function() {
    var lhsView = new AVMView({ collection: this.model.get('lhs') });
    this.$el.append(lhsView.render().$el);
    lhsView.trigger('inserted');
  },

  _updateURL: function() {
    window.location.replace(this.model.url() + '/input');
  },

  _renderAlert: function(button, msg) {
    var updateButton = this.$(button);
    updateButton.next('.alert-msg').remove();
    $.alertMsg(msg).insertAfter(updateButton);
  },

  events: {
    'dblclick #rule-name': function(e) {
      this._renderEditControls('name')(e)
    },
    'click button.name': function() {
      this._saveEdits('name')(this)
    },
    'dblclick #rule-description': function(e) {
      this._renderEditControls('description')(e)
    },
    'click button.description': function() {
      this._saveEdits('description')(this)
    },
  },

  _renderEditControls: function(modelField) {
    return function(e) {
      var fieldToEdit = $(e.currentTarget);
      var currentValue = fieldToEdit.text();
      if (modelField === 'name') {
        currentValue = currentValue.substring(1);
      }
      var inputField = $.textInput().addClass(modelField)
        .val(currentValue);
      var okButton = $.okButton().addClass(modelField);
      fieldToEdit.hide();
      inputField.insertAfter(fieldToEdit);
      okButton.insertAfter(inputField);
      inputField.focus();
    };
  },

  _saveEdits: function(modelField) {
    return function(view) {
      var inputField = view.$('input.' + modelField);
      if (!inputField.isEmpty() &&
          inputField.val() !== view.model.get(modelField)) {
        var updateFunction = 'update' + $.cap(modelField);
        view.model[updateFunction](inputField.val());
      } else {
        view._removeEditControls(modelField);
        var renderFunction = '_render' + $.cap(modelField);
        view[renderFunction]();
      }
    };
  },

  _removeEditControls: function(modelField) {
    this.$('.' + modelField).remove();
    this.$('.alert-msg').remove();
    this.$('#rule-' + modelField).show();
  },

});

// AVMs: models

// ...

// AVMs: views

var AVMView = Backbone.View.extend({

  // ...

  initialize: function() {
    // ...
    this.on({
      // ...
      'remove:pair': function(pair) {
        this.collection.remove(pair);
        this.trigger('update');
      },
    }, this);
  },

  // ...

  render: function() {
    this.$el.empty();
    // ...
  },

  // ...

  events: {
    // ...
    'click .empty-button': function() {
      this.collection.reset();
      this.render();
      this.trigger('re-rendered');
    },
  },

  // ...

});

var PairView = Backbone.View.extend({

  // ...

  events: {
    // ...
    'click .remove-button': function() {
      this.remove();
      this.parentView.trigger('remove:pair', this.model);
    },
  },

});

var AVM = Backbone.Collection.extend({

  initialize: function(models, options) {
    this.ruleName = options.ruleName;
    this.uuid = options.json.uuid;
    this.accept = options.accept || '.feature-item';
    var avm = this;
    _.each(options.json.pairs, (function(pair) {
      avm.add(new Pair(null, { parent: avm,
                               attribute: pair.attribute,
                               value: pair.value }));
    }));
  },

});

var Pair = Backbone.Model.extend({

  initialize: function(attrs, options) {
    this.parent = options.parent;
    this.set('attribute', new Feature({
      name: options.attribute.name,
      type: options.attribute.type,
      targets: options.attribute.targets
    }));
    if (options.value) {
      this._setValue(options.value);
    }
  },

  _setValue: function(value) {
    if (typeof value === 'string') {
      this.set('value', value);
    } else {
      var accept = '#' + this.get('attribute').get('targets').join(', #');
      this.set('value', new AVM(null, { ruleName: this.parent.ruleName,
                                        accept: accept,
                                        json: value }));
    }
  },

  create: function() {
    var pair = this;
    var success = function(model, response, options) {
      pair._setValue(model.get('value'));
      pair.parent.add(pair);
    };
    this.save({ uuid: this.parent.uuid },
              { url: '/rules/' + this.parent.ruleName + '/input',
                wait: true,
                success: success });
  },

});

var AVMView = Backbone.View.extend({

  className: 'avm',

  attributes: function() {
    return {
      id: this.collection.uuid,
    }
  },

  initialize: function(options) {
    this.parentView = options.parentView;
    if (this.parentView) {
      this.parentView.on({
        'inserted': function() {
          this.trigger('inserted');
        },
      }, this);
    }
    this.on({
      'inserted': function() {
        this.trigger('rendered');
        this._removeBrackets();
        this._renderBrackets();
      },
      'update': function() {
        this._removeBrackets();
        this._renderBrackets();
        this.trigger('re-rendered');
      },
    }, this);
    this.collection.on({
      'add': function(pair) {
        this._renderPair(pair);
        this.trigger('update');
      },
    }, this);
  },

  render: function() {
    this._renderContent();
    this._renderEmptyButton();
    return this;
  },

  _renderBrackets: function() {
    var leftBracket = this._makeBracket('left');
    var rightBracket = this._makeBracket('right');
    var h = this.$el.children('.content').height();
    leftBracket.insertBefore(this.$el.children('.content'));
    rightBracket.insertAfter(this.$el.children('.content'));
    leftBracket.height(h);
    rightBracket.height(h);
  },

  _makeBracket: function(type) {
    return $.div('bracket bracket-' + type);
  },

  _removeBrackets: function() {
    this.$el.children('.bracket').remove();
  },

  _renderPair: function(pair) {
    var placeholder = this.$el.children('.content').children('.placeholder');
    this._makePair(pair).insertBefore(placeholder);
    this.trigger('rendered');
  },

  _renderContent: function() {
    var content = $.div('content');
    this.collection.each(function(pair) {
      content.append(this._makePair(pair));
    }, this);
    content.append(this._makePlaceholder());
    this.$el.append(content);
  },

  _makePair: function(pair) {
    return new PairView({ model: pair, parentView: this }).render().$el;
  },

  _makePlaceholder: function() {
    var view = this;
    return $.placeholder('Drop feature here ...')
      .droppable({
        accept: this.collection.accept,
        drop: function(e, ui) {
          var item = $(ui.helper);
          var parent = view.collection;
          var attribute = {
            name: item.data('name'),
            type: item.data('type'),
            targets: item.dataToArray('targets'),
          };
          new Pair(null, { parent: parent, attribute: attribute }).create();
        },
      });
  },

  _renderEmptyButton: function() {
    this.$el.append($.emptyButton().css('visibility', 'hidden'));
  },

  events: {
    'mouseenter': '_showEmptyButton',
    'mouseleave': '_hideEmptyButton',
  },

  _showEmptyButton: function() {
    this.$('.empty-button').css('visibility', 'visible');
  },

  _hideEmptyButton: function() {
    this.$('.empty-button').css('visibility', 'hidden');
  },

});

var PairView = Backbone.View.extend({

  className: 'pair',

  initialize: function(options) {
    this.parentView = options.parentView;
    this.parentView.on({
      'rendered': function() {
        this.trigger('inserted');
      },
    }, this);
  },

  render: function() {
    this._renderAttr();
    this._renderVal();
    return this;
  },

  _renderAttr: function() {
    var name = this.model.get('attribute').get('name');
    var attr = $.span('attribute').text(name);
    attr.append($.removeButton(name).css('visibility', 'hidden'));
    this.$el.append(attr);
  },

  _renderVal: function() {
    if (this.model.get('attribute').get('type') === 'complex') {
      this._renderSubstructure();
    } else {
      this._renderValue();
    }
  },

  _renderSubstructure: function() {
    var value = $.div('value');
    var avmView = new AVMView({ collection: this.model.get('value'),
                                parentView: this });
    value.append(avmView.render().$el);
    this.$el.append(value);
    this.listenTo(avmView,
                  're-rendered',
                  function() { this.parentView.trigger('update') });
  },

  _renderValue: function() {
    var value = $.span('value');
    var selectMenu = $.selectMenu();
    var options = this.model.get('attribute').get('targets');
    _.each(options, function(opt) { selectMenu.append($.option(opt)) });
    selectMenu.val(this.model.get('value'));
    value.append(selectMenu);
    this.$el.append(value);
  },

  events: {
    'mouseenter .attribute': '_showRemoveButton',
    'mouseleave .attribute': '_hideRemoveButton',
  },

  _showRemoveButton: function(e) {
    e.stopPropagation();
    this.$('.remove-button').css('visibility', 'visible');
  },

  _hideRemoveButton: function() {
    this.$('.remove-button').css('visibility', 'hidden');
  },

});

// Application

$(document).ready(function() {

  // "Features" sidebar

  var featureItems = $('.feature-item');

  var featureList = new FeatureList(
    _.map(featureItems, function(i) {
      var item = $(i);
      var name = item.data('name');
      return new Feature({
        id: name,
        name: name,
        type: item.data('type'),
        description: item.data('description'),
        targets: item.dataToArray('targets'),
      });
    }),
    { comparator: 'name' }
  );

  var featureListView = new FeatureListView({
    el: '#feature-list',
    collection: featureList,
  });
  featureListView.render();

  $('#feature-filter').on('keyup', function() {
    var currentInput = $(this).val().toLowerCase();
    featureListView.filterItems(currentInput);
  });

  // Input Builder

  var name = $('#rule-name').text();
  var description = $('#rule-description').text();
  var lhsJSON = $('#rule-lhs').data('json');

  var lhs = new AVM(null, { ruleName: name, json: lhsJSON });

  var rule = new Rule({
    id: name,
    name: name,
    description: description,
    lhs: lhs,
  });

  var ruleView = new RuleView({
    model: rule,
    el: '#interaction-block',
  });
  ruleView.render();

});
<commit_msg>[InputBuilder] Set up client-side code to send appropriate data to the server when user changes value of atomic feature.<commit_after>// Features

var Feature = Backbone.Model.extend({});

var FeatureList = Backbone.Collection.extend({});

var FeatureItemView = Backbone.View.extend({

  className: 'feature-item draggable',

  attributes: function() {
    return {
      id: this.model.id,
      'data-name': this.model.get('name'),
      'data-description': this.model.get('description'),
      'data-type': this.model.get('type'),
      'data-targets': '[' + this.model.get('targets') + ']',
    }
  },

  initialize: function() {
    this.model.on({
      'hide': function() { this.$el.hide(); },
      'show': function() { this.$el.show(); },
    }, this);
  },

  render: function() {
    this.$el.text(this.model.get('name'));
    this.$el.draggable({
      helper: 'clone',
      revert: 'invalid',
    });
    return this;
  }

});

var FeatureListView = Backbone.View.extend({

  render: function() {
    this.$el.empty();
    this.collection.forEach(this._addFeatureItem, this);
    return this;
  },

  _addFeatureItem: function(featureItem) {
    var featureItemView = new FeatureItemView({ model: featureItem });
    this.$el.append(featureItemView.render().$el);
  },

  events: {
    'mouseenter .feature-item': '_highlight',
    'mouseleave .feature-item': '_unhighlight',
  },

  _highlight: function(e) {
    $(e.currentTarget).addClass('highlighted');
  },

  _unhighlight: function(e) {
    $(e.currentTarget).removeClass('highlighted');
  },

  filterItems: function(input) {
    this.collection.each(function(i) {
      if (!$.matches(i.get('name').toLowerCase(), input)) {
        i.trigger('hide');
      } else {
        i.trigger('show');
      }
    });
  },

});

// Rules

var Rule = Backbone.Model.extend({

  initialize: function() {
    this.urlRoot = '/rules';
  },

  _update: function(field, attrs, success) {
    this.save(attrs,
              { url: this.url() + '/' + field,
                wait: true,
                success: success,
                error: function(model, xhr, options) {
                  var response = $.parseJSON(xhr.responseText);
                  model.trigger('update-error:' + field, response.message);
                },
              });
  },

  updateName: function(newName) {
    var success = function(model, response, options) {
      model.id = newName;
    };
    this._update('name', { name: newName }, success);
  },

  updateDescription: function(newDescription) {
    var success = function(model, response, options) {};
    this._update('description', { description: newDescription }, success);
  },

});

var RuleView = Backbone.View.extend({

  initialize: function() {
    this.model.on({
      'change:name': function() {
        this._updateURL();
      },
      'change:description': function() {
        this._removeEditControls('description');
        this._renderDescription();
      },
      'update-error:name': function(msg) {
        this._renderAlert('button.name', msg);
      },
      'update-error:description': function(msg) {
        this._renderAlert('button.description', msg);
      },
    }, this);
  },

  render: function() {
    this.$el.empty();
    this.$el.append($.h3('').attr('id', 'rule-name'));
    this.$el.append($.p('').attr('id', 'rule-description'));
    this._renderName();
    this._renderDescription();
    this._renderLHS();
    return this;
  },

  _renderName: function() {
    this.$('#rule-name').text('@' + this.model.get('name'));
  },

  _renderDescription: function() {
    this.$('#rule-description').text(this.model.get('description'));
  },

  _renderLHS: function() {
    var lhsView = new AVMView({ collection: this.model.get('lhs') });
    this.$el.append(lhsView.render().$el);
    lhsView.trigger('inserted');
  },

  _updateURL: function() {
    window.location.replace(this.model.url() + '/input');
  },

  _renderAlert: function(button, msg) {
    var updateButton = this.$(button);
    updateButton.next('.alert-msg').remove();
    $.alertMsg(msg).insertAfter(updateButton);
  },

  events: {
    'dblclick #rule-name': function(e) {
      this._renderEditControls('name')(e)
    },
    'click button.name': function() {
      this._saveEdits('name')(this)
    },
    'dblclick #rule-description': function(e) {
      this._renderEditControls('description')(e)
    },
    'click button.description': function() {
      this._saveEdits('description')(this)
    },
  },

  _renderEditControls: function(modelField) {
    return function(e) {
      var fieldToEdit = $(e.currentTarget);
      var currentValue = fieldToEdit.text();
      if (modelField === 'name') {
        currentValue = currentValue.substring(1);
      }
      var inputField = $.textInput().addClass(modelField)
        .val(currentValue);
      var okButton = $.okButton().addClass(modelField);
      fieldToEdit.hide();
      inputField.insertAfter(fieldToEdit);
      okButton.insertAfter(inputField);
      inputField.focus();
    };
  },

  _saveEdits: function(modelField) {
    return function(view) {
      var inputField = view.$('input.' + modelField);
      if (!inputField.isEmpty() &&
          inputField.val() !== view.model.get(modelField)) {
        var updateFunction = 'update' + $.cap(modelField);
        view.model[updateFunction](inputField.val());
      } else {
        view._removeEditControls(modelField);
        var renderFunction = '_render' + $.cap(modelField);
        view[renderFunction]();
      }
    };
  },

  _removeEditControls: function(modelField) {
    this.$('.' + modelField).remove();
    this.$('.alert-msg').remove();
    this.$('#rule-' + modelField).show();
  },

});

// AVMs: models

// ...

// AVMs: views

var AVMView = Backbone.View.extend({

  // ...

  initialize: function() {
    // ...
    this.on({
      // ...
      'remove:pair': function(pair) {
        this.collection.remove(pair);
        this.trigger('update');
      },
    }, this);
  },

  // ...

  render: function() {
    this.$el.empty();
    // ...
  },

  // ...

  events: {
    // ...
    'click .empty-button': function() {
      this.collection.reset();
      this.render();
      this.trigger('re-rendered');
    },
  },

  // ...

});

var PairView = Backbone.View.extend({

  // ...

  events: {
    // ...
    'click .remove-button': function() {
      this.remove();
      this.parentView.trigger('remove:pair', this.model);
    },
  },

});

var AVM = Backbone.Collection.extend({

  initialize: function(models, options) {
    this.ruleName = options.ruleName;
    this.uuid = options.json.uuid;
    this.accept = options.accept || '.feature-item';
    var avm = this;
    _.each(options.json.pairs, (function(pair) {
      avm.add(new Pair(null, { parent: avm,
                               attribute: pair.attribute,
                               value: pair.value }));
    }));
  },

});

var Pair = Backbone.Model.extend({

  initialize: function(attrs, options) {
    this.parent = options.parent;
    this.set('attribute', new Feature({
      name: options.attribute.name,
      type: options.attribute.type,
      targets: options.attribute.targets
    }));
    if (options.value) {
      this._setValue(options.value);
    }
  },

  _setValue: function(value) {
    if (typeof value === 'string') {
      this.set('value', value);
    } else {
      var accept = '#' + this.get('attribute').get('targets').join(', #');
      this.set('value', new AVM(null, { ruleName: this.parent.ruleName,
                                        accept: accept,
                                        json: value }));
    }
  },

  create: function() {
    var pair = this;
    var success = function(model, response, options) {
      pair._setValue(model.get('value'));
      pair.parent.add(pair);
    };
    this.save({ uuid: this.parent.uuid },
              { url: '/rules/' + this.parent.ruleName + '/input',
                wait: true,
                success: success });
  },

  updateValue: function(newValue) {
    this.save({ uuid: this.parent.uuid,
                newValue: newValue },
              { url: '/rules/' + this.parent.ruleName + '/input',
                type: 'PUT',
                wait: true });
  },

});

var AVMView = Backbone.View.extend({

  className: 'avm',

  attributes: function() {
    return {
      id: this.collection.uuid,
    }
  },

  initialize: function(options) {
    this.parentView = options.parentView;
    if (this.parentView) {
      this.parentView.on({
        'inserted': function() {
          this.trigger('inserted');
        },
      }, this);
    }
    this.on({
      'inserted': function() {
        this.trigger('rendered');
        this._removeBrackets();
        this._renderBrackets();
      },
      'update': function() {
        this._removeBrackets();
        this._renderBrackets();
        this.trigger('re-rendered');
      },
    }, this);
    this.collection.on({
      'add': function(pair) {
        this._renderPair(pair);
        this.trigger('update');
      },
    }, this);
  },

  render: function() {
    this._renderContent();
    this._renderEmptyButton();
    return this;
  },

  _renderBrackets: function() {
    var leftBracket = this._makeBracket('left');
    var rightBracket = this._makeBracket('right');
    var h = this.$el.children('.content').height();
    leftBracket.insertBefore(this.$el.children('.content'));
    rightBracket.insertAfter(this.$el.children('.content'));
    leftBracket.height(h);
    rightBracket.height(h);
  },

  _makeBracket: function(type) {
    return $.div('bracket bracket-' + type);
  },

  _removeBrackets: function() {
    this.$el.children('.bracket').remove();
  },

  _renderPair: function(pair) {
    var placeholder = this.$el.children('.content').children('.placeholder');
    this._makePair(pair).insertBefore(placeholder);
    this.trigger('rendered');
  },

  _renderContent: function() {
    var content = $.div('content');
    this.collection.each(function(pair) {
      content.append(this._makePair(pair));
    }, this);
    content.append(this._makePlaceholder());
    this.$el.append(content);
  },

  _makePair: function(pair) {
    return new PairView({ model: pair, parentView: this }).render().$el;
  },

  _makePlaceholder: function() {
    var view = this;
    return $.placeholder('Drop feature here ...')
      .droppable({
        accept: this.collection.accept,
        drop: function(e, ui) {
          var item = $(ui.helper);
          var parent = view.collection;
          var attribute = {
            name: item.data('name'),
            type: item.data('type'),
            targets: item.dataToArray('targets'),
          };
          new Pair(null, { parent: parent, attribute: attribute }).create();
        },
      });
  },

  _renderEmptyButton: function() {
    this.$el.append($.emptyButton().css('visibility', 'hidden'));
  },

  events: {
    'mouseenter': '_showEmptyButton',
    'mouseleave': '_hideEmptyButton',
  },

  _showEmptyButton: function() {
    this.$('.empty-button').css('visibility', 'visible');
  },

  _hideEmptyButton: function() {
    this.$('.empty-button').css('visibility', 'hidden');
  },

});

var PairView = Backbone.View.extend({

  className: 'pair',

  initialize: function(options) {
    this.parentView = options.parentView;
    this.parentView.on({
      'rendered': function() {
        this.trigger('inserted');
      },
    }, this);
  },

  render: function() {
    this._renderAttr();
    this._renderVal();
    return this;
  },

  _renderAttr: function() {
    var name = this.model.get('attribute').get('name');
    var attr = $.span('attribute').text(name);
    attr.append($.removeButton(name).css('visibility', 'hidden'));
    this.$el.append(attr);
  },

  _renderVal: function() {
    if (this.model.get('attribute').get('type') === 'complex') {
      this._renderSubstructure();
    } else {
      this._renderValue();
    }
  },

  _renderSubstructure: function() {
    var value = $.div('value');
    var avmView = new AVMView({ collection: this.model.get('value'),
                                parentView: this });
    value.append(avmView.render().$el);
    this.$el.append(value);
    this.listenTo(avmView,
                  're-rendered',
                  function() { this.parentView.trigger('update') });
  },

  _renderValue: function() {
    var value = $.span('value');
    var selectMenu = $.selectMenu();
    var options = this.model.get('attribute').get('targets');
    _.each(options, function(opt) { selectMenu.append($.option(opt)) });
    selectMenu.val(this.model.get('value'));
    value.append(selectMenu);
    this.$el.append(value);
  },

  events: {
    'mouseenter .attribute': '_showRemoveButton',
    'mouseleave .attribute': '_hideRemoveButton',
    'change .value > select': '_changeValue',
  },

  _showRemoveButton: function(e) {
    e.stopPropagation();
    this.$('.remove-button').css('visibility', 'visible');
  },

  _hideRemoveButton: function() {
    this.$('.remove-button').css('visibility', 'hidden');
  },

  _changeValue: function(e) {
    var newValue = $(e.currentTarget).val();
    this.model.updateValue(newValue);
  },

});

// Application

$(document).ready(function() {

  // "Features" sidebar

  var featureItems = $('.feature-item');

  var featureList = new FeatureList(
    _.map(featureItems, function(i) {
      var item = $(i);
      var name = item.data('name');
      return new Feature({
        id: name,
        name: name,
        type: item.data('type'),
        description: item.data('description'),
        targets: item.dataToArray('targets'),
      });
    }),
    { comparator: 'name' }
  );

  var featureListView = new FeatureListView({
    el: '#feature-list',
    collection: featureList,
  });
  featureListView.render();

  $('#feature-filter').on('keyup', function() {
    var currentInput = $(this).val().toLowerCase();
    featureListView.filterItems(currentInput);
  });

  // Input Builder

  var name = $('#rule-name').text();
  var description = $('#rule-description').text();
  var lhsJSON = $('#rule-lhs').data('json');

  var lhs = new AVM(null, { ruleName: name, json: lhsJSON });

  var rule = new Rule({
    id: name,
    name: name,
    description: description,
    lhs: lhs,
  });

  var ruleView = new RuleView({
    model: rule,
    el: '#interaction-block',
  });
  ruleView.render();

});
<|endoftext|>


<commit_before>define([
	'gizmo/superdesk',
	'livedesk-embed/collections/autocollection',
	'livedesk-embed/models/Post'
], function(Gizmo) {
	return Gizmo.Register.AutoCollection.extend({
		parse: function(data){
			if(data.total !== undefined) {
				data.total = parseInt(data.total);
				this.listTotal = data.total;
				delete data.total;
			}
			if(data.PostList)
				return data.PostList;
			return data;
		},
		model: Gizmo.Register.Post
	},{ register: 'Posts' });
});<commit_msg>Linux issues start-sources.sh still has a bug with compoments Posts request now post resouce instead of Post<commit_after>define([
	'gizmo/superdesk',
	'livedesk-embed/collections/autocollection',
	'livedesk-embed/models/post'
], function(Gizmo) {
	return Gizmo.Register.AutoCollection.extend({
		parse: function(data){
			if(data.total !== undefined) {
				data.total = parseInt(data.total);
				this.listTotal = data.total;
				delete data.total;
			}
			if(data.PostList)
				return data.PostList;
			return data;
		},
		model: Gizmo.Register.Post
	},{ register: 'Posts' });
});<|endoftext|>


<commit_before>$(function() {

  var snorky = new Snorky(SockJS, "/sockjs", {
    "messaging": Snorky.Messaging
  }, true);

  var messaging = snorky.services.messaging;

  $("#frmRegister").submit(function(ev) {
    ev.preventDefault();

    messaging.registerParticipant({
      name: $("#txtParticipantName").val()
    }).then(function() {
      $("#statusRegister").text("Successfully registered");
    }, function(err) {
      $("#statusRegister").text("Register error: " + err.message);
    });
  });

  $("#btnUnregister").click(function() {
    messaging.unregisterParticipant({
      name: $("#txtParticipantName").val()
    }).then(function() {
      $("#statusRegister").text("Successfully unregistered");
    }, function(err) {
      $("#statusRegister").text("Unregister error: " + err.message);
    });
  });

  $("#btnListParticipants").click(function() {
    messaging.listParticipants({}).then(function(participants) {
      $("#ulParticipants").empty();
      $.each(participants, function(i, participant) {
        $("#ulParticipants").append($("<li/>", { text: participant }));
      });
      $("#statusParticipants").text("Participants listed");
    }, function(err) {
      $("#ulParticipants").empty();
      $("#statusParticipants").text("Error: " + err.message);
    });
  });

  $("#frmMessages").submit(function(ev) {
    ev.preventDefault();

    messaging.send({
      sender: $("#txtFrom").val(),
      dest: $("#txtTo").val(),
      body: $("#txtMessage").val()
    }).then(function() {
      $("#statusMessages").text("Successfully sent");
    }, function(err) {
      $("#statusMessages").text("Error: " + err.message);
    });
  });

  messaging.onParticipantMessage = function(sender, dest, body) {
    $("#ulMessages").append($("<li/>", {
      text: sender + " to " + dest + ": " + body
    }));
  };

});
<commit_msg>Make chat demo variables available for debugging<commit_after>var snorky, messaging;

$(function() {

  snorky = new Snorky(SockJS, "/sockjs", {
    "messaging": Snorky.Messaging
  }, true);

  messaging = snorky.services.messaging;

  $("#frmRegister").submit(function(ev) {
    ev.preventDefault();

    messaging.registerParticipant({
      name: $("#txtParticipantName").val()
    }).then(function() {
      $("#statusRegister").text("Successfully registered");
    }, function(err) {
      $("#statusRegister").text("Register error: " + err.message);
    });
  });

  $("#btnUnregister").click(function() {
    messaging.unregisterParticipant({
      name: $("#txtParticipantName").val()
    }).then(function() {
      $("#statusRegister").text("Successfully unregistered");
    }, function(err) {
      $("#statusRegister").text("Unregister error: " + err.message);
    });
  });

  $("#btnListParticipants").click(function() {
    messaging.listParticipants({}).then(function(participants) {
      $("#ulParticipants").empty();
      $.each(participants, function(i, participant) {
        $("#ulParticipants").append($("<li/>", { text: participant }));
      });
      $("#statusParticipants").text("Participants listed");
    }, function(err) {
      $("#ulParticipants").empty();
      $("#statusParticipants").text("Error: " + err.message);
    });
  });

  $("#frmMessages").submit(function(ev) {
    ev.preventDefault();

    messaging.send({
      sender: $("#txtFrom").val(),
      dest: $("#txtTo").val(),
      body: $("#txtMessage").val()
    }).then(function() {
      $("#statusMessages").text("Successfully sent");
    }, function(err) {
      $("#statusMessages").text("Error: " + err.message);
    });
  });

  messaging.onParticipantMessage = function(sender, dest, body) {
    $("#ulMessages").append($("<li/>", {
      text: sender + " to " + dest + ": " + body
    }));
  };

});
<|endoftext|>