<commit_before>var db = require('./frederickNorthDBRaw');

exports.connect = function(after) {
  db.connect(after);
}

exports.getWatching = function(googleId, after, leaflet) {
  console.log("Getting Watching for %s", googleId);
  db.Person.find({ GOOGLE_ID: googleId }, function (err, person) {
    if (err) {
      console.error("Error finding person");
      return after (err, null);
    }
    else if (person.length == 0) {
      return after ("No people found for " + googleId);
    }
    else {
      console.log("Found matching people %d", person.length);
      console.log("The person[0].ID = %s", person[0].ID);
      db.BoundedArea.find({ OWNER: person[0].ID }).where("PARENT IS NULL",
      function(err, boundedAreas) {
        console.log("Found %d BoundedAreas", boundedAreas.length);
        if (err) {
          return after(err, null);
        }
        return fillBoundedArea(boundedAreas, 0, function(err) {
          console.log("Executing final piece which should involve rendering the page");
          fillRouteSizes(boundedAreas, function(err) {
            if (leaflet) {
              return addLeafletMaps(boundedAreas, leaflet, after)
            }
            after(err, boundedAreas);
          });
        });
      });
    }
  });
}

addLeafletMaps = function(boundedAreas, leaflet, after) {
  after(null, boundedAreas);
}

exports.getLeaflets = function(googleId, after) {
  exports.getWatching(googleId, function(err, boundedAreas) {
    var routeIds = getRouteIds(boundedAreas, []);
    db.LeafletMap.aggregate(["LEAFLET"], {ROUTE: routeIds}).count().groupBy("LEAFLET").get(
      function(err, counts) {
        if (err) {
          return after(err);
        }
        var leaflets = [];
        for (var index = 0; index < counts.length; index++) {
          leaflets.push(counts[index].LEAFLET);
        }
        db.Leaflet.find({ID: leaflets}, after);
      });
  });
}

function fillRouteSizes(boundedAreas, after) {
  var routeIds = getRouteIds(boundedAreas, []);
  db.RouteMember.aggregate(["ROUTE"], {ROUTE: routeIds}).count().groupBy("ROUTE").get(
    function (err, stats) {
      if (err) {
        return after(err);
      }
      var routeSizes = [];
      for (var index = 0; index < stats.length; index++) {
        var stat = stats[index];
        routeSizes[stat.ROUTE] = stat.count;
      }
      matchRouteSizes(boundedAreas, routeSizes);
      after(err)
    });
}

function matchRouteSizes(boundedAreas, routeSizes) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      var route = boundedArea.routes[routeIndex];
      route.size = routeSizes[route.ID];
    }
    matchRouteSizes(boundedArea.children, routeSizes);
  }
}

function getRouteIds(boundedAreas, routeIds) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      routeIds.push(boundedArea.routes[routeIndex].ID);
    }
    getRouteIds(boundedArea.children, routeIds);
  }
  return routeIds
}

function fillBoundedArea(boundedAreas, index, after, err) {
  if (boundedAreas.length == index) {
    console.log("Ended with index: %d", index);
    return after(err);
  }
  console.log("BoundedArea: %d", index);
  boundedAreas[index].getRoutes(function(err, routes) {
    boundedAreas[index].routes = routes;
    boundedAreas[index].getChildren(function(err, children) {
      if (err) {
        return after(err);
      }
      console.log("%s has %d children", boundedAreas[index].NAME, children.length);
      boundedAreas[index].children = children;
      return fillBoundedArea(children, 0, function(err) {
        return fillBoundedArea(boundedAreas, index + 1, after, err);
      });
    });
  });
}
<commit_msg>First attempt at adding leaflet maps to the routes to allow progress to be reported<commit_after>var db = require('./frederickNorthDBRaw');

exports.connect = function(after) {
  db.connect(after);
}

exports.getWatching = function(googleId, after, leafletId) {
  console.log("Getting Watching for %s", googleId);
  db.Person.find({ GOOGLE_ID: googleId }, function (err, person) {
    if (err) {
      console.error("Error finding person");
      return after (err, null);
    }
    else if (person.length == 0) {
      return after ("No people found for " + googleId);
    }
    else {
      console.log("Found matching people %d", person.length);
      console.log("The person[0].ID = %s", person[0].ID);
      db.BoundedArea.find({ OWNER: person[0].ID }).where("PARENT IS NULL",
      function(err, boundedAreas) {
        console.log("Found %d BoundedAreas", boundedAreas.length);
        if (err) {
          return after(err, null);
        }
        return fillBoundedArea(boundedAreas, 0, function(err) {
          console.log("Executing final piece which should involve rendering the page");
          fillRouteSizes(boundedAreas, function(err) {
            if (leafletId) {
              return addLeafletMaps(boundedAreas, leafletId, after)
            }
            after(err, boundedAreas);
          });
        });
      });
    }
  });
}

addLeafletMaps = function(boundedAreas, leafletId, after) {
  var routeIds = getRouteIds(boundedAreas. []);
  db.LeafletMap.find({ROUTE: routeIds, LEAFLET: leafletId}, function(err, leafletMaps) {
    var leafletMapsByRouteMap = leafletMapsAsMap(leafletMaps);
    for (var index = 0; index < boundedAreas.length; index++) {
      matchLeafletMaps(boundedAreas[index], leafletMapsByRouteMap);
    }
    after(null, boundedAreas);
  });
}

function matchLeafletMaps(boundedArea, leafletMapByRoute) {
  var deliveryStatus = {complete: 0, remaining: 0};
  for (var index = 0; index < boundedArea.children.length; index++) {
    var childDeliveryStatus = matchLeafletMaps(boundedArea, leafletMapByRoute);
    if (childDeliveryStatus.complete + childDeliveryStatus.remaining == 0) {
      boundedArea.children.splice(index--,1);
    }
    else {
      deliveryStatus.complete += childDeliveryStatus.complete;
      deliveryStatus.remaining += childDeliveryStatus.remaining;
    }
  }
  for (var index = 0; index < boundedArea.routes.length; index++) {
    var route = boundedArea.routes[index];
    var leafletMap = leafletMapByRoute[route.ID];
    if (leafletMap) {
      if (leafletMap.DELIVERED) {
        deliveryStatus.complete += route.size;
      }
      else {
        deliveryStatus.remaining += route.size;
      }
      route.leafletMap = leafletMap;
    }
    else {
      boundedArea.routes.splice(index--, 1);
    }
  }
  return deliveryStatus;
}

function leafletMapsAsMap(leafletMaps) {
  var map = [];
  for (var index = 0; index < leafletMaps.length; index++) {
    var leafletMap = leafletMaps[index];
    map[leafletMap.ROUTE] = leafletMap;
  }
  return map;
}

exports.getLeaflets = function(googleId, after) {
  exports.getWatching(googleId, function(err, boundedAreas) {
    var routeIds = getRouteIds(boundedAreas, []);
    db.LeafletMap.aggregate(["LEAFLET"], {ROUTE: routeIds}).count().groupBy("LEAFLET").get(
      function(err, counts) {
        if (err) {
          return after(err);
        }
        var leaflets = [];
        for (var index = 0; index < counts.length; index++) {
          leaflets.push(counts[index].LEAFLET);
        }
        db.Leaflet.find({ID: leaflets}, after);
      });
  });
}

function fillRouteSizes(boundedAreas, after) {
  var routeIds = getRouteIds(boundedAreas, []);
  db.RouteMember.aggregate(["ROUTE"], {ROUTE: routeIds}).count().groupBy("ROUTE").get(
    function (err, stats) {
      if (err) {
        return after(err);
      }
      var routeSizes = [];
      for (var index = 0; index < stats.length; index++) {
        var stat = stats[index];
        routeSizes[stat.ROUTE] = stat.count;
      }
      matchRouteSizes(boundedAreas, routeSizes);
      after(err)
    });
}

function matchRouteSizes(boundedAreas, routeSizes) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      var route = boundedArea.routes[routeIndex];
      route.size = routeSizes[route.ID];
    }
    matchRouteSizes(boundedArea.children, routeSizes);
  }
}

function getRouteIds(boundedAreas, routeIds) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      routeIds.push(boundedArea.routes[routeIndex].ID);
    }
    getRouteIds(boundedArea.children, routeIds);
  }
  return routeIds
}

function fillBoundedArea(boundedAreas, index, after, err) {
  if (boundedAreas.length == index) {
    console.log("Ended with index: %d", index);
    return after(err);
  }
  console.log("BoundedArea: %d", index);
  boundedAreas[index].getRoutes(function(err, routes) {
    boundedAreas[index].routes = routes;
    boundedAreas[index].getChildren(function(err, children) {
      if (err) {
        return after(err);
      }
      console.log("%s has %d children", boundedAreas[index].NAME, children.length);
      boundedAreas[index].children = children;
      return fillBoundedArea(children, 0, function(err) {
        return fillBoundedArea(boundedAreas, index + 1, after, err);
      });
    });
  });
}
<|endoftext|>


<commit_before>/*
 * The SerGIS Project - sergis-client
 *
 * This is a SerGIS Client Frontend file for the ArcGIS API.
 * For more on SerGIS Frontends, see:
 * http://sergisproject.github.io/docs/client.html#frontends
 */

