<commit_before>
// PLUGIN: Google Maps
var googleCallback;
(function ( Popcorn ) {

  var i = 1,
    _mapFired = false,
    _mapLoaded = false,
    geocoder, loadMaps;
  //google api callback
  googleCallback = function ( data ) {
    // ensure all of the maps functions needed are loaded
    // before setting _maploaded to true
    if ( typeof google !== "undefined" && google.maps && google.maps.Geocoder && google.maps.LatLng ) {
      geocoder = new google.maps.Geocoder();
      Popcorn.getScript( "//maps.stamen.com/js/tile.stamen.js", function() {
        _mapLoaded = true;
      });
    } else {
      setTimeout(function () {
        googleCallback( data );
      }, 1);
    }
  };
  // function that loads the google api
  loadMaps = function () {
    // for some reason the Google Map API adds content to the body
    if ( document.body ) {
      _mapFired = true;
      Popcorn.getScript( "//maps.google.com/maps/api/js?sensor=false&callback=googleCallback" );
    } else {
      setTimeout(function () {
        loadMaps();
      }, 1);
    }
  };

  function buildMap( options, location, mapDiv ) {
    var type = options.type ? options.type.toUpperCase() : "HYBRID",
      layer;

    // See if we need to make a custom Stamen map layer
    if ( type === "STAMEN-WATERCOLOR" ||
         type === "STAMEN-TERRAIN"    ||
         type === "STAMEN-TONER" ) {
      // Stamen types are lowercase
      layer = type.replace("STAMEN-", "").toLowerCase();
    }

    var map = new google.maps.Map( mapDiv, {
      // If a custom layer was specified, use that, otherwise use type
      mapTypeId: layer ? layer : google.maps.MapTypeId[ type ],
      // Hide the layer selection UI
      mapTypeControlOptions: { mapTypeIds: [] }
    });

    if ( layer ) {
      map.mapTypes.set( layer, new google.maps.StamenMapType( layer ));
    }
    map.getDiv().style.display = "none";

    return map;
  }

  /**
   * googlemap popcorn plug-in
   * Adds a map to the target div centered on the location specified by the user
   * Options parameter will need a start, end, target, type, zoom, lat and lng, and location
   * -Start is the time that you want this plug-in to execute
   * -End is the time that you want this plug-in to stop executing
   * -Target is the id of the DOM element that you want the map to appear in. This element must be in the DOM
   * -Type [optional] either: HYBRID (default), ROADMAP, SATELLITE, TERRAIN, STREETVIEW, or one of the
   *                          Stamen custom map types (http://http://maps.stamen.com): STAMEN-TONER,
   *                          STAMEN-WATERCOLOR, or STAMEN-TERRAIN.
   * -Zoom [optional] defaults to 0
   * -Heading [optional] STREETVIEW orientation of camera in degrees relative to true north (0 north, 90 true east, ect)
   * -Pitch [optional] STREETVIEW vertical orientation of the camera (between 1 and 3 is recommended)
   * -Lat and Lng: the coordinates of the map must be present if location is not specified.
   * -Height [optional] the height of the map, in "px" or "%". Defaults to "100%".
   * -Width [optional] the width of the map, in "px" or "%". Defaults to "100%".
   * -Location: the adress you want the map to display, must be present if lat and lng are not specified.
   * Note: using location requires extra loading time, also not specifying both lat/lng and location will
   * cause and error.
   *
   * Tweening works using the following specifications:
   * -location is the start point when using an auto generated route
   * -tween when used in this context is a string which specifies the end location for your route
   * Note that both location and tween must be present when using an auto generated route, or the map will not tween
   * -interval is the speed in which the tween will be executed, a reasonable time is 1000 ( time in milliseconds )
   * Heading, Zoom, and Pitch streetview values are also used in tweening with the autogenerated route
   *
   * -tween is an array of objects, each containing data for one frame of a tween
   * -position is an object with has two paramaters, lat and lng, both which are mandatory for a tween to work
   * -pov is an object which houses heading, pitch, and zoom paramters, which are all optional, if undefined, these values default to 0
   * -interval is the speed in which the tween will be executed, a reasonable time is 1000 ( time in milliseconds )
   *
   * @param {Object} options
   *
   * Example:
   var p = Popcorn("#video")
   .googlemap({
   start: 5, // seconds
   end: 15, // seconds
   type: "ROADMAP",
   target: "map",
   lat: 43.665429,
   lng: -79.403323
   } )
   *
   */
  Popcorn.plugin( "googlemap", function ( options ) {
    var newdiv, map, location,
        target = document.getElementById( options.target );

    options.type = options.type || "ROADMAP";
    options.zoom = options.zoom || 1;
    options.lat = options.lat || 0;
    options.lng = options.lng || 0;

    // if this is the firest time running the plugins
    // call the function that gets the sctipt
    if ( !_mapFired ) {
      loadMaps();
    }

    // create a new div this way anything in the target div is left intact
    // this is later passed on to the maps api
    newdiv = document.createElement( "div" );
    newdiv.id = "actualmap" + i;
    newdiv.style.width = options.width || "100%";

    // height is a little more complicated than width.
    if ( options.height ) {
      newdiv.style.height = options.height;
    } else if ( target && target.clientHeight ) {
      newdiv.style.height = target.clientHeight + "px";
    } else {
      newdiv.style.height = "100%";
    }

    i++;

    // ensure the target container the user chose exists
    if ( !target && Popcorn.plugin.debug ) {
      throw new Error( "target container doesn't exist" );
    }
    target && target.appendChild( newdiv );

    // ensure that google maps and its functions are loaded
    // before setting up the map parameters
    var isMapReady = function () {
      if ( _mapLoaded ) {
        if ( newdiv ) {
          if ( options.location ) {
            // calls an anonymous google function called on separate thread
            geocoder.geocode({
              "address": options.location
            }, function ( results, status ) {
              if ( status === google.maps.GeocoderStatus.OK ) {
                options.lat = results[ 0 ].geometry.location.lat();
                options.lng = results[ 0 ].geometry.location.lng();
                location = new google.maps.LatLng( options.lat, options.lng );
                map = buildMap( options, location, newdiv );
              }
            });
          } else {
            location = new google.maps.LatLng( options.lat, options.lng );
            map = buildMap( options, location, newdiv );
          }
        }
      } else {
          setTimeout(function () {
            isMapReady();
          }, 5);
        }
      };

    isMapReady();

    return {
      /**
       * @member webpage
       * The start function will be executed when the currentTime
       * of the video reaches the start time provided by the
       * options variable
       */
      start: function( event, options ) {
        var that = this,
            sView;

        // ensure the map has been initialized in the setup function above
        var isMapSetup = function() {
          if ( map ) {
            map.getDiv().style.display = "block";
            // reset the location and zoom just in case the user plaid with the map
            google.maps.event.trigger( map, "resize" );
            map.setCenter( location );

            // make sure options.zoom is a number
            if ( options.zoom && typeof options.zoom !== "number" ) {
              options.zoom = +options.zoom;
            }

            map.setZoom( options.zoom );

            //Make sure heading is a number
            if ( options.heading && typeof options.heading !== "number" ) {
              options.heading = +options.heading;
            }
            //Make sure pitch is a number
            if ( options.pitch && typeof options.pitch !== "number" ) {
              options.pitch = +options.pitch;
            }

            if ( options.type === "STREETVIEW" ) {
              // Switch this map into streeview mode
              map.setStreetView(
              // Pass a new StreetViewPanorama instance into our map

                sView = new google.maps.StreetViewPanorama( newdiv, {
                  position: location,
                  pov: {
                    heading: options.heading = options.heading || 0,
                    pitch: options.pitch = options.pitch || 0,
                    zoom: options.zoom
                  }
                })
              );

              //  Function to handle tweening using a set timeout
              var tween = function( rM, t ) {

                var computeHeading = google.maps.geometry.spherical.computeHeading;
                setTimeout(function() {

                  var current_time = that.media.currentTime;

                  //  Checks whether this is a generated route or not
                  if ( typeof options.tween === "object" ) {

                    for ( var i = 0, m = rM.length; i < m; i++ ) {

                      var waypoint = rM[ i ];

                      //  Checks if this position along the tween should be displayed or not
                      if ( current_time >= ( waypoint.interval * ( i + 1 ) ) / 1000 &&
                         ( current_time <= ( waypoint.interval * ( i + 2 ) ) / 1000 ||
                           current_time >= waypoint.interval * ( m ) / 1000 ) ) {

                        sView3.setPosition( new google.maps.LatLng( waypoint.position.lat, waypoint.position.lng ) );

                        sView3.setPov({
                          heading: waypoint.pov.heading || computeHeading( waypoint, rM[ i + 1 ] ) || 0,
                          zoom: waypoint.pov.zoom || 0,
                          pitch: waypoint.pov.pitch || 0
                        });
                      }
                    }

                    //  Calls the tween function again at the interval set by the user
                    tween( rM, rM[ 0 ].interval );
                  } else {

                    for ( var k = 0, l = rM.length; k < l; k++ ) {

                      var interval = options.interval;

                      if( current_time >= (interval * ( k + 1 ) ) / 1000 &&
                        ( current_time <= (interval * ( k + 2 ) ) / 1000 ||
                          current_time >= interval * ( l ) / 1000 ) ) {

                        sView2.setPov({
                          heading: computeHeading( rM[ k ], rM[ k + 1 ] ) || 0,
                          zoom: options.zoom,
                          pitch: options.pitch || 0
                        });
                        sView2.setPosition( checkpoints[ k ] );
                      }
                    }

                    tween( checkpoints, options.interval );
                  }
                }, t );
              };

              //  Determines if we should use hardcoded values ( using options.tween ),
              //  or if we should use a start and end location and let google generate
              //  the route for us
              if ( options.location && typeof options.tween === "string" ) {

              //  Creating another variable to hold the streetview map for tweening,
              //  Doing this because if there was more then one streetview map, the tweening would sometimes appear in other maps
              var sView2 = sView;

                //  Create an array to store all the lat/lang values along our route
                var checkpoints = [];

                //  Creates a new direction service, later used to create a route
                var directionsService = new google.maps.DirectionsService();

                //  Creates a new direction renderer using the current map
                //  This enables us to access all of the route data that is returned to us
                var directionsDisplay = new google.maps.DirectionsRenderer( sView2 );

                var request = {
                  origin: options.location,
                  destination: options.tween,
                  travelMode: google.maps.TravelMode.DRIVING
                };

                //  Create the route using the direction service and renderer
                directionsService.route( request, function( response, status ) {

                  if ( status == google.maps.DirectionsStatus.OK ) {
                    directionsDisplay.setDirections( response );
                    showSteps( response, that );
                  }

                });

                var showSteps = function ( directionResult, that ) {

                  //  Push new google map lat and lng values into an array from our list of lat and lng values
                  var routes = directionResult.routes[ 0 ].overview_path;
                  for ( var j = 0, k = routes.length; j < k; j++ ) {
                    checkpoints.push( new google.maps.LatLng( routes[ j ].lat(), routes[ j ].lng() ) );
                  }

                  //  Check to make sure the interval exists, if not, set to a default of 1000
                  options.interval = options.interval || 1000;
                  tween( checkpoints, 10 );

                };
              } else if ( typeof options.tween === "object" ) {

                //  Same as the above to stop streetview maps from overflowing into one another
                var sView3 = sView;

                for ( var i = 0, l = options.tween.length; i < l; i++ ) {

                  //  Make sure interval exists, if not, set to 1000
                  options.tween[ i ].interval = options.tween[ i ].interval || 1000;
                  tween( options.tween, 10 );
                }
              }
            }
          } else {
            setTimeout(function () {
              isMapSetup();
            }, 13);
          }
        };
        isMapSetup();
      },
      /**
       * @member webpage
       * The end function will be executed when the currentTime
       * of the video reaches the end time provided by the
       * options variable
       */
      end: function ( event, options ) {
        // if the map exists hide it do not delete the map just in
        // case the user seeks back to time b/w start and end
        if ( map ) {
          map.getDiv().style.display = "none";
        }
      },
      _teardown: function ( options ) {

        var target = document.getElementById( options.target );

        // the map must be manually removed
        target && target.removeChild( newdiv );
        newdiv = map = location = null;
      }
    };
  }, {
    about: {
      name: "Popcorn Google Map Plugin",
      version: "0.1",
      author: "@annasob",
      website: "annasob.wordpress.com"
    },
    options: {
      start: {
        elem: "input",
        type: "text",
        label: "In"
      },
      end: {
        elem: "input",
        type: "text",
        label: "Out"
      },
      target: "map-container",
      type: {
        elem: "select",
        options: [ "ROADMAP", "SATELLITE", "STREETVIEW", "HYBRID", "TERRAIN", "STAMEN-WATERCOLOR", "STAMEN-TERRAIN", "STAMEN-TONER" ],
        label: "Type",
        optional: true
      },
      zoom: {
        elem: "input",
        type: "text",
        label: "Zoom",
        "default": 0,
        optional: true
      },
      lat: {
        elem: "input",
        type: "text",
        label: "Lat",
        optional: true
      },
      lng: {
        elem: "input",
        type: "text",
        label: "Lng",
        optional: true
      },
      location: {
        elem: "input",
        type: "text",
        label: "Location",
        "default": "Toronto, Ontario, Canada"
      },
      heading: {
        elem: "input",
        type: "text",
        label: "Heading",
        "default": 0,
        optional: true
      },
      pitch: {
        elem: "input",
        type: "text",
        label: "Pitch",
        "default": 1,
        optional: true
      }
    }
  });
})( Popcorn );

<commit_msg>[t1184] exposed googlemap map as _map<commit_after>
// PLUGIN: Google Maps
var googleCallback;
(function ( Popcorn ) {

  var i = 1,
    _mapFired = false,
    _mapLoaded = false,
    geocoder, loadMaps;
  //google api callback
  googleCallback = function ( data ) {
    // ensure all of the maps functions needed are loaded
    // before setting _maploaded to true
    if ( typeof google !== "undefined" && google.maps && google.maps.Geocoder && google.maps.LatLng ) {
      geocoder = new google.maps.Geocoder();
      Popcorn.getScript( "//maps.stamen.com/js/tile.stamen.js", function() {
        _mapLoaded = true;
      });
    } else {
      setTimeout(function () {
        googleCallback( data );
      }, 1);
    }
  };
  // function that loads the google api
  loadMaps = function () {
    // for some reason the Google Map API adds content to the body
    if ( document.body ) {
      _mapFired = true;
      Popcorn.getScript( "//maps.google.com/maps/api/js?sensor=false&callback=googleCallback" );
    } else {
      setTimeout(function () {
        loadMaps();
      }, 1);
    }
  };

  function buildMap( options, location, mapDiv ) {
    var type = options.type ? options.type.toUpperCase() : "HYBRID",
      layer;

    // See if we need to make a custom Stamen map layer
    if ( type === "STAMEN-WATERCOLOR" ||
         type === "STAMEN-TERRAIN"    ||
         type === "STAMEN-TONER" ) {
      // Stamen types are lowercase
      layer = type.replace("STAMEN-", "").toLowerCase();
    }

    var map = new google.maps.Map( mapDiv, {
      // If a custom layer was specified, use that, otherwise use type
      mapTypeId: layer ? layer : google.maps.MapTypeId[ type ],
      // Hide the layer selection UI
      mapTypeControlOptions: { mapTypeIds: [] }
    });

    if ( layer ) {
      map.mapTypes.set( layer, new google.maps.StamenMapType( layer ));
    }
    map.getDiv().style.display = "none";

    return map;
  }

  /**
   * googlemap popcorn plug-in
   * Adds a map to the target div centered on the location specified by the user
   * Options parameter will need a start, end, target, type, zoom, lat and lng, and location
   * -Start is the time that you want this plug-in to execute
   * -End is the time that you want this plug-in to stop executing
   * -Target is the id of the DOM element that you want the map to appear in. This element must be in the DOM
   * -Type [optional] either: HYBRID (default), ROADMAP, SATELLITE, TERRAIN, STREETVIEW, or one of the
   *                          Stamen custom map types (http://http://maps.stamen.com): STAMEN-TONER,
   *                          STAMEN-WATERCOLOR, or STAMEN-TERRAIN.
   * -Zoom [optional] defaults to 0
   * -Heading [optional] STREETVIEW orientation of camera in degrees relative to true north (0 north, 90 true east, ect)
   * -Pitch [optional] STREETVIEW vertical orientation of the camera (between 1 and 3 is recommended)
   * -Lat and Lng: the coordinates of the map must be present if location is not specified.
   * -Height [optional] the height of the map, in "px" or "%". Defaults to "100%".
   * -Width [optional] the width of the map, in "px" or "%". Defaults to "100%".
   * -Location: the adress you want the map to display, must be present if lat and lng are not specified.
   * Note: using location requires extra loading time, also not specifying both lat/lng and location will
   * cause and error.
   *
   * Tweening works using the following specifications:
   * -location is the start point when using an auto generated route
   * -tween when used in this context is a string which specifies the end location for your route
   * Note that both location and tween must be present when using an auto generated route, or the map will not tween
   * -interval is the speed in which the tween will be executed, a reasonable time is 1000 ( time in milliseconds )
   * Heading, Zoom, and Pitch streetview values are also used in tweening with the autogenerated route
   *
   * -tween is an array of objects, each containing data for one frame of a tween
   * -position is an object with has two paramaters, lat and lng, both which are mandatory for a tween to work
   * -pov is an object which houses heading, pitch, and zoom paramters, which are all optional, if undefined, these values default to 0
   * -interval is the speed in which the tween will be executed, a reasonable time is 1000 ( time in milliseconds )
   *
   * @param {Object} options
   *
   * Example:
   var p = Popcorn("#video")
   .googlemap({
   start: 5, // seconds
   end: 15, // seconds
   type: "ROADMAP",
   target: "map",
   lat: 43.665429,
   lng: -79.403323
   } )
   *
   */
  Popcorn.plugin( "googlemap", function ( options ) {
    var newdiv, map, location,
        target = document.getElementById( options.target );

    options.type = options.type || "ROADMAP";
    options.zoom = options.zoom || 1;
    options.lat = options.lat || 0;
    options.lng = options.lng || 0;

    // if this is the firest time running the plugins
    // call the function that gets the sctipt
    if ( !_mapFired ) {
      loadMaps();
    }

    // create a new div this way anything in the target div is left intact
    // this is later passed on to the maps api
    newdiv = document.createElement( "div" );
    newdiv.id = "actualmap" + i;
    newdiv.style.width = options.width || "100%";

    // height is a little more complicated than width.
    if ( options.height ) {
      newdiv.style.height = options.height;
    } else if ( target && target.clientHeight ) {
      newdiv.style.height = target.clientHeight + "px";
    } else {
      newdiv.style.height = "100%";
    }

    i++;

    // ensure the target container the user chose exists
    if ( !target && Popcorn.plugin.debug ) {
      throw new Error( "target container doesn't exist" );
    }
    target && target.appendChild( newdiv );

    // ensure that google maps and its functions are loaded
    // before setting up the map parameters
    var isMapReady = function () {
      if ( _mapLoaded ) {
        if ( newdiv ) {
          if ( options.location ) {
            // calls an anonymous google function called on separate thread
            geocoder.geocode({
              "address": options.location
            }, function ( results, status ) {
              if ( status === google.maps.GeocoderStatus.OK ) {
                options.lat = results[ 0 ].geometry.location.lat();
                options.lng = results[ 0 ].geometry.location.lng();
                location = new google.maps.LatLng( options.lat, options.lng );
                map = buildMap( options, location, newdiv );
              }
            });
          } else {
            location = new google.maps.LatLng( options.lat, options.lng );
            map = buildMap( options, location, newdiv );
          }
        }
      } else {
          setTimeout(function () {
            isMapReady();
          }, 5);
        }
      };

    isMapReady();

    return {
      /**
       * @member webpage
       * The start function will be executed when the currentTime
       * of the video reaches the start time provided by the
       * options variable
       */
      start: function( event, options ) {
        var that = this,
            sView;

        // ensure the map has been initialized in the setup function above
        var isMapSetup = function() {
          if ( map ) {
            options._map = map;

            map.getDiv().style.display = "block";
            // reset the location and zoom just in case the user plaid with the map
            google.maps.event.trigger( map, "resize" );
            map.setCenter( location );

            // make sure options.zoom is a number
            if ( options.zoom && typeof options.zoom !== "number" ) {
              options.zoom = +options.zoom;
            }

            map.setZoom( options.zoom );

            //Make sure heading is a number
            if ( options.heading && typeof options.heading !== "number" ) {
              options.heading = +options.heading;
            }
            //Make sure pitch is a number
            if ( options.pitch && typeof options.pitch !== "number" ) {
              options.pitch = +options.pitch;
            }

            if ( options.type === "STREETVIEW" ) {
              // Switch this map into streeview mode
              map.setStreetView(
              // Pass a new StreetViewPanorama instance into our map

                sView = new google.maps.StreetViewPanorama( newdiv, {
                  position: location,
                  pov: {
                    heading: options.heading = options.heading || 0,
                    pitch: options.pitch = options.pitch || 0,
                    zoom: options.zoom
                  }
                })
              );

              //  Function to handle tweening using a set timeout
              var tween = function( rM, t ) {

                var computeHeading = google.maps.geometry.spherical.computeHeading;
                setTimeout(function() {

                  var current_time = that.media.currentTime;

                  //  Checks whether this is a generated route or not
                  if ( typeof options.tween === "object" ) {

                    for ( var i = 0, m = rM.length; i < m; i++ ) {

                      var waypoint = rM[ i ];

                      //  Checks if this position along the tween should be displayed or not
                      if ( current_time >= ( waypoint.interval * ( i + 1 ) ) / 1000 &&
                         ( current_time <= ( waypoint.interval * ( i + 2 ) ) / 1000 ||
                           current_time >= waypoint.interval * ( m ) / 1000 ) ) {

                        sView3.setPosition( new google.maps.LatLng( waypoint.position.lat, waypoint.position.lng ) );

                        sView3.setPov({
                          heading: waypoint.pov.heading || computeHeading( waypoint, rM[ i + 1 ] ) || 0,
                          zoom: waypoint.pov.zoom || 0,
                          pitch: waypoint.pov.pitch || 0
                        });
                      }
                    }

                    //  Calls the tween function again at the interval set by the user
                    tween( rM, rM[ 0 ].interval );
                  } else {

                    for ( var k = 0, l = rM.length; k < l; k++ ) {

                      var interval = options.interval;

                      if( current_time >= (interval * ( k + 1 ) ) / 1000 &&
                        ( current_time <= (interval * ( k + 2 ) ) / 1000 ||
                          current_time >= interval * ( l ) / 1000 ) ) {

                        sView2.setPov({
                          heading: computeHeading( rM[ k ], rM[ k + 1 ] ) || 0,
                          zoom: options.zoom,
                          pitch: options.pitch || 0
                        });
                        sView2.setPosition( checkpoints[ k ] );
                      }
                    }

                    tween( checkpoints, options.interval );
                  }
                }, t );
              };

              //  Determines if we should use hardcoded values ( using options.tween ),
              //  or if we should use a start and end location and let google generate
              //  the route for us
              if ( options.location && typeof options.tween === "string" ) {

              //  Creating another variable to hold the streetview map for tweening,
              //  Doing this because if there was more then one streetview map, the tweening would sometimes appear in other maps
              var sView2 = sView;

                //  Create an array to store all the lat/lang values along our route
                var checkpoints = [];

                //  Creates a new direction service, later used to create a route
                var directionsService = new google.maps.DirectionsService();

                //  Creates a new direction renderer using the current map
                //  This enables us to access all of the route data that is returned to us
                var directionsDisplay = new google.maps.DirectionsRenderer( sView2 );

                var request = {
                  origin: options.location,
                  destination: options.tween,
                  travelMode: google.maps.TravelMode.DRIVING
                };

                //  Create the route using the direction service and renderer
                directionsService.route( request, function( response, status ) {

                  if ( status == google.maps.DirectionsStatus.OK ) {
                    directionsDisplay.setDirections( response );
                    showSteps( response, that );
                  }

                });

                var showSteps = function ( directionResult, that ) {

                  //  Push new google map lat and lng values into an array from our list of lat and lng values
                  var routes = directionResult.routes[ 0 ].overview_path;
                  for ( var j = 0, k = routes.length; j < k; j++ ) {
                    checkpoints.push( new google.maps.LatLng( routes[ j ].lat(), routes[ j ].lng() ) );
                  }

                  //  Check to make sure the interval exists, if not, set to a default of 1000
                  options.interval = options.interval || 1000;
                  tween( checkpoints, 10 );

                };
              } else if ( typeof options.tween === "object" ) {

                //  Same as the above to stop streetview maps from overflowing into one another
                var sView3 = sView;

                for ( var i = 0, l = options.tween.length; i < l; i++ ) {

                  //  Make sure interval exists, if not, set to 1000
                  options.tween[ i ].interval = options.tween[ i ].interval || 1000;
                  tween( options.tween, 10 );
                }
              }
            }
          } else {
            setTimeout(function () {
              isMapSetup();
            }, 13);
          }
        };
        isMapSetup();
      },
      /**
       * @member webpage
       * The end function will be executed when the currentTime
       * of the video reaches the end time provided by the
       * options variable
       */
      end: function ( event, options ) {
        // if the map exists hide it do not delete the map just in
        // case the user seeks back to time b/w start and end
        if ( map ) {
          map.getDiv().style.display = "none";
        }
      },
      _teardown: function ( options ) {

        var target = document.getElementById( options.target );

        // the map must be manually removed
        target && target.removeChild( newdiv );
        newdiv = map = location = null;

        options._map = null;
      }
    };
  }, {
    about: {
      name: "Popcorn Google Map Plugin",
      version: "0.1",
      author: "@annasob",
      website: "annasob.wordpress.com"
    },
    options: {
      start: {
        elem: "input",
        type: "text",
        label: "In"
      },
      end: {
        elem: "input",
        type: "text",
        label: "Out"
      },
      target: "map-container",
      type: {
        elem: "select",
        options: [ "ROADMAP", "SATELLITE", "STREETVIEW", "HYBRID", "TERRAIN", "STAMEN-WATERCOLOR", "STAMEN-TERRAIN", "STAMEN-TONER" ],
        label: "Type",
        optional: true
      },
      zoom: {
        elem: "input",
        type: "text",
        label: "Zoom",
        "default": 0,
        optional: true
      },
      lat: {
        elem: "input",
        type: "text",
        label: "Lat",
        optional: true
      },
      lng: {
        elem: "input",
        type: "text",
        label: "Lng",
        optional: true
      },
      location: {
        elem: "input",
        type: "text",
        label: "Location",
        "default": "Toronto, Ontario, Canada"
      },
      heading: {
        elem: "input",
        type: "text",
        label: "Heading",
        "default": 0,
        optional: true
      },
      pitch: {
        elem: "input",
        type: "text",
        label: "Pitch",
        "default": 1,
        optional: true
      }
    }
  });
})( Popcorn );