// This is wrapped inside an anonymous, self-executing function to prevent
// variables from leaking into the global scope.
(function () {
    /**
     * Make an event handler for a toolbar "Draw ..." button.
     *
     * @param {string} type - The name of a constant in esri.toolbars.Draw.
     *
     * @return {function}
     */
    var makeDrawHandler = function (type) {
        return (function () {
            gToolbar.activate(esri.toolbars.Draw[type]);
            gMap.hideZoomSlider();
        });
    };

    /**
     * The ArcGIS-specific toolbar buttons.
     *
     * Each item is an object with the following properties:
     *   - label (SerGISContent): The label of the toolbar button,
     *   - tooltip (string): An optional tooltip for the toolbar button,
     *   - action (function): The action of the toolbar button. Can optionally
     *     return a Promise if the action happens asynchronously.
     *
     * @type {Array.<Object>}
     */
    var toolbarButtons = [
        {
            label: {type: "text", value: "Layers"},
            tooltip: "Turn specific map layers on or off",
            action: function () {
                return new Promise(function (resolve, reject) {
                    // ...
                    resolve();
                });
            }
        },
        {
            label: {type: "text", value: "Measure"},
            tooltip: "Measure a distance on the map",
            action: function () {
                return new Promise(function (resolve, reject) {
                    // ...
                    resolve();
                });
            }
        },
        {
            label: {type: "text", value: "Draw Point"},
            tooltip: "Draw a point on the map",
            action: makeDrawHandler("POINT")
        },
        {
            label: {type: "text", value: "Draw Line"},
            tooltip: "Draw a line on the map",
            action: makeDrawHandler("LINE")
        },
        {
            label: {type: "text", value: "Draw Polyline"},
            tooltip: "Draw a polyline on the map",
            action: makeDrawHandler("POLYLINE")
        },
        {
            label: {type: "text", value: "Draw Polygon"},
            tooltip: "Draw a polygon on the map",
            action: makeDrawHandler("POLYGON")
        },
        {
            label: {type: "text", value: "Reset Map"},
            tooltip: "Remove all custom drawings from the map",
            action: function () {
                // This is a bit hackish, calling stuff from sergis.main
                return sergis.main.reinitMap();
            }
        }
    ];

    /** A cache of things that have been "require"d. */
    var api = {};
    /** "global map" */
    var gMap;
    /** "global toolbar" */
    var gToolbar;

    // A reference to parameters about the last thing that we (the user) drew
    var lastDrawn = {
        geometry: null,
        symbol: null,
        graphic: null
    };

    /**
     * Initialize (or re-initialize) the map.
     *
     * @param {Element} mapContainer - The DOM element to stick the map into.
     * @param {SerGISMap} map - The SerGIS JSON Map object to position the map.
     *
     * @return {Promise}
     */
    var initMap = function (mapContainer, map) {
        return new Promise(function (resolve, reject) {
            // Remove all children of mapContainer
            while (mapContainer.firstChild) {
                mapContainer.removeChild(mapContainer.firstChild);
            }
            // Make a sub-container
            var mapElem = document.createElement("div");
            mapElem.id = "map-container-ARCGIS_API";
            mapElem.style.margin = "0";
            mapElem.style.padding = "0";
            mapElem.style.height = "100%";
            mapContainer.appendChild(mapElem);

            // Get all the map information together
            var info = {
                center: [map.longitude, map.latitude],
                zoom: map.zoom
            };
            // Check for any other changes that we need to make
            if (map.frontendInfo && map.frontendInfo.arcgis) {
                if (map.frontendInfo.arcgis.basemap) {
                    info.basemap = map.frontendInfo.arcgis.basemap;
                }
            }
            // Create the map
            gMap = new api.Map("map-container-ARCGIS_API", info);
            gMap.on("load", function (event) {
                // Initialize the drawing ability
                gToolbar = new api.Draw(gMap);
                gToolbar.on("draw-end", function (event) {
                    lastDrawn.geometry = event.geometry;
                    // Make the actual map symbol
                    switch (lastDrawn.geometry.type) {
                        case "point":
                            lastDrawn.symbol = new api.SimpleMarkerSymbol(api.SimpleMarkerSymbol.STYLE_SQUARE, 10, new api.SimpleLineSymbol(api.SimpleLineSymbol.STYLE_SOLID, new api.Color([255,0,0]), 1), new api.Color([0,255,0,0.25]));
                            break;
                        case "polyline":
                            lastDrawn.symbol = new api.SimpleLineSymbol(api.SimpleLineSymbol.STYLE_DASH, new api.Color([255,0,0]), 1);
                            break;
                        case "polygon":
                            lastDrawn.symbol = new api.SimpleFillSymbol(api.SimpleFillSymbol.STYLE_NONE, new api.SimpleLineSymbol(api.SimpleLineSymbol.STYLE_DASHDOT, new api.Color([255,0,0]), 2), new api.Color([255,255,0,0.25]));
                            break;
                    }
                    // Add the symbol to the map
                    lastDrawn.graphic = new api.Graphic(lastDrawn.geometry, lastDrawn.symbol);
                    gMap.graphics.add(lastDrawn.graphic);
                    // Deactivate the drawing and put the zoom slider back
                    gToolbar.deactivate();
                    gMap.showZoomSlider();
                });

                resolve();
            });
        });
    };

    /**
     * A map of ArcGIS code names for different parts of the API, mapped to the
     * name we use when loading them into `api`.
     */
    var toBeRequired = {
        "esri/map": "Map",
        "esri/graphic": "Graphic",
        "esri/Color": "Color",

        "esri/geometry/Geometry": "Geometry",
        "esri/geometry/Point": "Point",
        "esri/geometry/Multipoint": "Multipoint",
        "esri/geometry/Polygon": "Polygon",
        "esri/geometry/Polyline": "Polyline",

        "esri/tasks/GeometryService": "GeometryService",
        "esri/tasks/BufferParameters": "BufferParameters",

        "esri/toolbars/draw": "Draw",

        "esri/symbols/SimpleMarkerSymbol": "SimpleMarkerSymbol",
        "esri/symbols/SimpleLineSymbol": "SimpleLineSymbol",
        "esri/symbols/SimpleFillSymbol": "SimpleFillSymbol"
    };

    /**
     * Require all the stuff that we'll need, if we haven't already.
     *
     * @return {Promise}
     */
    var initRequire = function () {
        return new Promise(function (resolve, reject) {
            var requireArgs = [],
                requireNames = [];
            for (var prop in toBeRequired) {
                if (toBeRequired.hasOwnProperty(prop) && toBeRequired[prop]) {
                    requireArgs.push(prop);
                    requireNames.push(toBeRequired[prop]);
                    // We don't want to require it more than once
                    delete toBeRequired[prop];
                }
            }
            if (requireArgs.length > 0) {
                require(requireArgs, function () {
                    for (var i = 0; i < arguments.length; i++) {
                        api[requireNames[i]] = arguments[i];
                    }
                    resolve();
                });
            } else {
                resolve();
            }
        });
    };

    /**
     * Test function that returns a promise and alerts the arguments passed to the
     * function, then resolves the promise.
     */
    var TEST_FRONTEND_ACTION = function () {
        var args = Array.prototype.slice.call(arguments, 0);
        return new Promise(function (resolve, reject) {
            alert("Doing action with:\n" + JSON.stringify(args));
            resolve();
        });
    }

    /**
     * @namespace
     * @see {@link http://sergisproject.github.io/docs/client.html}
     */
    sergis.frontend = {
        name: "arcgis",

        init: function (mapContainer, map) {
            return new Promise(function (resolve, reject) {
                // Since it's the first time, load everything we need from the ArcGIS API
                initRequire().then(function () {
                    // Initialize the map
                    initMap(mapContainer, map).then(function () {
                        // Resolve with a list of toolbar buttons
                        resolve(toolbarButtons.map(function (button) {
                            return {
                                label: button.label,
                                tooltip: button.tooltip
                            };
                        }));
                    }, reject).catch(sergis.error);
                }, reject).catch(sergis.error);
            });
        },

        reinit: function (mapContainer, map) {
            return new Promise(function (resolve, reject) {
                // Initialize the map
                resolve(initMap(mapContainer, map));
            });
        },

        centerMap: function (map) {
            return new Promise(function (resolve, reject) {
                // Check for any other changes that we need to make first
                // (so it can load crap for them while changing the map zoom)
                if (map.frontendInfo && map.frontendInfo.arcgis) {
                    if (map.frontendInfo.arcgis.basemap) {
                        gMap.setBasemap(map.frontendInfo.arcgis.basemap);
                    }
                }
                // NOTE: This below looks like it returns a Promise... but it doesn't. It's a "Deferred" (damn dojo)
                gMap.centerAndZoom([map.longitude, map.latitude], map.zoom).then(function () {
                    resolve();
                }, reject);
            });
        },

        toolbarAction: function (buttonIndex) {
            return new Promise(function (resolve, reject) {
                if (toolbarButtons[buttonIndex]) {
                    resolve(toolbarButtons[buttonIndex].action());
                } else {
                    reject("Invalid buttonIndex!");
                }
            });
        },

        actions: {
            clearGraphics: function () {
                return new Promise(function (resolve, reject) {
                    gMap.graphics.clear();
                    resolve();
                });
            },

            // Actions that the old serious game could do: buffer, intersect, clip, union, multibuffer
            buffer: TEST_FRONTEND_ACTION
        }
    };
})();
<commit_msg>Worked on implementing actions.draw and actions.buffer<commit_after>/*
 * The SerGIS Project - sergis-client
 *
 * This is a SerGIS Client Frontend file for the ArcGIS API.
 * For more on SerGIS Frontends, see:
 * http://sergisproject.github.io/docs/client.html#frontends
 */

// These type definitions are used below in SerGIS's ArcGIS Frontend code.