<|endoftext|>


<commit_before>/**
 * @preserve
 *
 *                                     .,,,;;,'''..
 *                                 .'','...     ..',,,.
 *                               .,,,,,,',,',;;:;,.  .,l,
 *                              .,',.     ...     ,;,   :l.
 *                             ':;.    .'.:do;;.    .c   ol;'.
 *      ';;'                   ;.;    ', .dkl';,    .c   :; .'.',::,,'''.
 *     ',,;;;,.                ; .,'     .'''.    .'.   .d;''.''''.
 *    .oxddl;::,,.             ',  .'''.   .... .'.   ,:;..
 *     .'cOX0OOkdoc.            .,'.   .. .....     'lc.
 *    .:;,,::co0XOko'              ....''..'.'''''''.
 *    .dxk0KKdc:cdOXKl............. .. ..,c....
 *     .',lxOOxl:'':xkl,',......'....    ,'.
 *          .';:oo:...                        .
 *               .cd,    ╔═╗┌─┐┬─┐┬  ┬┌─┐┬─┐   .
 *                 .l;   ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘   '
 *                   'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─  '.
 *                    .o.                   ...
 *                     .''''','.;:''.........
 *                          .'  .l
 *                         .:.   l'
 *                        .:.    .l.
 *                       .x:      :k;,.
 *                       cxlc;    cdc,,;;.
 *                      'l :..   .c  ,
 *                      o.
 *                     .,
 *
 *             ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐  ╔═╗┌┐  ┬┌─┐┌─┐┌┬┐┌─┐
 *             ╠═╣└┬┘├┴┐├┬┘│ ││  ║ ║├┴┐ │├┤ │   │ └─┐
 *             ╩ ╩ ┴ └─┘┴└─┴─┴┘  ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘
 *
 * Created by Valentin on 10/22/14.
 * Modified by Carsten on 12/06/15.
 *
 * Copyright (c) 2015 Valentin Heun
 *
 * All ascii characters above must be included in any redistribution.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/**
 * Set to true to enable the hardware interface
 **/
exports.enabled = false;

if (exports.enabled) {
/**
 * @desc This function is called once by the server. Start the event loop of your hardware interface in here.
 **/
    exports.receive = function () {

};

/**
 * @desc This function is called by the server whenever data for one of your HybridObject's IO points arrives. Parse the input and write the
 *       value to your hardware.
 * @param {string} objName Name of the HybridObject
 * @param {string} ioName Name of the IO point
 * @param {value} value The value
 * @param {string} mode Specifies the datatype of value
 * @param {type} type The type
 **/
exports.send = function (objName, ioName, value, mode, type) {

};

/**
 * @desc prototype for an interface init. The init reinitialize the communication with the external source.
 *       Place calls to addIO(), clearIO(), developerOn(), developerOff(), writeIOToServer() here. Call clearIO() after you have added all the IO points with addIO() calls.
 * @note program the init so that it can be called anytime there is a change to the amount of objects.
 **/
    exports.init = function () {

};

/**
 * @desc This function is called once by the server when the process is being torn down.
 *       Clean up open file handles or resources and return quickly.
 **/
    exports.shutdown = function () {

};

}<commit_msg>Updated comments<commit_after>/**
 * @preserve
 *
 *                                     .,,,;;,'''..
 *                                 .'','...     ..',,,.
 *                               .,,,,,,',,',;;:;,.  .,l,
 *                              .,',.     ...     ,;,   :l.
 *                             ':;.    .'.:do;;.    .c   ol;'.
 *      ';;'                   ;.;    ', .dkl';,    .c   :; .'.',::,,'''.
 *     ',,;;;,.                ; .,'     .'''.    .'.   .d;''.''''.
 *    .oxddl;::,,.             ',  .'''.   .... .'.   ,:;..
 *     .'cOX0OOkdoc.            .,'.   .. .....     'lc.
 *    .:;,,::co0XOko'              ....''..'.'''''''.
 *    .dxk0KKdc:cdOXKl............. .. ..,c....
 *     .',lxOOxl:'':xkl,',......'....    ,'.
 *          .';:oo:...                        .
 *               .cd,    ╔═╗┌─┐┬─┐┬  ┬┌─┐┬─┐   .
 *                 .l;   ╚═╗├┤ ├┬┘└┐┌┘├┤ ├┬┘   '
 *                   'l. ╚═╝└─┘┴└─ └┘ └─┘┴└─  '.
 *                    .o.                   ...
 *                     .''''','.;:''.........
 *                          .'  .l
 *                         .:.   l'
 *                        .:.    .l.
 *                       .x:      :k;,.
 *                       cxlc;    cdc,,;;.
 *                      'l :..   .c  ,
 *                      o.
 *                     .,
 *
 *             ╦ ╦┬ ┬┌┐ ┬─┐┬┌┬┐  ╔═╗┌┐  ┬┌─┐┌─┐┌┬┐┌─┐
 *             ╠═╣└┬┘├┴┐├┬┘│ ││  ║ ║├┴┐ │├┤ │   │ └─┐
 *             ╩ ╩ ┴ └─┘┴└─┴─┴┘  ╚═╝└─┘└┘└─┘└─┘ ┴ └─┘
 *
 * Created by Valentin on 10/22/14.
 * Modified by Carsten on 12/06/15.
 *
 * Copyright (c) 2015 Valentin Heun
 *
 * All ascii characters above must be included in any redistribution.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/**
 * Set to true to enable the hardware interface
 **/
exports.enabled = false;

if (exports.enabled) {
/**
 * @desc This function is called once by the server. Start the event loop of your hardware interface in here. Call writeIOToServer()
 *       whenever you receive new values from your hardware and you want to send the data to the server
 **/
    exports.receive = function () {

};

/**
 * @desc This function is called by the server whenever data for one of your HybridObject's IO points arrives. Parse the input and write the
 *       value to your hardware.
 * @param {string} objName Name of the HybridObject
 * @param {string} ioName Name of the IO point
 * @param {value} value The value
 * @param {string} mode Specifies the datatype of value
 * @param {type} type The type
 **/
exports.send = function (objName, ioName, value, mode, type) {

};

/**
 * @desc prototype for an interface init. The init reinitialize the communication with the external source.
 *       Place calls to addIO() and clearIO() here. Call clearIO() after you have added all the IO points with addIO() calls.
 * @note program the init so that it can be called anytime there is a change to the amount of objects.
 **/
    exports.init = function () {

};

/**
 * @desc This function is called once by the server when the process is being torn down.
 *       Clean up open file handles or resources and return quickly.
 **/
    exports.shutdown = function () {

};

}
<|endoftext|>


<commit_before>import './About.css';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import Gravatar from 'react-gravatar';
import Header from 'shared/containers/header/Header';
import MaterialIcon from 'shared/components/icon/MaterialIcon';
import SvgIcon from 'shared/components/icon/SvgIcon';
import keymetricsLogo from 'file!./logos/keymetrics.svg';
import opbeatLogo from 'file!./logos/opbeat.svg';

// TODO: split each section in its own component?
// TODO: add screenshots of npmjs search results

class About extends Component {
    render() {
        return (

About

                        npms - which stands for npm search - was built to empower the JavaScript
                        community by providing a better and open source search for node packages.

                    { /* ------------- Why ------------- */ }

Why?

                            npmjs.com allows developers to search for node packages, but,
                            having used it for several years, I always felt that the overall experience and quality of the results were bad.

                            The official search is powered by Elasticsearch but no advanced analyzers were
                            configured. More specifically, no stemming nor split word are
                            enabled. What does this mean for you? Try searching for "couchdb promise" and "couchdb promises" and see how different the search results are.
                            Imagine how many packages you lost on your previous searches because of this.

                            When a list of results is presented to you on the screen, the order of the results are simply based on the
                            relevance they have to the search terms. npmjs.com search does
                            not take into account the packages value to rank good packages higher. Because of this, users must manually
                            analyze the search results one by one, taking into consideration several attributes such as the package's
                            version (> 1.0.0?), the downloads count, the latest publish date, the number of GitHub issues,
                            stars, forks, etc. This process is tedious and slow.

                    { /* ------------- How it works ------------- */ }

How it works

                            The npms analyzer continuously analyzes npm ecosystem,
                            gathering as much information as possible from a variety of sources, including GitHub, david and nsp.

                            Using the collected information, a final score for each package is calculated based on four different aspects:

                                <MaterialIcon id="high_quality" />

Quality

                                        Quality attributes are easy to calculate because they are self contained.
                                        These are the kind of attributes that a person looks first when looking at the package.

Has README? Has license? Has .gitignore and friends?

Is the version stable (> 1.x.x)? Is it deprecated?

Has tests? Whats their coverage %? Is build passing?

Has outdated dependencies? Do they have vulnerabilities?

Has custom website? Has badges?

Does the project have linters configured?

                                <MaterialIcon id="build" />

Maintenance

                                        Maintenance attributes allows us to understand if the package is active & healthy or if it is
                                        abandoned. These are typically the second kind of attributes that a person looks when looking at
                                        the package.

Ratio of open issues vs total issues

The time it takes to close issues

Most recent commit

Commit frequency

Release frequency

                                <MaterialIcon id="star_half" />

Popularity

                                        Popularity attributes allows us to understand the package adoption and community size.

                                        These are the kind of attributes that a person looks when they are undecided on the package choice.

Number of stars

Number of forks

Number of subscribers

Number of contributors

Number of dependents

Number of downloads

Downloads acceleration

                                <MaterialIcon id="record_voice_over" />

Personalities

                                        If two packages are similar, one tends to choose the one in which the author is well known in the
                                        community.

                                        Relationships between people are also important. When an user follows another, there's a bound
                                        between them. We can infer that people prefer packages from the users they follow.

                                        As of this writing the personalities attributes are not yet implemented.

If you want to know more, you may look at the architecture document.

                    { /* ------------- Get involved ------------- */ }

Get involved

                            npms is open-source and we still have some work to do.
                            Any contributions, ideas or bug reports are welcome. Visit our GitHub and help us!

                            Feel free to reach us directly via email or Twitter.

                    { /* ------------- Sponsors ------------- */ }

Sponsors

                                    Opbeat allows us to monitor our services performance, from backend to frontend.
                                    Additionally, Opbeat is supporting npms by generously paying for our hosting expenses.

                                    We use PM2 to deploy our services
                                    and Keymetrics provides an easy way to manage these deployments and to monitor the production machines.

                            We are using money from our own pockets to provide this service to you. Donations are welcome.
                            If you would like to sponsor this project, feel free to reach us.

                    { /* ------------- Authors ------------- */ }

Authors

                                    <Gravatar size={ 130 } email="andremiguelcruz@msn.com" className="avatar" https />

André Cruz

                                            <SvgIcon id={ SvgIcon.twitter } />

                                            <SvgIcon id={ SvgIcon.github } />

                                    <Gravatar size={ 130 } email="mail@andreduarte.net" className="avatar" https />

André Duarte

                                            <SvgIcon id={ SvgIcon.twitter } />

                                            <SvgIcon id={ SvgIcon.github } />

Special thanks

Cátia Santos for the website design

José Bateira for the initial effort put into this project

        );
    }
}

About.propTypes = {
    dispatch: PropTypes.func.isRequired,
};