/**
 * @typedef {object} SerGIS_ArcGIS_DrawStyle
 * @description An object representing style for a drawing using the ArcGIS
 *              frontend. Default values can be seen in the function
 *              `checkDrawStyle`.
 * @see sergis.frontend.actions.draw
 * @see drawObject
 * @see checkDrawStyle
 *
 * @property {string} dotStyle - "circle", "cross", "diamond", "square", "x"
 *           (case insensitive)
 * @property {array.<number>} dotColor - [red, green, blue, alpha]
 * @property {string} lineStyle - one of "Dash", "DashDot", "DashDotDot",
 *           "LongDash", "LongDashDot", "Null", "ShortDash", "ShortDashDot",
 *           "ShortDashDotDot", "ShortDot", "Solid" (case insensitive)
 * @property {array.<number>} lineColor - [red, green, blue, alpha]
 * @property {number} lineWidth - positive integer
 * @property {array.<number>} fillColor - [red, green, blue, alpha]
 * @property {string} fillStyle - "backward_diagonal", "cross",
 *           "diagonal_cross", "forward_diagonal", "horizontal", "null",
 *           "solid", "vertical" (case insensitive)
 */

/**
 * @typedef {object} SerGIS_ArcGIS_Point
 * @description An object representing a map point.
 *
 * @property {number} latitude - The latitude coordinate.
 * @property {number} longitude - The longitude coordinate.
 */

/**
 * @typedef {string} SerGIS_ArcGIS_Unit
 * @description The name of an ArcGIS unit constant (case insensitive).
 * A list of these can be found at:
 * {@link https://developers.arcgis.com/javascript/jsapi/geometryservice-amd.html}
 *
 * Any property or parameter that takes a SerGIS_ArcGIS_Unit is looking for one
 * of those constants WITHOUT THE "UNIT_" in front.
 *
 * Distance units: "foot", "kilometer", "meter", "nautical_mile",
 *     "statute_mile", "us_nautical_mile"
 * Area units: "acres", "ares", "hectacres", "square_centimeters",
 *     "square_decimeters", "square_feet", "square_inches",
 *     "square_kilometers", "square_meters", "square_miles",
 *     "square_millimeters", "square_yards"
 */

// Special SerGIS objects (for JSDoc)
// http://sergisproject.github.io/docs/json.html

/**
 * @typedef SerGISMap
 * @description A SerGIS JSON Map Object.
 * @see {@link http://sergisproject.github.io/docs/json.html#map-object}
 */