export default connect()(About);
<commit_msg>Fix typos in About page (#130)<commit_after>import './About.css';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import Gravatar from 'react-gravatar';
import Header from 'shared/containers/header/Header';
import MaterialIcon from 'shared/components/icon/MaterialIcon';
import SvgIcon from 'shared/components/icon/SvgIcon';
import keymetricsLogo from 'file!./logos/keymetrics.svg';
import opbeatLogo from 'file!./logos/opbeat.svg';

// TODO: split each section in its own component?
// TODO: add screenshots of npmjs search results

class About extends Component {
    render() {
        return (

About

                        npms - which stands for npm search - was built to empower the JavaScript
                        community by providing a better and open source search for node packages.

                    { /* ------------- Why ------------- */ }

Why?

                            npmjs.com allows developers to search for node packages, but,
                            having used it for several years, I always felt that the overall experience and quality of the results were bad.

                            The official search is powered by Elasticsearch but no advanced analyzers were
                            configured. More specifically, no stemming nor split word are
                            enabled. What does this mean for you? Try searching for "couchdb promise" and "couchdb promises" and see how different the search results are.
                            Imagine how many packages you lost on your previous searches because of this.

                            When a list of results is presented to you on the screen, the order of the results are simply based on the
                            relevance they have to the search terms. npmjs.com search does
                            not take into account the package's value to rank good packages higher. Because of this, users must manually
                            analyze the search results one by one, taking into consideration several attributes such as the package's
                            version (> 1.0.0?), the downloads count, the latest publish date, the number of GitHub issues,
                            stars, forks, etc. This process is tedious and slow.

                    { /* ------------- How it works ------------- */ }

How it works

                            The npms analyzer continuously analyzes the npm ecosystem,
                            gathering as much information as possible from a variety of sources, including GitHub, David and nsp.

                            Using the collected information, a final score for each package is calculated based on four different aspects:

                                <MaterialIcon id="high_quality" />

Quality

                                        Quality attributes are easy to calculate because they are self-contained.
                                        These are the kind of attributes that a person looks at first when checking out a package.

Has README? Has license? Has .gitignore and friends?

Is the version stable (> 1.x.x)? Is it deprecated?

Has tests? What's their coverage %? Is the build passing?

Has outdated dependencies? Do they have vulnerabilities?

Has custom website? Has badges?

Are there linters configured?

                                <MaterialIcon id="build" />

Maintenance

                                        Maintenance attributes allows us to understand if the package is active and healthy or if it is
                                        abandoned. These are typically the second kind of attributes that a person looks at when examining a package.

Ratio of open issues vs. total issues

The time it takes to close issues

Most recent commit

Commit frequency

Release frequency

                                <MaterialIcon id="star_half" />

Popularity

                                        Popularity attributes allows us to understand the package adoption and community size.

                                        These are the kind of attributes that a person looks at when they are undecided on the package choice.

Number of stars

Number of forks

Number of subscribers

Number of contributors

Number of dependents

Number of downloads

Downloads acceleration

                                <MaterialIcon id="record_voice_over" />

Personalities

                                        If two packages are similar, one tends to choose the one whose author is well known in the
                                        community.

                                        Relationships between people are also important. When a user follows another, there's a link
                                        between them. We can infer that people prefer packages from the users they follow.

                                        As of this writing the personalities attributes are not yet implemented.

If you want to know more, you may look at the architecture document.

                    { /* ------------- Get involved ------------- */ }

Get involved

                            npms is open-source and we still have some work to do.
                            Any contributions, ideas or bug reports are welcome. Visit our GitHub and help us!

                            Feel free to reach us directly via email or Twitter.

                    { /* ------------- Sponsors ------------- */ }

Sponsors

                                    Opbeat allows us to monitor our services performance, from backend to frontend.
                                    Additionally, Opbeat is supporting npms by generously paying for our hosting expenses.

                                    We use PM2 to deploy our services
                                    and Keymetrics provides an easy way to manage these deployments and to monitor the production machines.

                            We are using money from our own pockets to provide this service to you. Donations are welcome.
                            If you would like to sponsor this project, feel free to reach us.

                    { /* ------------- Authors ------------- */ }

Authors

                                    <Gravatar size={ 130 } email="andremiguelcruz@msn.com" className="avatar" https />

André Cruz

                                            <SvgIcon id={ SvgIcon.twitter } />

                                            <SvgIcon id={ SvgIcon.github } />

                                    <Gravatar size={ 130 } email="mail@andreduarte.net" className="avatar" https />

André Duarte

                                            <SvgIcon id={ SvgIcon.twitter } />

                                            <SvgIcon id={ SvgIcon.github } />

Special thanks

Cátia Santos for the website design

José Bateira for the initial effort put into this project

        );
    }
}

About.propTypes = {
    dispatch: PropTypes.func.isRequired,
};

export default connect()(About);
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

/**
 * @overview Initialization for the SAP UI Library
 *
 * This module creates the main SAP namespaces {@link sap} and automatically
 * registers it to the OpenAjax hub if that exists.
 *
 * This class provides method {@link #namespace} to register namespaces to the
 * SAP UI Library.
 *
 * @sample
 * Ensures a control can be used afterwards but does not load immediately
 * sap.ui.lazyRequire("sap.ui.core.Control");
 * sap.ui.lazyRequire("sap.ui.commons.Button");
 *
 * @version ${version}
 * @author  Martin Schaus, Daniel Brinkmann
 * @public
 */

/*global OpenAjax */// declare unusual global vars for JSLint/SAPUI5 validation

// Register to the OpenAjax Hub if it exists
sap.ui.define(['sap/ui/VersionInfo', 'jquery.sap.global', 'jquery.sap.dom'],
	function(VersionInfo, jQuery/* , jQuerySap */) {
	"use strict";

	if (window.OpenAjax && window.OpenAjax.hub) {
		OpenAjax.hub.registerLibrary("sap", "http://www.sap.com/", "0.1", {});
	}

	/**
	 * Root namespace for JavaScript functionality provided by SAP SE.
	 *
	 * The sap namespace is automatically registered with the
	 * OpenAjax hub if it exists.
	 *
	 * @version ${version}
	 * @namespace
	 * @public
	 * @name sap
	 */
	if ( typeof window.sap !== "object" && typeof window.sap !== "function"  ) {
	  window.sap = {};
	}

	/**
	 * The sap.ui namespace is the central OpenAjax compliant entry
	 * point for UI related JavaScript functionality provided by SAP.
	 *
	 * @version ${version}
	 * @namespace
	 * @name sap.ui
	 * @public
	 */
	if ( typeof window.sap.ui !== "object") {
		window.sap.ui = {};
	}

	sap.ui = jQuery.extend(sap.ui, {
		/**
		 * The version of the SAP UI Library
		 * @type string
		 */
		version: "${version}",
		buildinfo : { lastchange : "${lastchange}", buildtime : "${buildtime}" }
	});

	var oCfgData = window["sap-ui-config"] || {};

	var syncCallBehavior = 0; // ignore
	if ( oCfgData['xx-nosync'] === 'warn' || /(?:\?|&)sap-ui-xx-nosync=(?:warn)/.exec(window.location.search) ) {
		syncCallBehavior = 1;
	}
	if ( oCfgData['xx-nosync'] === true || oCfgData['xx-nosync'] === 'true' || /(?:\?|&)sap-ui-xx-nosync=(?:x|X|true)/.exec(window.location.search) ) {
		syncCallBehavior = 2;
	}

	/**
	 * Loads the version info file (resources/sap-ui-version.json) and returns
	 * it or if a library name is specified then the version info of the individual
	 * library will be returned.
	 *
	 * In case of the version info file is not available an error will occur when
	 * calling this function.
	 *
	 * @param {string|object} [mOptions] name of the library (e.g. "sap.ui.core") or an object map (see below)
	 * @param {boolean} [mOptions.library] name of the library (e.g. "sap.ui.core")
	 * @param {boolean} [mOptions.async=false] whether "sap-ui-version.json" should be loaded asynchronously
	 * @param {boolean} [mOptions.failOnError=true] whether to propagate load errors or not (not relevant for async loading)
	 * @return {object|undefined|Promise} the full version info, the library specific one,
	 *                                    undefined (if library is not listed or there was an error and "failOnError" is set to "false")
	 *                                    or a Promise which resolves with one of them
	 * @deprecated since 1.56: Use {@link sap.ui.VersionInfo.load} instead
	 * @public
	 * @static
	 */
	sap.ui.getVersionInfo = function(mOptions) {
		if (mOptions && mOptions.async) {
			jQuery.sap.log.info("Do not use deprecated function 'sap.ui.getVersionInfo'. Use 'sap.ui.VersionInfo.load' instead");
		} else {
			jQuery.sap.log.warning("Do not use deprecated function 'sap.ui.getVersionInfo' synchronously! Use asynchronous 'sap.ui.VersionInfo.load' instead");
		}

		return VersionInfo._load(mOptions); // .load() is async only!
	};

	/**
	 * Ensures that a given a namespace or hierarchy of nested namespaces exists in the
	 * current window.
	 *
	 * @param {string} sNamespace
	 * @return {object} the innermost namespace of the hierarchy
	 * @public
	 * @static
	 * @deprecated As of version 1.1, see {@link topic:c78c07c094e04ccfaab659378a1707c7 Creating Control and Class Modules}.
	 */
	sap.ui.namespace = function(sNamespace){

		jQuery.sap.assert(false, "sap.ui.namespace is long time deprecated and shouldn't be used");

		return jQuery.sap.getObject(sNamespace, 0);
	};

	/**
	 * Creates a lazy loading stub for a given class sClassName.
	 *
	 * If the class has been loaded already, nothing is done. Otherwise a stub object
	 * or constructor and - optionally - a set of stub methods are created.
	 * All created stubs will load the corresponding module on execution
	 * and then delegate to their counterpart in the loaded module.
	 *
	 * When no methods are given or when the list of methods contains the special name
	 * "new" (which is an operator can't be used as method name in JavaScript), then a
	 * stub constructor for class sClassName is created.
	 * Otherwise, a plain object is created.
	 *
	 * Note: Accessing any stub as a plain object without executing it (no matter
	 * whether it is a function or an object) won't load the module and therefore most like
	 * won't work as expected. This is a fundamental restriction of the lazy loader approach.
	 * It could only be fixed with JavaScript 1.5 features that are not available in all
	 * UI5 target browsers (e.g. not in IE8).
	 *
	 * Note: As a side effect of this method, the namespace containing the given
	 * class is created immediately.
	 *
	 * @param {string} sClassName Fully qualified name (dot notation) of the class that should be prepared
	 * @param {string} [sMethods='new'] space separated list of additional (static) methods that should be created as stubs
	 * @param {string} [sModuleName] name of the module to load, defaults to the class name
	 * @public
	 * @static
	 */
	sap.ui.lazyRequire = function(sClassName, sMethods, sModuleName) {

		jQuery.sap.assert(typeof sClassName === "string" && sClassName, "lazyRequire: sClassName must be a non-empty string");
		jQuery.sap.assert(!sMethods || typeof sMethods === "string", "lazyRequire: sMethods must be empty or a string");

		if ( syncCallBehavior === 2 ) {
			jQuery.sap.log.error("[nosync] lazy stub creation ignored for '" + sClassName + "'");
			return;
		}

		var sFullClass = sClassName.replace(/\//gi,"\."),
			iLastDotPos = sFullClass.lastIndexOf("."),
			sPackage = sFullClass.substr(0, iLastDotPos),
			sClass = sFullClass.substr(iLastDotPos + 1),
			oPackage = jQuery.sap.getObject(sPackage, 0),
			oClass = oPackage[sClass],
			aMethods = (sMethods || "new").split(" "),
			iConstructor = aMethods.indexOf("new");

		sModuleName = sModuleName || sFullClass;

		if (!oClass) {

			if ( iConstructor >= 0 ) {

				// Create dummy constructor which loads the class on demand
				oClass = function() {
					if ( syncCallBehavior ) {
						if ( syncCallBehavior === 1 ) {
							jQuery.sap.log.error("[nosync] lazy stub for constructor '" + sFullClass + "' called");
						}
					} else {
						jQuery.sap.log.debug("lazy stub for constructor '" + sFullClass + "' called.");
					}
					jQuery.sap.require(sModuleName);
					var oRealClass = oPackage[sClass];
					jQuery.sap.assert(typeof oRealClass === "function", "lazyRequire: oRealClass must be a function after loading");
					if ( oRealClass._sapUiLazyLoader ) {
						throw new Error("lazyRequire: stub '" + sFullClass + "'has not been replaced by module '" + sModuleName + "'");
					}

					// create a new instance and invoke the constructor
					var oInstance = Object.create(oRealClass.prototype);
					var oResult = oRealClass.apply(oInstance, arguments);
					if (oResult && (typeof oResult === "function" || typeof oResult === "object")) {
						oInstance = oResult;
					}
					return oInstance;
				};
				// mark the stub as lazy loader
				oClass._sapUiLazyLoader = true;

				aMethods.splice(iConstructor,1);

			} else {

				// Create dummy object
				oClass = {};

			}

			// remember the stub
			oPackage[sClass] = oClass;

		}

		// add stub methods to it
		aMethods.forEach( function(sMethod) {
			// check whether method is already available
			if (!oClass[sMethod]) {
				oClass[sMethod] = function() {
					if ( syncCallBehavior ) {
						if ( syncCallBehavior === 1 ) {
							jQuery.sap.log.error("[no-sync] lazy stub for method '" + sFullClass + "." + sMethod + "' called");
						}
					} else {
						jQuery.sap.log.debug("lazy stub for method '" + sFullClass + "." + sMethod + "' called.");
					}
					jQuery.sap.require(sModuleName);
					var oRealClass = oPackage[sClass];
					jQuery.sap.assert(typeof oRealClass === "function" || typeof oRealClass === "object", "lazyRequire: oRealClass must be a function or object after loading");
					jQuery.sap.assert(typeof oRealClass[sMethod] === "function", "lazyRequire: method must be a function");
					if (oRealClass[sMethod]._sapUiLazyLoader ) {
						throw new Error("lazyRequire: stub '" + sFullClass + "." + sMethod + "' has not been replaced by loaded module '" + sModuleName + "'");
					}
					return oRealClass[sMethod].apply(oRealClass, arguments);
				};
				oClass[sMethod]._sapUiLazyLoader = true;
			}
		});

	};

	/**
	 * Note: this method only works when sClassName has been stubbed itself, not when
	 *    it has been stubbed as a static utility class with individual stubs for its methods.
	 *    (e.g. might not work for 'sap.ui.core.BusyIndicator').
	 * Must not be used outside the core, e.g. not by controls, apps, tests etc.
	 * @private
	 */
	sap.ui.lazyRequire._isStub = function(sClassName) {
		jQuery.sap.assert(typeof sClassName === "string" && sClassName, "lazyRequire._isStub: sClassName must be a non-empty string");

		var iLastDotPos = sClassName.lastIndexOf("."),
			sContext = sClassName.slice(0, iLastDotPos),
			sProperty = sClassName.slice(iLastDotPos + 1),
			oContext = jQuery.sap.getObject(sContext);

		return !!(oContext && typeof oContext[sProperty] === "function" && oContext[sProperty]._sapUiLazyLoader);

	};

	/**
	 * Returns the URL of a resource that belongs to the given library and has the given relative location within the library.
	 * This is mainly meant for static resources like images that are inside the library.
	 * It is NOT meant for access to JavaScript modules or anything for which a different URL has been registered with jQuery.sap.registerModulePath(). For
	 * these cases use jQuery.sap.getModulePath().
	 * It DOES work, however, when the given sResourcePath starts with "themes/" (= when it is a theme-dependent resource). Even when for this theme a different
	 * location outside the normal library location is configured.
	 *
	 * @param {string} sLibraryName the name of a library, like "sap.ui.commons"
	 * @param {string} sResourcePath the relative path of a resource inside this library, like "img/mypic.png" or "themes/my_theme/img/mypic.png"
	 * @returns {string} the URL of the requested resource
	 *
	 * @static
	 * @public
	 * @deprecated since 1.56.0, use sap.ui.require.toUrl instead.
	 */
	sap.ui.resource = function(sLibraryName, sResourcePath) {
		jQuery.sap.assert(typeof sLibraryName === "string", "sLibraryName must be a string");
		jQuery.sap.assert(typeof sResourcePath === "string", "sResourcePath must be a string");

		// special handling for theme-dependent resources: move theme folder into module name
		var match = sResourcePath.match(/^themes\/([^\/]+)\//);
		if (match) {
			sLibraryName += ".themes." + match[1];
			sResourcePath = sResourcePath.substr(match[0].length);
		}

		return jQuery.sap.getModulePath(sLibraryName, '/') + sResourcePath;
	};

	/**
	 * Redirects access to resources that are part of the given namespace to a location
	 * relative to the assumed application root folder.
	 *
	 * Any UI5 managed resource (view, controller, control, JavaScript module, CSS file, etc.)
	 * whose resource name starts with sNamespace, will be loaded from an
	 * equally named subfolder of the application root folder.
	 * If the resource name consists of multiple segments (separated by a dot), each segment
	 * is assumed to represent an individual folder. In other words: when a resource name is
	 * converted to a URL, any dots ('.') are converted to slashes ('/').
	 *
	 * Limitation: For the time being, the application root folder is assumed to be
	 * the same as the folder where the current page resides in.
	 *
	 * Usage sample:
	 *

	 *   // Let UI5 know that resources, whose name starts with "com.mycompany.myapp"
	 *   // should be loaded from the URL location "./com/mycompany/myapp"
	 *   sap.ui.localResources("com.mycompany.myapp");
	 *
	 *   // The following call implicitly will use the mapping done by the previous line
	 *   // It will load a view from ./com/mycompany/myapp/views/Main.view.xml
	 *   sap.ui.view({ view : "com.mycompany.myapp.views.Main", type : sap.ui.core.mvc.ViewType.XML});
	 *

	 *
	 * When applications need a more flexible mapping between resource names and their location,
	 * they can use {@link jQuery.sap.registerModulePath}.
	 *
	 * It is intended to make this configuration obsolete in future releases, but for the time
	 * being, applications must call this method when they want to store resources relative to
	 * the assumed application root folder.
	 *
	 * @param {string} sNamespace Namespace prefix for which to load resources relative to the application root folder
	 * @public
	 * @static
	 * @see jQuery.sap.registerModulePath
	 * @deprecated since 1.56, use sap.ui.loader.config instead.
	 */
	sap.ui.localResources = function(sNamespace) {
		jQuery.sap.assert(sNamespace, "sNamespace must not be empty");
		jQuery.sap.registerModulePath(sNamespace, "./" + sNamespace.replace(/\./g, "/"));
	};

	return sap.ui;

});
<commit_msg>[INTERNAL] sap.ui.lazyRequire: Deprecate API<commit_after>/*!
 * ${copyright}
 */

/**
 * @overview Initialization for the SAP UI Library
 *
 * This module creates the main SAP namespaces {@link sap} and automatically
 * registers it to the OpenAjax hub if that exists.
 *
 * This class provides method {@link #namespace} to register namespaces to the
 * SAP UI Library.
 *
 * @sample
 * Ensures a control can be used afterwards but does not load immediately
 * sap.ui.lazyRequire("sap.ui.core.Control");
 * sap.ui.lazyRequire("sap.ui.commons.Button");
 *
 * @version ${version}
 * @author  Martin Schaus, Daniel Brinkmann
 * @public
 */

/*global OpenAjax */// declare unusual global vars for JSLint/SAPUI5 validation

// Register to the OpenAjax Hub if it exists
sap.ui.define(['sap/ui/VersionInfo', 'jquery.sap.global', 'jquery.sap.dom'],
	function(VersionInfo, jQuery/* , jQuerySap */) {
	"use strict";

	if (window.OpenAjax && window.OpenAjax.hub) {
		OpenAjax.hub.registerLibrary("sap", "http://www.sap.com/", "0.1", {});
	}

	/**
	 * Root namespace for JavaScript functionality provided by SAP SE.
	 *
	 * The sap namespace is automatically registered with the
	 * OpenAjax hub if it exists.
	 *
	 * @version ${version}
	 * @namespace
	 * @public
	 * @name sap
	 */
	if ( typeof window.sap !== "object" && typeof window.sap !== "function"  ) {
	  window.sap = {};
	}

	/**
	 * The sap.ui namespace is the central OpenAjax compliant entry
	 * point for UI related JavaScript functionality provided by SAP.
	 *
	 * @version ${version}
	 * @namespace
	 * @name sap.ui
	 * @public
	 */
	if ( typeof window.sap.ui !== "object") {
		window.sap.ui = {};
	}

	sap.ui = jQuery.extend(sap.ui, {
		/**
		 * The version of the SAP UI Library
		 * @type string
		 */
		version: "${version}",
		buildinfo : { lastchange : "${lastchange}", buildtime : "${buildtime}" }
	});

	var oCfgData = window["sap-ui-config"] || {};

	var syncCallBehavior = 0; // ignore
	if ( oCfgData['xx-nosync'] === 'warn' || /(?:\?|&)sap-ui-xx-nosync=(?:warn)/.exec(window.location.search) ) {
		syncCallBehavior = 1;
	}
	if ( oCfgData['xx-nosync'] === true || oCfgData['xx-nosync'] === 'true' || /(?:\?|&)sap-ui-xx-nosync=(?:x|X|true)/.exec(window.location.search) ) {
		syncCallBehavior = 2;
	}

	/**
	 * Loads the version info file (resources/sap-ui-version.json) and returns
	 * it or if a library name is specified then the version info of the individual
	 * library will be returned.
	 *
	 * In case of the version info file is not available an error will occur when
	 * calling this function.
	 *
	 * @param {string|object} [mOptions] name of the library (e.g. "sap.ui.core") or an object map (see below)
	 * @param {boolean} [mOptions.library] name of the library (e.g. "sap.ui.core")
	 * @param {boolean} [mOptions.async=false] whether "sap-ui-version.json" should be loaded asynchronously
	 * @param {boolean} [mOptions.failOnError=true] whether to propagate load errors or not (not relevant for async loading)
	 * @return {object|undefined|Promise} the full version info, the library specific one,
	 *                                    undefined (if library is not listed or there was an error and "failOnError" is set to "false")
	 *                                    or a Promise which resolves with one of them
	 * @deprecated since 1.56: Use {@link sap.ui.VersionInfo.load} instead
	 * @public
	 * @static
	 */
	sap.ui.getVersionInfo = function(mOptions) {
		if (mOptions && mOptions.async) {
			jQuery.sap.log.info("Do not use deprecated function 'sap.ui.getVersionInfo'. Use 'sap.ui.VersionInfo.load' instead");
		} else {
			jQuery.sap.log.warning("Do not use deprecated function 'sap.ui.getVersionInfo' synchronously! Use asynchronous 'sap.ui.VersionInfo.load' instead");
		}

		return VersionInfo._load(mOptions); // .load() is async only!
	};

	/**
	 * Ensures that a given a namespace or hierarchy of nested namespaces exists in the
	 * current window.
	 *
	 * @param {string} sNamespace
	 * @return {object} the innermost namespace of the hierarchy
	 * @public
	 * @static
	 * @deprecated As of version 1.1, see {@link topic:c78c07c094e04ccfaab659378a1707c7 Creating Control and Class Modules}.
	 */
	sap.ui.namespace = function(sNamespace){

		jQuery.sap.assert(false, "sap.ui.namespace is long time deprecated and shouldn't be used");

		return jQuery.sap.getObject(sNamespace, 0);
	};

	/**
	 * Creates a lazy loading stub for a given class sClassName.
	 *
	 * If the class has been loaded already, nothing is done. Otherwise a stub object
	 * or constructor and - optionally - a set of stub methods are created.
	 * All created stubs will load the corresponding module on execution
	 * and then delegate to their counterpart in the loaded module.
	 *
	 * When no methods are given or when the list of methods contains the special name
	 * "new" (which is an operator can't be used as method name in JavaScript), then a
	 * stub constructor for class sClassName is created.
	 * Otherwise, a plain object is created.
	 *
	 * Note: Accessing any stub as a plain object without executing it (no matter
	 * whether it is a function or an object) won't load the module and therefore most like
	 * won't work as expected. This is a fundamental restriction of the lazy loader approach.
	 * It could only be fixed with JavaScript 1.5 features that are not available in all
	 * UI5 target browsers (e.g. not in IE8).
	 *
	 * Note: As a side effect of this method, the namespace containing the given
	 * class is created immediately.
	 *
	 * @param {string} sClassName Fully qualified name (dot notation) of the class that should be prepared
	 * @param {string} [sMethods='new'] space separated list of additional (static) methods that should be created as stubs
	 * @param {string} [sModuleName] name of the module to load, defaults to the class name
	 * @public
	 * @static
	 * @deprecated since 1.56
	 */
	sap.ui.lazyRequire = function(sClassName, sMethods, sModuleName) {

		jQuery.sap.assert(typeof sClassName === "string" && sClassName, "lazyRequire: sClassName must be a non-empty string");
		jQuery.sap.assert(!sMethods || typeof sMethods === "string", "lazyRequire: sMethods must be empty or a string");

		if ( syncCallBehavior === 2 ) {
			jQuery.sap.log.error("[nosync] lazy stub creation ignored for '" + sClassName + "'");
			return;
		}

		var sFullClass = sClassName.replace(/\//gi,"\."),
			iLastDotPos = sFullClass.lastIndexOf("."),
			sPackage = sFullClass.substr(0, iLastDotPos),
			sClass = sFullClass.substr(iLastDotPos + 1),
			oPackage = jQuery.sap.getObject(sPackage, 0),
			oClass = oPackage[sClass],
			aMethods = (sMethods || "new").split(" "),
			iConstructor = aMethods.indexOf("new");

		sModuleName = sModuleName || sFullClass;

		if (!oClass) {

			if ( iConstructor >= 0 ) {

				// Create dummy constructor which loads the class on demand
				oClass = function() {
					if ( syncCallBehavior ) {
						if ( syncCallBehavior === 1 ) {
							jQuery.sap.log.error("[nosync] lazy stub for constructor '" + sFullClass + "' called");
						}
					} else {
						jQuery.sap.log.debug("lazy stub for constructor '" + sFullClass + "' called.");
					}
					jQuery.sap.require(sModuleName);
					var oRealClass = oPackage[sClass];
					jQuery.sap.assert(typeof oRealClass === "function", "lazyRequire: oRealClass must be a function after loading");
					if ( oRealClass._sapUiLazyLoader ) {
						throw new Error("lazyRequire: stub '" + sFullClass + "'has not been replaced by module '" + sModuleName + "'");
					}

					// create a new instance and invoke the constructor
					var oInstance = Object.create(oRealClass.prototype);
					var oResult = oRealClass.apply(oInstance, arguments);
					if (oResult && (typeof oResult === "function" || typeof oResult === "object")) {
						oInstance = oResult;
					}
					return oInstance;
				};
				// mark the stub as lazy loader
				oClass._sapUiLazyLoader = true;

				aMethods.splice(iConstructor,1);

			} else {

				// Create dummy object
				oClass = {};

			}

			// remember the stub
			oPackage[sClass] = oClass;

		}

		// add stub methods to it
		aMethods.forEach( function(sMethod) {
			// check whether method is already available
			if (!oClass[sMethod]) {
				oClass[sMethod] = function() {
					if ( syncCallBehavior ) {
						if ( syncCallBehavior === 1 ) {
							jQuery.sap.log.error("[no-sync] lazy stub for method '" + sFullClass + "." + sMethod + "' called");
						}
					} else {
						jQuery.sap.log.debug("lazy stub for method '" + sFullClass + "." + sMethod + "' called.");
					}
					jQuery.sap.require(sModuleName);
					var oRealClass = oPackage[sClass];
					jQuery.sap.assert(typeof oRealClass === "function" || typeof oRealClass === "object", "lazyRequire: oRealClass must be a function or object after loading");
					jQuery.sap.assert(typeof oRealClass[sMethod] === "function", "lazyRequire: method must be a function");
					if (oRealClass[sMethod]._sapUiLazyLoader ) {
						throw new Error("lazyRequire: stub '" + sFullClass + "." + sMethod + "' has not been replaced by loaded module '" + sModuleName + "'");
					}
					return oRealClass[sMethod].apply(oRealClass, arguments);
				};
				oClass[sMethod]._sapUiLazyLoader = true;
			}
		});

	};

	/**
	 * Note: this method only works when sClassName has been stubbed itself, not when
	 *    it has been stubbed as a static utility class with individual stubs for its methods.
	 *    (e.g. might not work for 'sap.ui.core.BusyIndicator').
	 * Must not be used outside the core, e.g. not by controls, apps, tests etc.
	 * @private
	 * @deprecated since 1.56
	 */
	sap.ui.lazyRequire._isStub = function(sClassName) {
		jQuery.sap.assert(typeof sClassName === "string" && sClassName, "lazyRequire._isStub: sClassName must be a non-empty string");

		var iLastDotPos = sClassName.lastIndexOf("."),
			sContext = sClassName.slice(0, iLastDotPos),
			sProperty = sClassName.slice(iLastDotPos + 1),
			oContext = jQuery.sap.getObject(sContext);

		return !!(oContext && typeof oContext[sProperty] === "function" && oContext[sProperty]._sapUiLazyLoader);

	};

	/**
	 * Returns the URL of a resource that belongs to the given library and has the given relative location within the library.
	 * This is mainly meant for static resources like images that are inside the library.
	 * It is NOT meant for access to JavaScript modules or anything for which a different URL has been registered with jQuery.sap.registerModulePath(). For
	 * these cases use jQuery.sap.getModulePath().
	 * It DOES work, however, when the given sResourcePath starts with "themes/" (= when it is a theme-dependent resource). Even when for this theme a different
	 * location outside the normal library location is configured.
	 *
	 * @param {string} sLibraryName the name of a library, like "sap.ui.commons"
	 * @param {string} sResourcePath the relative path of a resource inside this library, like "img/mypic.png" or "themes/my_theme/img/mypic.png"
	 * @returns {string} the URL of the requested resource
	 *
	 * @static
	 * @public
	 * @deprecated since 1.56.0, use sap.ui.require.toUrl instead.
	 */
	sap.ui.resource = function(sLibraryName, sResourcePath) {
		jQuery.sap.assert(typeof sLibraryName === "string", "sLibraryName must be a string");
		jQuery.sap.assert(typeof sResourcePath === "string", "sResourcePath must be a string");

		// special handling for theme-dependent resources: move theme folder into module name
		var match = sResourcePath.match(/^themes\/([^\/]+)\//);
		if (match) {
			sLibraryName += ".themes." + match[1];
			sResourcePath = sResourcePath.substr(match[0].length);
		}

		return jQuery.sap.getModulePath(sLibraryName, '/') + sResourcePath;
	};

	/**
	 * Redirects access to resources that are part of the given namespace to a location
	 * relative to the assumed application root folder.
	 *
	 * Any UI5 managed resource (view, controller, control, JavaScript module, CSS file, etc.)
	 * whose resource name starts with sNamespace, will be loaded from an
	 * equally named subfolder of the application root folder.
	 * If the resource name consists of multiple segments (separated by a dot), each segment
	 * is assumed to represent an individual folder. In other words: when a resource name is
	 * converted to a URL, any dots ('.') are converted to slashes ('/').
	 *
	 * Limitation: For the time being, the application root folder is assumed to be
	 * the same as the folder where the current page resides in.
	 *
	 * Usage sample:
	 *

	 *   // Let UI5 know that resources, whose name starts with "com.mycompany.myapp"
	 *   // should be loaded from the URL location "./com/mycompany/myapp"
	 *   sap.ui.localResources("com.mycompany.myapp");
	 *
	 *   // The following call implicitly will use the mapping done by the previous line
	 *   // It will load a view from ./com/mycompany/myapp/views/Main.view.xml
	 *   sap.ui.view({ view : "com.mycompany.myapp.views.Main", type : sap.ui.core.mvc.ViewType.XML});
	 *

	 *
	 * When applications need a more flexible mapping between resource names and their location,
	 * they can use {@link jQuery.sap.registerModulePath}.
	 *
	 * It is intended to make this configuration obsolete in future releases, but for the time
	 * being, applications must call this method when they want to store resources relative to
	 * the assumed application root folder.
	 *
	 * @param {string} sNamespace Namespace prefix for which to load resources relative to the application root folder
	 * @public
	 * @static
	 * @see jQuery.sap.registerModulePath
	 * @deprecated since 1.56, use sap.ui.loader.config instead.
	 */
	sap.ui.localResources = function(sNamespace) {
		jQuery.sap.assert(sNamespace, "sNamespace must not be empty");
		jQuery.sap.registerModulePath(sNamespace, "./" + sNamespace.replace(/\./g, "/"));
	};

	return sap.ui;

});
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////
// A sensor that sets a variable to 1 on contact and 0 otherwise
////////////////////////////////////////////////////////////////

var Box2D = require('box2dweb-commonjs').Box2D;
var constants = require('./../../../base/constants');

// Aliases
var b2Vec2 = Box2D.Common.Math.b2Vec2;
var b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
var b2FixtureDef = Box2D.Dynamics.b2FixtureDef;

/**
 * Provides a whisker sensor that returns a high (1) value
 * on contact and low (0) otherwise
 * @class Whisker
 * @namespace Sensors.Base.Pressure
 * @constructor
 * @param {Object} agentObject The Agent object the sensor will
 * be attached to
 * @param {Object} specs Contains the specifications of the
 * sensor. The mandatory fields are:
 *
 *   - id: Identifier to store the sensor value
 *   - pos_x: x offset from the main body center
 *   - pos_y: y offset from the main body center
 *   - angle: angle with the main body
 *   - width: width of the sensor
 *   - height: height of the sensor
 */
function Whisker(agentObject, specs) {
  var sensorId, posX, posY, angle, width, height, whiskerShape;

  // Sensor specs
  sensorId = specs.id;
  posX     = specs.pos_x;
  posY     = specs.pos_y;
  angle    = specs.angle;
  width    = specs.width;
  height   = specs.height;

  whiskerShape = new b2PolygonShape();
  whiskerShape.SetAsOrientedBox(height, width, new b2Vec2(posX, posY), angle);
  whisker = new b2FixtureDef();

  whisker.shape = whiskerShape;
  whisker.isSensor = true;
  whisker.userData = {
    onBeginContact: function() {
      agentObject.setSensor(sensorId, 1);
    },
    onEndContact: function() {
      agentObject.setSensor(sensorId, 0);
    }
  };

  // Static objects only
  whisker.filter.maskBits = constants.MAP_OBJECT;

  agentObject.body.CreateFixture(whisker);
  return whisker;
}

exports.Whisker = Whisker;

<commit_msg>Initialize whisker value<commit_after>////////////////////////////////////////////////////////////////
// A sensor that sets a variable to 1 on contact and 0 otherwise
////////////////////////////////////////////////////////////////

var Box2D = require('box2dweb-commonjs').Box2D;
var constants = require('./../../../base/constants');

// Aliases
var b2Vec2 = Box2D.Common.Math.b2Vec2;
var b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
var b2FixtureDef = Box2D.Dynamics.b2FixtureDef;

/**
 * Provides a whisker sensor that returns a high (1) value
 * on contact and low (0) otherwise
 * @class Whisker
 * @namespace Sensors.Base.Pressure
 * @constructor
 * @param {Object} agentObject The Agent object the sensor will
 * be attached to
 * @param {Object} specs Contains the specifications of the
 * sensor. The mandatory fields are:
 *
 *   - id: Identifier to store the sensor value
 *   - pos_x: x offset from the main body center
 *   - pos_y: y offset from the main body center
 *   - angle: angle with the main body
 *   - width: width of the sensor
 *   - height: height of the sensor
 */
function Whisker(agentObject, specs) {
  var sensorId, posX, posY, angle, width, height, whiskerShape;

  // Sensor specs
  sensorId = specs.id;
  posX     = specs.pos_x;
  posY     = specs.pos_y;
  angle    = specs.angle;
  width    = specs.width;
  height   = specs.height;

  whiskerShape = new b2PolygonShape();
  whiskerShape.SetAsOrientedBox(height, width, new b2Vec2(posX, posY), angle);
  whisker = new b2FixtureDef();

  whisker.shape = whiskerShape;
  whisker.isSensor = true;
  whisker.userData = {
    onBeginContact: function() {
      agentObject.setSensor(sensorId, 1);
    },
    onEndContact: function() {
      agentObject.setSensor(sensorId, 0);
    }
  };

  // Initial value
  agentObject.setSensor(sensorId, 0);

  // Static objects only
  whisker.filter.maskBits = constants.MAP_OBJECT;

  agentObject.body.CreateFixture(whisker);
  return whisker;
}

exports.Whisker = Whisker;

<|endoftext|>


<commit_before>import titleGenerator from './generators/titleGenerator'
import attrsGenerator from './generators/attrsGenerator'
import tagGenerator from './generators/tagGenerator'

export default function _generateServerInjector (options = {}) {
  /**
   * Converts a meta info property to one that can be stringified on the server
   *
   * @param  {String} type - the type of data to convert
   * @param  {(String|Object|Array<Object>)} data - the data value
   * @return {Object} - the new injector
   */
  return function generateServerInjector (type, data) {
    switch (type) {
      case 'title':
        return titleGenerator(options)(type, data)
      case 'htmlAttrs':
      case 'bodyAttrs':
        return attrsGenerator(options)(type, data)
      default:
        return tagGenerator(options)(type, data)
    }
  }
}
<commit_msg>added headAttrs to generators<commit_after>import titleGenerator from './generators/titleGenerator'
import attrsGenerator from './generators/attrsGenerator'
import tagGenerator from './generators/tagGenerator'

export default function _generateServerInjector (options = {}) {
  /**
   * Converts a meta info property to one that can be stringified on the server
   *
   * @param  {String} type - the type of data to convert
   * @param  {(String|Object|Array<Object>)} data - the data value
   * @return {Object} - the new injector
   */
  return function generateServerInjector (type, data) {
    switch (type) {
      case 'title':
        return titleGenerator(options)(type, data)
      case 'htmlAttrs':
      case 'bodyAttrs':
      case 'headAttrs':
        return attrsGenerator(options)(type, data)
      default:
        return tagGenerator(options)(type, data)
    }
  }
}
<|endoftext|>


<commit_before><commit_msg>First steps towards being able to sort the player rows<commit_after><|endoftext|>