// This is all wrapped inside an anonymous, self-executing function to prevent
// variables from leaking into the global scope.
(function () {
    /**
     * Make an event handler for a toolbar "Draw ..." button.
     *
     * @param {string} type - The name of a constant in esri.toolbars.Draw.
     *
     * @return {function}
     */
    var makeDrawHandler = function (type) {
        return (function () {
            gToolbar.activate(esri.toolbars.Draw[type]);
            gMap.hideZoomSlider();
        });
    };

    /**
     * The ArcGIS-specific toolbar buttons.
     *
     * Each item is an object with the following properties:
     *   - label (SerGISContent): The label of the toolbar button,
     *   - tooltip (string): An optional tooltip for the toolbar button,
     *   - action (function): The action of the toolbar button. Can optionally
     *     return a Promise if the action happens asynchronously.
     *
     * @type {Array.<Object>}
     */
    var toolbarButtons = [
        {
            label: {type: "text", value: "Layers"},
            tooltip: "Turn specific map layers on or off",
            action: function () {
                return new Promise(function (resolve, reject) {
                    // ...
                    resolve();
                });
            }
        },
        {
            label: {type: "text", value: "Measure"},
            tooltip: "Measure a distance on the map",
            action: function () {
                return new Promise(function (resolve, reject) {
                    // ...
                    resolve();
                });
            }
        },
        {
            label: {type: "text", value: "Draw Point"},
            tooltip: "Draw a point on the map",
            action: makeDrawHandler("POINT")
        },
        {
            label: {type: "text", value: "Draw Line"},
            tooltip: "Draw a line on the map",
            action: makeDrawHandler("LINE")
        },
        {
            label: {type: "text", value: "Draw Polyline"},
            tooltip: "Draw a polyline on the map",
            action: makeDrawHandler("POLYLINE")
        },
        {
            label: {type: "text", value: "Draw Polygon"},
            tooltip: "Draw a polygon on the map",
            action: makeDrawHandler("POLYGON")
        },
        {
            label: {type: "text", value: "Reset Map"},
            tooltip: "Remove all custom drawings from the map",
            action: function () {
                // This is a bit hackish, calling stuff from sergis.main
                return sergis.main.reinitMap();
            }
        }
    ];

    /** A cache of things that have been "require"d. */
    var api = {};
    /** "global map" */
    var gMap;
    /** "global toolbar" */
    var gToolbar;
    /** "global geometry service" */
    var gSvc;

    /**
     * The index of the last geometry item drawn by the user.
     * Corresponds to drawnObjects["userDrawing_" + index].
     */
    var userDrawingIndex = -1;

    /**
     * A map of geometry items (points, lines, polygons) that have been drawn
     * through map actions (key is internal ID of what we drew, value is object
     * with `geometry`, `symbol`, and `graphic`).
     */
    var drawnObjects = {};

    /**
     * Check a SerGIS_ArcGIS_DrawStyle object and put in default values for
     * missing ones (modifications done in place).
     *
     * @param {SerGIS_ArcGIS_DrawStyle} style - See the corresponding typedef
     *        at the top of this file.
     */
    var checkDrawStyle = function (style) {
        // *** HERE ARE THE DEFAULT STYLE VALUES ***
        if (!style.dotStyle) style.dotStyle = "circle";
        if (!style.dotColor) style.dotColor = [0, 255, 0, 0.25];
        if (!style.lineStyle) style.lineStyle = "Solid";
        if (!style.lineColor) style.lineColor = [255, 0, 0];
        if (!style.lineWidth) style.lineWidth = 2;
        if (!style.fillColor) style.fillColor = [0, 255, 0, 0.25];
        if (!style.fillStyle) style.fillStyle = "solid";
    };

    /**
     * Draw some geometry on the map.
     *
     * @param {string} drawnObjectName - The name of the thing to draw (its
     *        data will be stored in drawnObjects[drawnObjectName]).
     * @param geometry - The geometry ("esri/geometry/Geometry") of the object
     *        to draw.
     * @param {SerGIS_ArcGIS_DrawStyle} style - See the corresponding typedef
     *        at the top of this file.
     */
    var drawObject = function (drawnObjectName, geometry, style) {
        var o = (drawnObjects[drawnObjectName] = {});
        o.geometry = geometry;
        // Make the actual map symbol
        switch (o.geometry.type) {
            case "point":
                o.symbol = new api.SimpleMarkerSymbol(
                    api.SimpleMarkerSymbol["STYLE_" + style.dotStyle.toUpperCase()],
                    10,
                    new api.SimpleLineSymbol(
                        api.SimpleLineSymbol["STYLE_" + style.lineStyle.toUpperCase()],
                        new api.Color(style.lineColor),
                        1
                    ),
                    new api.Color(style.dotColor)
                );
                break;
            case "polyline":
                o.symbol = new api.SimpleLineSymbol(
                    api.SimpleLineSymbol["STYLE_" + style.lineStyle.toUpperCase()],
                    new api.Color(style.lineColor),
                    style.lineWidth
                );
                break;
            case "polygon":
                o.symbol = new api.SimpleFillSymbol(
                    api.SimpleFillSymbol.STYLE_NONE,
                    new api.SimpleLineSymbol(
                        api.SimpleLineSymbol["STYLE_" + style.lineStyle.toUpperCase()],
                        new api.Color(style.lineColor),
                        style.lineWidth
                    ),
                    new api.Color(style.fillColor)
                );
                break;
        }

        // Add the symbol to the map
        o.graphic = new api.Graphic(o.geometry, o.symbol);
        gMap.graphics.add(o.graphic);
    };

    /**
     * Draw a buffer on the map.
     * (Called by frontend.actions.buffer)
     *
     * @param bufferedGeometries - The buffered geometries.
     */
    var drawBuffer = function (bufferedGeometries) {
        var symbol = new api.SimpleFillSymbol(
            api.SimpleFillSymbol.STYLE_SOLID,
            new api.SimpleLineSymbol(api.SimpleLineSymbol.STYLE_SOLID, new api.Color([255,0,0,0.65]), 2),
            new api.Color([255, 0, 0, 0.35])
        );

        for (var graphic, i = 0; i < bufferedGeometries.length; i++) {
            graphic = new api.Graphic(bufferedGeometries[i], symbol);
            gMap.graphics.add(graphic);
        }
    };

    /**
     * Initialize (or re-initialize) the map.
     *
     * @param {Element} mapContainer - The DOM element to stick the map into.
     * @param {SerGISMap} map - The SerGIS JSON Map object to position the map.
     *
     * @return {Promise}
     */
    var initMap = function (mapContainer, map) {
        return new Promise(function (resolve, reject) {
            // Remove all children of mapContainer
            while (mapContainer.firstChild) {
                mapContainer.removeChild(mapContainer.firstChild);
            }
            // Make a sub-container
            var mapElem = document.createElement("div");
            mapElem.id = "map-container-ARCGIS_API";
            mapElem.style.margin = "0";
            mapElem.style.padding = "0";
            mapElem.style.height = "100%";
            mapContainer.appendChild(mapElem);

            // Get all the map information together
            var info = {
                center: [map.longitude, map.latitude],
                zoom: map.zoom
            };
            // Check for any other changes that we need to make
            if (map.frontendInfo && map.frontendInfo.arcgis) {
                if (map.frontendInfo.arcgis.basemap) {
                    info.basemap = map.frontendInfo.arcgis.basemap;
                }
            }
            // Create the map
            gMap = new api.Map("map-container-ARCGIS_API", info);
            gMap.on("load", function (event) {
                // Initialize the drawing ability
                gToolbar = new api.Draw(gMap);
                gToolbar.on("draw-end", function (event) {
                    var index = ++userDrawingIndex;
                    // Draw the object on the map
                    var style = {};
                    checkDrawStyle(style);
                    drawObject("userDrawing_" + index, event.geometry, style);
                    // Deactivate the drawing and put the zoom slider back
                    gToolbar.deactivate();
                    gMap.showZoomSlider();
                });

                resolve();
            });
        });
    };

    /**
     * A map of ArcGIS code names for different parts of the API, mapped to the
     * name we use when loading them into `api`.
     */
    var toBeRequired = {
        "esri/map": "Map",
        "esri/graphic": "Graphic",
        "esri/Color": "Color",

        "esri/geometry/Geometry": "Geometry",
        "esri/geometry/Point": "Point",
        "esri/geometry/Multipoint": "Multipoint",
        "esri/geometry/Polygon": "Polygon",
        "esri/geometry/Polyline": "Polyline",

        "esri/tasks/GeometryService": "GeometryService",
        "esri/tasks/BufferParameters": "BufferParameters",

        "esri/toolbars/draw": "Draw",

        "esri/symbols/SimpleMarkerSymbol": "SimpleMarkerSymbol",
        "esri/symbols/SimpleLineSymbol": "SimpleLineSymbol",
        "esri/symbols/SimpleFillSymbol": "SimpleFillSymbol"
    };

    /**
     * Require all the stuff that we'll need, if we haven't already.
     *
     * @return {Promise}
     */
    var initRequire = function () {
        return new Promise(function (resolve, reject) {
            var requireArgs = [],
                requireNames = [];
            for (var prop in toBeRequired) {
                if (toBeRequired.hasOwnProperty(prop) && toBeRequired[prop]) {
                    requireArgs.push(prop);
                    requireNames.push(toBeRequired[prop]);
                    // We don't want to require it more than once
                    delete toBeRequired[prop];
                }
            }
            if (requireArgs.length > 0) {
                require(requireArgs, function () {
                    for (var i = 0; i < arguments.length; i++) {
                        api[requireNames[i]] = arguments[i];
                    }
                    resolve();
                });
            } else {
                resolve();
            }
        });
    };

    /**
     * Test function that returns a promise and alerts the arguments passed to the
     * function, then resolves the promise.
     */
    var TEST_FRONTEND_ACTION = function () {
        var args = Array.prototype.slice.call(arguments, 0);
        return new Promise(function (resolve, reject) {
            alert("Doing action with:\n" + JSON.stringify(args));
            resolve();
        });
    }

    /**
     * @namespace
     * @see {@link http://sergisproject.github.io/docs/client.html}
     */
    sergis.frontend = {
        name: "arcgis",

        init: function (mapContainer, map) {
            return new Promise(function (resolve, reject) {
                // Since it's the first time, load everything we need from the ArcGIS API
                initRequire().then(function () {
                    // Initialize the map
                    initMap(mapContainer, map).then(function () {
                        // Initialize the geometry service
                        //gSvc = new api.GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
                        gSvc = new api.GeometryService("http://utility.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
                        // Resolve with a list of toolbar buttons
                        resolve(toolbarButtons.map(function (button) {
                            return {
                                label: button.label,
                                tooltip: button.tooltip
                            };
                        }));
                    }, reject).catch(sergis.error);
                }, reject).catch(sergis.error);
            });
        },

        reinit: function (mapContainer, map) {
            return new Promise(function (resolve, reject) {
                // Clear out all previous drawing info
                drawnObjects = {};
                // Initialize the map
                resolve(initMap(mapContainer, map));
            });
        },

        centerMap: function (map) {
            return new Promise(function (resolve, reject) {
                // Check for any other changes that we need to make first
                // (so it can load crap for them while changing the map zoom)
                if (map.frontendInfo && map.frontendInfo.arcgis) {
                    if (map.frontendInfo.arcgis.basemap) {
                        gMap.setBasemap(map.frontendInfo.arcgis.basemap);
                    }
                }
                // NOTE: This below looks like it returns a Promise... but it doesn't. It's a "Deferred" (damn dojo)
                gMap.centerAndZoom([map.longitude, map.latitude], map.zoom).then(function () {
                    resolve();
                }, reject);
            });
        },

        toolbarAction: function (buttonIndex) {
            return new Promise(function (resolve, reject) {
                if (toolbarButtons[buttonIndex]) {
                    resolve(toolbarButtons[buttonIndex].action());
                } else {
                    reject("Invalid buttonIndex!");
                }
            });
        },

        actions: {
            /**
             * Clear any drawn graphics on the map.
             *
             * @return {Promise}
             */
            clearGraphics: function () {
                return new Promise(function (resolve, reject) {
                    gMap.graphics.clear();
                    resolve();
                });
            },

            /**
             * Draw a predefined point, line, polyline, or polygon on the map.
             *
             * @param {string} objectName - The name of the object that is
             *        drawn (for later reference). Must not have been used
             *        already, and must not start with "userDrawing".
             *
             * @param {string} type - The type of object to draw; one of:
             *        "point" (draws a single point for each item in `points`),
             *        "line" or "polyline" (draws a line from `points`),
             *        "polygon" (draws an enclosed polygon from `points`).
             *
             * @param {array.<SerGIS_ArcGIS_Point>} points - An array of 2 or
             *        more map points. See the SerGIS_ArcGIS_Point typedef at
             *        the top of this file.
             *
             * @param {SerGIS_ArcGIS_DrawStyle} [style] - See the corresponding
             *        typedef at the top of this file.
             *
             * @return {Promise}
             */
            draw: function (objectName, type, points, style) {
                return new Promise(function (resolve, reject) {
                    if (typeof objectName != "string" ||
                        objectName.substring(0, 11) == "userDrawing" ||
                        drawnObjects[objectName]) {

                        reject("Invalid objectName!");
                    } else {
                        // Add in default values for missing style stuff
                        if (!style) style = {};
                        checkDrawStyle(style);
                        // Make the thing
                        if (type == "point") {
                            drawObject(objectName, new api.Point(points[0].longitude, points[0].latitude), style);
                        } else {
                            if (type == "polygon") {
                                // Make sure first and last points are the same
                                if (points[0] != points[points.length - 1]) {
                                    points.push(points[0]);
                                }
                            }
                            // Convert the points to actual Points
                            var pointObjects = [];
                            for (var i = 0; i < points.length; i++) {
                                //pointObjects.push(new api.Point(points[i].longitude, points[i].latitude));
                                pointObjects.push([points[i].longitude, points[i].latitude]);
                            }
                            // Make the geometry
                            var geometry;
                            if (type == "polygon") {
                                geometry = new api.Polygon(pointObjects);
                            } else {
                                geometry = new api.Polyline(pointObjects);
                            }
                            // Draw the geometry
                            drawObject(objectName, geometry, style);
                        }
                        resolve();
                    }
                });
            },

            // Actions that the old serious game could do: buffer, intersect, clip, union, multibuffer

            /**
             * Draw a buffer on the map around data.
             *
             * @param {number} distance - The size of the buffer.
             * @param {SerGIS_ArcGIS_Unit} unit - The unit that the size is in.
             * @param {string} [objectName] - The name of something that was
             *        previously drawn (through actions.draw) to buffer. If not
             *        provided, then the last item drawn by the user (using the
             *        toolbar buttons) is used.
             * @param {SerGIS_ArcGIS_DrawStyle} [style] - See the corresponding
             *        typedef at the top of this file.
             *
             * @return {Promise}
             */
            buffer: function (distance, unit, objectName, style) {
                return new Promise(function (resolve, reject) {
                    if (!objectName) {
                        objectName = "userDrawing_" + userDrawingIndex;
                    }
                    if (drawnObjects[objectName]) {
                        var o = drawnObjects[objectName],
                            params = new api.BufferParameters();
                        params.distances = [distance];
                        params.unit = api.GeometryService["UNIT_" + unit.toUpperCase()];
                        params.outSpatialReference = gMap.spatialReference;
                        // Make style
                        if (!style) style = {};
                        checkDrawStyle(style);
                        if (o.geometry.type == "polygon") {
                            // We're buffering a polygon; simplify it so it is
                            // topologically correct.
                            gSvc.simplify([o.geometry], function (geometries) {
                                params.geometries = geometries;
                                gSvc.buffer(params, function (bufferedGeometries) {
                                    drawBuffer(bufferedGeometries, style);
                                    resolve();
                                });
                            });
                        } else {
                            // Not a polygon
                            params.geometries = [o.geometry];
                            gSvc.buffer(params, function (bufferedGeometries) {
                                drawBuffer(bufferedGeometries, style);
                                resolve();
                            });
                        }
                    } else {
                        reject("Invalid objectName!");
                    }
                });
            }
        }
    };
})();
<|endoftext|>


<commit_before>'use strict';

const superagent = require('superagent');
const Promise = require('bluebird');
const logger = require('heroku-logger');

const uri = process.env.DS_GAMBIT_CAMPAIGNS_API_BASEURI;
const apiKey = process.env.DS_GAMBIT_CAMPAIGNS_API_KEY;

module.exports.get = function (endpoint) {
  const url = `${uri}/${endpoint}`;
  logger.trace('gambitCampaigns.get', { url });

  return superagent.get(url)
    .then(res => res.body.data)
    .catch(err => err);
};

module.exports.post = function (endpoint, data) {
  return superagent
    .post(`${uri}/${endpoint}`)
    .set('x-gambit-api-key', apiKey)
    .send(data)
    .then(res => res.body)
    .catch(err => err);
};

module.exports.getActiveCampaigns = function () {
  return this.get('campaigns');
};

/**
 * Parse our incoming Express request for expected Gambit Campaigns format.
 * @param {object} req
 * @return {object}
 */
function parseReceiveMessageRequest(req) {
  let phone = req.conversation._id;
  if (req.conversation.platform === 'sms') {
    phone = req.conversation.platformUserId;
  }
  const data = {
    phone,
    campaignId: req.campaign.id,
    text: req.inboundMessageText,
    mediaUrl: req.mediaUrl,
    broadcastId: req.broadcastId,
  };
  if (req.keyword) {
    data.keyword = req.keyword.toLowerCase();
  }

  return data;
}

/**
 * Posts data to the /receive-message endpoint.
 */
module.exports.postReceiveMessage = function (req) {
  const data = parseReceiveMessageRequest(req);
  const loggerMessage = 'gambitCampaigns.postReceiveMessage';
  logger.debug(loggerMessage, data);

  return new Promise((resolve, reject) => {
    this.post('receive-message', data)
      .then((res) => {
        logger.debug(`${loggerMessage} res.success`, res.success);
        return resolve(res.success);
      })
      .catch(err => reject(err));
  });
};
<commit_msg>Pass req.userId to Gambit Campaigns<commit_after>'use strict';

const superagent = require('superagent');
const Promise = require('bluebird');
const logger = require('heroku-logger');

const uri = process.env.DS_GAMBIT_CAMPAIGNS_API_BASEURI;
const apiKey = process.env.DS_GAMBIT_CAMPAIGNS_API_KEY;

module.exports.get = function (endpoint) {
  const url = `${uri}/${endpoint}`;
  logger.trace('gambitCampaigns.get', { url });

  return superagent.get(url)
    .then(res => res.body.data)
    .catch(err => err);
};

module.exports.post = function (endpoint, data) {
  return superagent
    .post(`${uri}/${endpoint}`)
    .set('x-gambit-api-key', apiKey)
    .send(data)
    .then(res => res.body)
    .catch(err => err);
};

module.exports.getActiveCampaigns = function () {
  return this.get('campaigns');
};

/**
 * Parse our incoming Express request for expected Gambit Campaigns format.
 * @param {object} req
 * @return {object}
 */
function parseReceiveMessageRequest(req) {
  let phone = req.conversation._id;
  if (req.conversation.platform === 'sms') {
    phone = req.conversation.platformUserId;
  }
  const data = {
    phone,
    campaignId: req.campaign.id,
    text: req.inboundMessageText,
    mediaUrl: req.mediaUrl,
    broadcastId: req.broadcastId,
  };
  if (req.keyword) {
    data.keyword = req.keyword.toLowerCase();
  }
  if (req.userId) {
    data.userId = req.userId;
  }

  return data;
}

/**
 * Posts data to the /receive-message endpoint.
 */
module.exports.postReceiveMessage = function (req) {
  const data = parseReceiveMessageRequest(req);
  const loggerMessage = 'gambitCampaigns.postReceiveMessage';
  logger.debug(loggerMessage, data);

  return new Promise((resolve, reject) => {
    this.post('receive-message', data)
      .then((res) => {
        logger.debug(`${loggerMessage} res.success`, res.success);
        return resolve(res.success);
      })
      .catch(err => reject(err));
  });
};
<|endoftext|>


<commit_before>"use strict";

/**
 * This is the plugin for syncing scroll between devices
 * @type {string}
 */
var WINDOW_EVENT_NAME  = "scroll";
var ELEMENT_EVENT_NAME = "scroll:element";
var OPT_PATH           = "ghostMode.scroll";
var utils;

exports.canEmitEvents = true;

/**
 * @param {BrowserSync} bs
 * @param eventManager
 */
exports.init = function (bs, eventManager) {
    utils     = bs.utils;
    var opts  = bs.options;

    /**
     * Window Scroll events
     */
    eventManager.addEvent(window, WINDOW_EVENT_NAME, exports.browserEvent(bs));
    bs.socket.on(WINDOW_EVENT_NAME, exports.socketEvent(bs));

    /**
     * element Scroll Events
     */
    var cache = {};
    addElementScrollEvents("scrollElements", false);
    addElementScrollEvents("scrollElementMapping", true);
    bs.socket.on(ELEMENT_EVENT_NAME, exports.socketEventForElement(bs, cache));

    function addElementScrollEvents (key, map) {
        if (!opts[key] || !opts[key].length || !("querySelectorAll" in document)) {
            return;
        }
        utils.forEach(opts[key], function (selector) {
            var elems = document.querySelectorAll(selector) || [];
            utils.forEach(elems, function (elem) {
                var data = utils.getElementData(elem);
                data.cacheSelector = data.tagName + ":" + data.index;
                data.map = map;
                cache[data.cacheSelector] = elem;
                eventManager.addEvent(elem, WINDOW_EVENT_NAME, exports.browserEventForElement(bs, elem, data));
            });
        });
    }
};

/**
 * @param {BrowserSync} bs
 */
exports.socketEvent = function (bs) {

    return function (data) {

        if (!bs.canSync(data, OPT_PATH)) {
            return false;
        }

        var scrollSpace = utils.getScrollSpace();

        exports.canEmitEvents = false;

        if (bs.options && bs.options.scrollProportionally) {
            return window.scrollTo(0, scrollSpace.y * data.position.proportional); // % of y axis of scroll to px
        } else {
            return window.scrollTo(0, data.position.raw);
        }
    };
};

/**
 * @param bs
 */
exports.socketEventForElement = function (bs, cache) {
    return function (data) {

        if (!bs.canSync(data, OPT_PATH)) {
            return false;
        }

        exports.canEmitEvents = false;

        function scrollOne (selector, pos) {
            if (cache[selector]) {
                cache[selector].scrollTop = pos;
            }
        }

        if (data.map) {
            return Object.keys(cache).forEach(function (key) {
                scrollOne(key, data.position);
            });
        }

        scrollOne(data.elem.cacheSelector, data.position);
    };
};

/**
 * @param bs
 */
exports.browserEventForElement = function (bs, elem, data) {
    return function () {
        var canSync = exports.canEmitEvents;
        if (canSync) {
            bs.socket.emit(ELEMENT_EVENT_NAME, {
                position: elem.scrollTop,
                elem: data,
                map: data.map
            });
        }
        exports.canEmitEvents = true;
    };
};

exports.browserEvent = function (bs) {

    return function () {

        var canSync = exports.canEmitEvents;

        if (canSync) {
            bs.socket.emit(WINDOW_EVENT_NAME, {
                position: exports.getScrollPosition()
            });
        }

        exports.canEmitEvents = true;
    };
};

/**
 * @returns {{raw: number, proportional: number}}
 */
exports.getScrollPosition = function () {
    var pos = utils.getBrowserScrollPosition();
    return {
        raw: pos.y, // Get px of y axis of scroll
        proportional: exports.getScrollTopPercentage(pos) // Get % of y axis of scroll
    };
};

/**
 * @param {{x: number, y: number}} scrollSpace
 * @param scrollPosition
 * @returns {{x: number, y: number}}
 */
exports.getScrollPercentage = function (scrollSpace, scrollPosition) {

    var x = scrollPosition.x / scrollSpace.x;
    var y = scrollPosition.y / scrollSpace.y;

    return {
        x: x || 0,
        y: y
    };
};

/**
 * Get just the percentage of Y axis of scroll
 * @returns {number}
 */
exports.getScrollTopPercentage = function (pos) {
    var scrollSpace = utils.getScrollSpace();
    var percentage  = exports.getScrollPercentage(scrollSpace, pos);
    return percentage.y;
};<commit_msg>Emit object with both x and y scroll values, update window.scrollTo call to use only y value.<commit_after>"use strict";

/**
 * This is the plugin for syncing scroll between devices
 * @type {string}
 */
var WINDOW_EVENT_NAME  = "scroll";
var ELEMENT_EVENT_NAME = "scroll:element";
var OPT_PATH           = "ghostMode.scroll";
var utils;

exports.canEmitEvents = true;

/**
 * @param {BrowserSync} bs
 * @param eventManager
 */
exports.init = function (bs, eventManager) {
    utils     = bs.utils;
    var opts  = bs.options;

    /**
     * Window Scroll events
     */
    eventManager.addEvent(window, WINDOW_EVENT_NAME, exports.browserEvent(bs));
    bs.socket.on(WINDOW_EVENT_NAME, exports.socketEvent(bs));

    /**
     * element Scroll Events
     */
    var cache = {};
    addElementScrollEvents("scrollElements", false);
    addElementScrollEvents("scrollElementMapping", true);
    bs.socket.on(ELEMENT_EVENT_NAME, exports.socketEventForElement(bs, cache));

    function addElementScrollEvents (key, map) {
        if (!opts[key] || !opts[key].length || !("querySelectorAll" in document)) {
            return;
        }
        utils.forEach(opts[key], function (selector) {
            var elems = document.querySelectorAll(selector) || [];
            utils.forEach(elems, function (elem) {
                var data = utils.getElementData(elem);
                data.cacheSelector = data.tagName + ":" + data.index;
                data.map = map;
                cache[data.cacheSelector] = elem;
                eventManager.addEvent(elem, WINDOW_EVENT_NAME, exports.browserEventForElement(bs, elem, data));
            });
        });
    }
};

/**
 * @param {BrowserSync} bs
 */
exports.socketEvent = function (bs) {

    return function (data) {

        if (!bs.canSync(data, OPT_PATH)) {
            return false;
        }

        var scrollSpace = utils.getScrollSpace();

        exports.canEmitEvents = false;

        if (bs.options && bs.options.scrollProportionally) {
            return window.scrollTo(0, scrollSpace.y * data.position.proportional); // % of y axis of scroll to px
        } else {
            return window.scrollTo(0, data.position.raw.y);
        }
    };
};

/**
 * @param bs
 */
exports.socketEventForElement = function (bs, cache) {
    return function (data) {

        if (!bs.canSync(data, OPT_PATH)) {
            return false;
        }

        exports.canEmitEvents = false;

        function scrollOne (selector, pos) {
            if (cache[selector]) {
                cache[selector].scrollTop = pos;
            }
        }

        if (data.map) {
            return Object.keys(cache).forEach(function (key) {
                scrollOne(key, data.position);
            });
        }

        scrollOne(data.elem.cacheSelector, data.position);
    };
};

/**
 * @param bs
 */
exports.browserEventForElement = function (bs, elem, data) {
    return function () {
        var canSync = exports.canEmitEvents;
        if (canSync) {
            bs.socket.emit(ELEMENT_EVENT_NAME, {
                position: elem.scrollTop,
                elem: data,
                map: data.map
            });
        }
        exports.canEmitEvents = true;
    };
};

exports.browserEvent = function (bs) {

    return function () {

        var canSync = exports.canEmitEvents;

        if (canSync) {
            bs.socket.emit(WINDOW_EVENT_NAME, {
                position: exports.getScrollPosition()
            });
        }

        exports.canEmitEvents = true;
    };
};

/**
 * @returns {{raw: number, proportional: number}}
 */
exports.getScrollPosition = function () {
    var pos = utils.getBrowserScrollPosition();
    return {
        raw: pos, // Get px of x and y axis of scroll
        proportional: exports.getScrollTopPercentage(pos) // Get % of y axis of scroll
    };
};

/**
 * @param {{x: number, y: number}} scrollSpace
 * @param scrollPosition
 * @returns {{x: number, y: number}}
 */
exports.getScrollPercentage = function (scrollSpace, scrollPosition) {

    var x = scrollPosition.x / scrollSpace.x;
    var y = scrollPosition.y / scrollSpace.y;

    return {
        x: x || 0,
        y: y
    };
};

/**
 * Get just the percentage of Y axis of scroll
 * @returns {number}
 */
exports.getScrollTopPercentage = function (pos) {
    var scrollSpace = utils.getScrollSpace();
    var percentage  = exports.getScrollPercentage(scrollSpace, pos);
    return percentage.y;
};<|endoftext|>


<commit_before>
var ref1 = objective.logger
  , generate = require('shortid').generate
  , pipeline
  , sequence = require('when/sequence')
  , promise = require('when').promise
  , count = 0
  , debug = ref1.createDebug('pipeline')
  , TODO = ref1.TODO
  , error = ref1.error
  , warn = ref1.warn
  , info = ref1.info

function exitWarning() {
  for (id in pipeline.runs) {
    var event, payload, depth, runningHandler;
    event = pipeline.runs[id].event;
    payload = pipeline.runs[id].payload;
    depth = pipeline.runs[id].depth;
    caller = pipeline.runs[id].caller;
    runningHandler = pipeline.runs[id].runningHandler;
    warn('still in pipeline');
    warn('at %s:%d:%d', caller.file, caller.line, caller.col);
    warn('event:%s depth:%s, payload', event, depth, payload);
    warn('');
    //warn('function', runningHandler);
  }
}

process.on('exit', function() {
  if (count == 0) exitWarning();
});

process.on('SIGINT', function() {
  if (objective.program.attach) return process.exit(0)
  count++;
  setTimeout(function(){
    count--
  }, 2000);
  if (count > 1) return process.exit(1);
  exitWarning();
  console.log('\nagain to exit');
});

module.exports = pipeline = {

  pipes: {},

  runs: {},

  startRun: function(event, payload) {
    var id = generate();
    pipeline.runs[id] = {
      event: event,
      payload: payload,
      depth: 0,
      runningHandler: null,
      caller: null
    }
    return id;
  },

  createEvent: function(event) {
    var base;
    debug("pipeline created event '" + event + "'");
    return (base = pipeline.pipes)[event] || (base[event] = []);
  },

  emit: function(event, payload, callback) {
    var id, cancelled, cancelledReason, fn, pipe;
    if (!(pipe = pipeline.pipes[event])) {
      return callback(new Error("No handlers for '" + event + "'."));
    }
    debug("pipeline emitting event '" + event + "'");
    id = pipeline.startRun(event, payload);
    cancelled = false;
    cancelledReason = 'reason unspecified';
    return sequence(
      pipe.map(function(handler){
        return function() {
          return promise(function(resolve, reject){
            pipeline.runs[id].runningHandler = handler.fn;
            pipeline.runs[id].caller = handler.caller;
            pipeline.runs[id].depth++;
            debug("pipeline event handler running event '" + event + "'");
            return objective.injector({
              args: [payload],
              next: function(e) {
                // TODO, is it error?
                if (e) return reject(e);
                resolve();
              },
              onError: reject,
              cancel: function(reason) {
                if (reason != null) {
                  cancelledReason = reason;
                }
                cancelled = true;
                return reject();
              }
            }, handler.fn);
          });
        }
      })
    ).then(function(result) {
      debug("pipeline event '" + event + "' done ok");
      delete pipeline.runs[id];
      return callback(null, payload);
    }, function(err) {
      var depth, fn;
      depth = pipeline.runs[id].depth;
      fn = pipeline.runs[id].runningHandler;
      if (cancelled) {
        debug("event cancelled at depth " + depth + " by ", fn);
        info("pipeline event '" + event + "' cancelled because '" + cancelledReason + "'");
        delete pipeline.runs[id];
        return;
      }
      console.log(err.stack);
      debug("event failed at depth " + depth + " by ", fn, err);
      error("pipeline event '" + event + "' failed " + (err.toString()));
      delete pipeline.runs[id];
      return callback(err);
    }, function(notify) {});
  },

  on: function(event, fn, anyway) {
                          // does not exist yet, subscribe anyway
    if (fn.$$pipeid) return fn.$$pipeid;
    fn.$$pipeid = generate();
    var base;
    if (typeof pipeline.pipes[event] === 'undefined' && !anyway) {
      error("No such event '" + event + "'");
      throw new Error("No such event '" + event + "'");
    }
    debug("pipeline registering handler on event '" + event + "'");
    (base = pipeline.pipes)[event] || (base[event] = []);
    pipeline.pipes[event].push({
      fn: fn,
      caller: objective.getCaller(2)
    });
    return fn.$$pipeid;
  },

  off: function(event, fn) {
    // deleted handlers may still still be called by any
    // already (long) running emits (TODO: fix)
    var deleteId = fn.$$pipeid;
    pipeline.pipes[event] = pipeline.pipes[event].filter(
      function(handler) {
        return handler.fn.$$pipeid != deleteId;
      }
    );
    delete fn.$$pipeid;
  }
};

<commit_msg>support label for pipeline middleware<commit_after>
var ref1 = objective.logger
  , generate = require('shortid').generate
  , pipeline
  , sequence = require('when/sequence')
  , promise = require('when').promise
  , count = 0
  , debug = ref1.createDebug('pipeline')
  , TODO = ref1.TODO
  , error = ref1.error
  , warn = ref1.warn
  , info = ref1.info

function exitWarning() {
  for (id in pipeline.runs) {
    var event, payload, depth, runningHandler;
    event = pipeline.runs[id].event;
    payload = pipeline.runs[id].payload;
    depth = pipeline.runs[id].depth;
    caller = pipeline.runs[id].caller;
    runningHandler = pipeline.runs[id].runningHandler;
    warn('still in pipeline');
    warn('at %s:%d:%d', caller.file, caller.line, caller.col);
    warn('event:%s depth:%s, payload', event, depth, payload);
    warn('');
    //warn('function', runningHandler);
  }
}

process.on('exit', function() {
  if (count == 0) exitWarning();
});

process.on('SIGINT', function() {
  if (objective.program.attach) return process.exit(0)
  count++;
  setTimeout(function(){
    count--
  }, 2000);
  if (count > 1) return process.exit(1);
  exitWarning();
  console.log('\nagain to exit');
});

module.exports = pipeline = {

  pipes: {},

  runs: {},

  startRun: function(event, payload) {
    var id = generate();
    pipeline.runs[id] = {
      event: event,
      payload: payload,
      depth: 0,
      runningHandler: null,
      caller: null
    }
    return id;
  },

  createEvent: function(event) {
    var base;
    debug("pipeline created event '" + event + "'");
    return (base = pipeline.pipes)[event] || (base[event] = []);
  },

  emit: function(event, payload, callback) {
    var id, cancelled, cancelledReason, fn, pipe;
    if (!(pipe = pipeline.pipes[event])) {
      return callback(new Error("No handlers for '" + event + "'."));
    }
    debug("pipeline emitting event '" + event + "'");
    id = pipeline.startRun(event, payload);
    cancelled = false;
    cancelledReason = 'reason unspecified';
    return sequence(
      pipe.map(function(handler){
        return function() {
          return promise(function(resolve, reject){
            pipeline.runs[id].runningHandler = handler.fn;
            pipeline.runs[id].caller = handler.caller;
            pipeline.runs[id].depth++;
            debug("pipeline event handler '%s' running event '%s'", handler.opts.label, event);
            return objective.injector({
              args: [payload],
              next: function(e) {
                // TODO, is it error?
                if (e) return reject(e);
                resolve();
              },
              onError: reject,
              cancel: function(reason) {
                if (reason != null) {
                  cancelledReason = reason;
                }
                cancelled = true;
                return reject();
              }
            }, handler.fn);
          });
        }
      })
    ).then(function(result) {
      debug("pipeline event '" + event + "' done ok");
      delete pipeline.runs[id];
      return callback(null, payload);
    }, function(err) {
      var depth, fn;
      depth = pipeline.runs[id].depth;
      fn = pipeline.runs[id].runningHandler;
      if (cancelled) {
        debug("event cancelled at depth " + depth + " by ", fn);
        info("pipeline event '" + event + "' cancelled because '" + cancelledReason + "'");
        delete pipeline.runs[id];
        return;
      }
      console.log(err.stack);
      debug("event failed at depth " + depth + " by ", fn, err);
      error("pipeline event '" + event + "' failed " + (err.toString()));
      delete pipeline.runs[id];
      return callback(err);
    }, function(notify) {});
  },
                        // optional
                       //
  on: function(event, opts, fn, anyway) {
                                  //
                                 // does not exist yet, subscribe anyway
    var _arguments = arguments;
    var args = Object.keys(arguments).map(function(key){return _arguments[key]});
    event = args.shift();
    opts = args.shift();
    if (typeof opts == 'string') opts = {label:opts};
    if (typeof opts == 'function') {
      fn = opts;
      anyway = args.shift();
      opts = {label:'untitled'};
    } else {
      fn = args.shift();
      anyway = args.shift();
    }

    if (fn.$$pipeid) return fn.$$pipeid;
    Object.defineProperty(fn, '$$pipeid', {
      enumareble: false,
      configurable: false,
      writable: false,
      value: generate()
    });

    var base;
    if (typeof pipeline.pipes[event] === 'undefined' && !anyway) {
      error("No such event '" + event + "'");
      throw new Error("No such event '" + event + "'");
    }
    debug("pipeline registering handler on event '" + event + "'");
    (base = pipeline.pipes)[event] || (base[event] = []);
    pipeline.pipes[event].push({
      opts: opts,
      fn: fn,
      caller: objective.getCaller(2)
    });
    return fn.$$pipeid;
  },

  off: function(event, fn) {
    // deleted handlers may still still be called by any
    // already (long) running emits (TODO: fix)
    var deleteId = fn.$$pipeid;
    pipeline.pipes[event] = pipeline.pipes[event].filter(
      function(handler) {
        return handler.fn.$$pipeid != deleteId;
      }
    );
    delete fn.$$pipeid;
  }
};

<|endoftext|>


<commit_before>import superagent from 'superagent';
import config from 'config';

/*
 * This silly underscore is here to avoid a mysterious "ReferenceError: ApiClient is not defined" error.
 * See Issue #14. https://github.com/erikras/react-redux-universal-hot-example/issues/14
 *
 * Remove it at your own risk.
 */
class ApiClient_ {
  constructor(req) {
    ['get', 'post', 'put', 'patch', 'del'].
      forEach((method) => {
        this[method] = (path, options) => {
          return new Promise((resolve, reject) => {
            const request = superagent[method](this.formatUrl(path));
            if (options && options.params) {
              request.query(options.params);
            }
            if (__SERVER__) {
              if (req.get('cookie')) {
                request.set('cookie', req.get('cookie'));
              }
            }
            if (options && options.data) {
              request.send(options.data);
            }
            request.end((err, res) => {
              if (err) {
                reject(res.body || err);
              } else {
                resolve(res.body);
              }
            });
          });
        };
      });
  }

  /* This was originally a standalone function outside of this class, but babel kept breaking, and this fixes it  */
  formatUrl(path) {
    const adjustedPath = path[0] !== '/' ? '/' + path : path;
    if (__SERVER__) {
      // Prepend host and port of the API server to the path.
      return 'http://localhost:' + config.apiPort + adjustedPath;
    }
    // Prepend `/api` to relative URL, to proxy to API server.
    return '/api' + adjustedPath;
  }
}
const ApiClient = ApiClient_;

export default ApiClient;
<commit_msg>Fix config module path<commit_after>import superagent from 'superagent';
import config from './config';

/*
 * This silly underscore is here to avoid a mysterious "ReferenceError: ApiClient is not defined" error.
 * See Issue #14. https://github.com/erikras/react-redux-universal-hot-example/issues/14
 *
 * Remove it at your own risk.
 */
class ApiClient_ {
  constructor(req) {
    ['get', 'post', 'put', 'patch', 'del'].
      forEach((method) => {
        this[method] = (path, options) => {
          return new Promise((resolve, reject) => {
            const request = superagent[method](this.formatUrl(path));
            if (options && options.params) {
              request.query(options.params);
            }
            if (__SERVER__) {
              if (req.get('cookie')) {
                request.set('cookie', req.get('cookie'));
              }
            }
            if (options && options.data) {
              request.send(options.data);
            }
            request.end((err, res) => {
              if (err) {
                reject(res.body || err);
              } else {
                resolve(res.body);
              }
            });
          });
        };
      });
  }

  /* This was originally a standalone function outside of this class, but babel kept breaking, and this fixes it  */
  formatUrl(path) {
    const adjustedPath = path[0] !== '/' ? '/' + path : path;
    if (__SERVER__) {
      // Prepend host and port of the API server to the path.
      return 'http://localhost:' + config.apiPort + adjustedPath;
    }
    // Prepend `/api` to relative URL, to proxy to API server.
    return '/api' + adjustedPath;
  }
}
const ApiClient = ApiClient_;

export default ApiClient;
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var _ = require('lodash'),
  express = require('express');

module.exports = function(sails) {

  var initialize = require('./initialize')(sails);

  /**
   * Expose `http` hook definition
   */

  return {

    defaults: function(config) {
      return {

        // Self-awareness: the host the server *thinks it is*
        // host: 'localhost',

        // Port to run this app on
        port: 1337,

        // Users' SSL cert settings end up here
        ssl: {},

        // HTTP cache configuration
        cache: {
          maxAge: config.environment === 'development' ? 1 : 31557600000
        },

        // Path where static files will be served from
        paths: {
          public: config.appPath + '/.tmp/public'
        },

        // New http-only middleware config
        // (provides default middleware)
        http: {
          middleware: {
            order: [
              'startRequestTimer',
              'cookieParser',
              'session',
              'bodyParser',
              'handleBodyParserError',
              'compress',
              'methodOverride',
              'poweredBy',
              '$custom',
              'router',
              'www',
              'favicon',
              '404',
              '500'
            ],

            // Default middleware definitions are injected
            // after the `app` object is available.
            // (see `loadMiddleware.js` and `middleware.js`)
            // e.g.:
            // session: {
            //   options: {},
            //   fn: function (req, res, next) { ... }
            // }

          },

          // Extra options to pass directly into the Express server
          // when it is instantiated
          //      (or false to disable)
          //
          // This is the options object for the `createServer` method, as discussed here:
          // http://nodejs.org/docs/v0.10.20/api/https.html#https_class_https_server
          serverOptions: false,

          // Custom express middleware function to use
          customMiddleware: false,

          // Configures the middleware function used for parsing the HTTP request body
          // Defaults to the Formidable-based version built into Express/Connect
          //
          // To enable streaming file uploads (to disk or somewhere else)
          // you'll want to set this option to `false` to disable the body parser.
          //
          // Alternatively, if you're comfortable with the bleeding edge,
          // check out: https://github.com/balderdashy/skipper
          bodyParser: undefined,

          // Cookie parser middleware to use
          //      (or false to disable)
          //
          // Defaults to `express.cookieParser`
          //
          // Example override:
          // cookieParser: (function cookieParser (req, res, next) {})(),
          cookieParser: express.cookieParser,

          // HTTP method override middleware
          //      (or false to disable)
          //
          // This option allows artificial query params to be passed to trick
          // Express into thinking a different HTTP verb was used.
          // Useful when supporting an API for user-agents which don't allow
          // PUT or DELETE requests
          //
          // Defaults to `express.methodOverride`
          //
          // Example override:
          // methodOverride: (function customMethodOverride (req, res, next) {})()
          methodOverride: express.methodOverride

        }

      };
    },

    configure: function() {

      // If one piece of the ssl config is specified, ensure the other required piece is there
      if (sails.config.ssl && (
        sails.config.ssl.cert && !sails.config.ssl.key
      ) || (!sails.config.ssl.cert && sails.config.ssl.key)) {
        throw new Error('Invalid SSL config object!  Must include cert and key!');
      }

      if (sails.config.host) {
        sails.config.explicitHost = sails.config.host;
      }

      if (sails.config.express) {
        sails.log.warn('`sails.config.express` is deprecated; use `sails.config.http` instead.');
      }
      sails.util.defaultsDeep(sails.config.http, sails.config.express);

    },

    /**
     * Initialize is fired first thing when the hook is loaded
     * but after waiting for user config (if applicable)
     *
     * @api public
     */

    initialize: function(cb) {
      return initialize(cb);
    }
  };

};
<commit_msg>Updated http hook defaults so merging in `sails.config.express` works<commit_after>/**
 * Module dependencies.
 */

var _ = require('lodash'),
  express = require('express');

module.exports = function(sails) {

  var initialize = require('./initialize')(sails);

  /**
   * Expose `http` hook definition
   */

  return {

    defaults: function(config) {
      return {

        // Self-awareness: the host the server *thinks it is*
        // host: 'localhost',

        // Port to run this app on
        port: 1337,

        // Users' SSL cert settings end up here
        ssl: {},

        // HTTP cache configuration
        cache: {
          maxAge: config.environment === 'development' ? 1 : 31557600000
        },

        // Path where static files will be served from
        paths: {
          public: config.appPath + '/.tmp/public'
        },

        // New http-only middleware config
        // (provides default middleware)
        http: {
          middleware: {
            order: [
              'startRequestTimer',
              'cookieParser',
              'session',
              'bodyParser',
              'handleBodyParserError',
              'compress',
              'methodOverride',
              'poweredBy',
              '$custom',
              'router',
              'www',
              'favicon',
              '404',
              '500'
            ],

            // Default middleware definitions are injected
            // after the `app` object is available.
            // (see `loadMiddleware.js` and `middleware.js`)
            // e.g.:
            // session: {
            //   options: {},
            //   fn: function (req, res, next) { ... }
            // }

          },

          // Extra options to pass directly into the Express server
          // when it is instantiated
          //      (or false to disable)
          //
          // This is the options object for the `createServer` method, as discussed here:
          // http://nodejs.org/docs/v0.10.20/api/https.html#https_class_https_server
          serverOptions: undefined,

          // Custom express middleware function to use
          customMiddleware: undefined,

          // Configures the middleware function used for parsing the HTTP request body
          // Defaults to the Formidable-based version built into Express/Connect
          //
          // To enable streaming file uploads (to disk or somewhere else)
          // you'll want to set this option to `false` to disable the body parser.
          //
          // Alternatively, if you're comfortable with the bleeding edge,
          // check out: https://github.com/balderdashy/skipper
          bodyParser: undefined,

          // Cookie parser middleware to use
          //      (or false to disable)
          //
          // Defaults to `express.cookieParser`
          //
          // Example override:
          // cookieParser: (function cookieParser (req, res, next) {})(),
          cookieParser: express.cookieParser,

          // HTTP method override middleware
          //      (or false to disable)
          //
          // This option allows artificial query params to be passed to trick
          // Express into thinking a different HTTP verb was used.
          // Useful when supporting an API for user-agents which don't allow
          // PUT or DELETE requests
          //
          // Defaults to `express.methodOverride`
          //
          // Example override:
          // methodOverride: (function customMethodOverride (req, res, next) {})()
          methodOverride: express.methodOverride

        }

      };
    },

    configure: function() {

      // If one piece of the ssl config is specified, ensure the other required piece is there
      if (sails.config.ssl && (
        sails.config.ssl.cert && !sails.config.ssl.key
      ) || (!sails.config.ssl.cert && sails.config.ssl.key)) {
        throw new Error('Invalid SSL config object!  Must include cert and key!');
      }

      if (sails.config.host) {
        sails.config.explicitHost = sails.config.host;
      }

      if (sails.config.express) {
        sails.log.warn('`sails.config.express` is deprecated; use `sails.config.http` instead.');
      }
      sails.util.defaultsDeep(sails.config.http, sails.config.express);

    },

    /**
     * Initialize is fired first thing when the hook is loaded
     * but after waiting for user config (if applicable)
     *
     * @api public
     */

    initialize: function(cb) {
      return initialize(cb);
    }
  };

};
<|endoftext|>


<commit_before>var _ = require('lodash');
var path = require('path');
var Promise = require("bluebird");
var request = Promise.promisifyAll(require("request"));
var fs = require("fs");
var config = require("config");
var log = require("../logger");

function FileIndexingError(message, fileName) {
    this.message = message;
    this.fileName = fileName;
    this.name = "FileIndexingError";
    //Error.captureStackTrace(this, FaileIndexingError);
}
FileIndexingError.prototype = Object.create(Error.prototype);
FileIndexingError.prototype.constructor = FileIndexingError;

function index(fileNames, extention, collectionName, callback) {
    var solr_extract_url = 'http://' + config.get("dbConfig.solr.host") + ':' +
        config.get("dbConfig.solr.port") +
        '/solr/' + collectionName + '/update/extract';
    log.info("Indexing %d files in the %s collection.", fileNames.length,
        collectionName)
    Promise.map(fileNames, function (fileName) {
        var appInfo = path.basename(fileName, extention).split('-');
        var package_name = appInfo[0];
        var version_code = appInfo[1];
        var app_id = package_name + "-" + version_code;
        var solrUpdateParams = {
            "literal.id": app_id,
            "literal.package_name": package_name,
            "literal.version_code": Number(version_code),
            "wt": "json",
            my_file: {
                value: fs.createReadStream(fileName),
                options: {
                    contentType: 'text/plain'
                }
            }
        };

        return request.postAsync({
            url: solr_extract_url,
            formData: solrUpdateParams
        }).get(1)
            .then(function (body) {
                var resHeader = JSON.parse(body).responseHeader;
                if (resHeader.status == 0) {
                    log.info("Successfully updated %s-%s", package_name,
                        version_code);
                }
                else {
                    throw new FileIndexingError("File indexing failed. " +
                        "Response Header: " + JSON.stringify(resHeader), fileName);
                }
            })
            .catch(FileIndexingError, function (e) {
                log.error('Indexing error. ' + e.message);
                throw e;
            })
    }, {concurrency: 1}).then(function () {
        return commit(collectionName)
    }).then(function () {
        callback(null);
    }).catch(FileIndexingError, function (e) {
        log.error("Failed to update %s. %s", e.fileName, e.message);
        callback(e);
    }).catch(function (e) {
        callback(e);
    })
}

function commit(collectionName) {
    var solr_update_url = 'http://' + config.get("dbConfig.solr.host") + ':' +
        config.get("dbConfig.solr.port") +
        '/solr/' + collectionName + '/update'
    // commit all pending updates
    return request.postAsync({
        headers: {'content-type': 'application/json'},
        url: solr_update_url,
        qs: {"commit": 'true', "wt": "json"}
    }).get(1)
        .then(function (body) {
            var resHeader = JSON.parse(body).responseHeader;
            if (resHeader.status == 0) {
                log.info("Successfully committed all pending operations.");
                //callback(null);
                return;
            }
            else {
                throw new Error('Failed to commit pending updates. Response: ' +
                    JSON.stringify(resHeader));
            }
        })
        .catch(function (e) {
            log.error(e.message);
            return Promise.reject(e);
        });
}

module.exports = {
    index: index, commit: commit
};<commit_msg>Fix crash caused by indexing error<commit_after>var _ = require('lodash');
var path = require('path');
var Promise = require("bluebird");
var request = Promise.promisifyAll(require("request"));
var fs = require("fs");
var config = require("config");
var log = require("../logger");

function FileIndexingError(message, fileName) {
    this.message = message;
    this.fileName = fileName;
    this.name = "FileIndexingError";
    //Error.captureStackTrace(this, FaileIndexingError);
}
FileIndexingError.prototype = Object.create(Error.prototype);
FileIndexingError.prototype.constructor = FileIndexingError;

function index(fileNames, extention, collectionName, callback) {
    var solr_extract_url = 'http://' + config.get("dbConfig.solr.host") + ':' +
        config.get("dbConfig.solr.port") +
        '/solr/' + collectionName + '/update/extract';
    log.info("Indexing %d files in the %s collection.", fileNames.length,
        collectionName)
    Promise.map(fileNames, function (fileName) {
        var appInfo = path.basename(fileName, extention).split('-');
        var package_name = appInfo[0];
        var version_code = appInfo[1];
        var app_id = package_name + "-" + version_code;
        var solrUpdateParams = {
            "literal.id": app_id,
            "literal.package_name": package_name,
            "literal.version_code": Number(version_code),
            "wt": "json",
            my_file: {
                value: fs.createReadStream(fileName),
                options: {
                    contentType: 'text/plain'
                }
            }
        };

        return request.postAsync({
            url: solr_extract_url,
            formData: solrUpdateParams
        }).get(1)
            .then(function (body) {
                var resHeader = JSON.parse(body).responseHeader;
                if (resHeader.status == 0) {
                    log.info("Successfully updated %s-%s", package_name,
                        version_code);
                }
                else {
                    throw new FileIndexingError("File indexing failed. " +
                        "Response Header: " + JSON.stringify(resHeader), fileName);
                }
            })
            .catch(FileIndexingError, function (e) {
                log.error('Indexing error. ' + e.message);
            })
    }, {concurrency: 1}).then(function () {
        return commit(collectionName)
    }).then(function () {
        callback(null);
    }).catch(FileIndexingError, function (e) {
        log.error("Failed to update %s. %s", e.fileName, e.message);
        callback(e);
    }).catch(function (e) {
        callback(e);
    })
}

function commit(collectionName) {
    var solr_update_url = 'http://' + config.get("dbConfig.solr.host") + ':' +
        config.get("dbConfig.solr.port") +
        '/solr/' + collectionName + '/update'
    // commit all pending updates
    return request.postAsync({
        headers: {'content-type': 'application/json'},
        url: solr_update_url,
        qs: {"commit": 'true', "wt": "json"}
    }).get(1)
        .then(function (body) {
            var resHeader = JSON.parse(body).responseHeader;
            if (resHeader.status == 0) {
                log.info("Successfully committed all pending operations.");
                //callback(null);
                return;
            }
            else {
                throw new Error('Failed to commit pending updates. Response: ' +
                    JSON.stringify(resHeader));
            }
        })
        .catch(function (e) {
            log.error(e.message);
            return Promise.reject(e);
        });
}

module.exports = {
    index: index, commit: commit
};<|endoftext|>