text: var travelMode, unitSystem;
  
  GMaps.prototype.getRoutes = function (options) {
      switch (options.travelMode) {
          case 'bicycling':
              travelMode = google.maps.TravelMode.BICYCLING;
              break;
          case 'transit':
              travelMode = google.maps.TravelMode.TRANSIT;
              break;
          case 'driving':
              travelMode = google.maps.TravelMode.DRIVING;
              break;
          default:
              travelMode = google.maps.TravelMode.WALKING;
              break;
      }
  
      if (options.unitSystem === 'imperial') {
          unitSystem = google.maps.UnitSystem.IMPERIAL;
      }
      else {
          unitSystem = google.maps.UnitSystem.METRIC;
      }
  
      var base_options = {
              avoidHighways: false,
              avoidTolls: false,
              optimizeWaypoints: false,
              waypoints: []
          },
          request_options = extend_object(base_options, options);
  
      request_options.origin = /string/.test(typeof options.origin) ? options.origin : new google.maps.LatLng(options.origin[0], options.origin[1]);
      request_options.destination = /string/.test(typeof options.destination) ? options.destination : new google.maps.LatLng(options.destination[0], options.destination[1]);
      request_options.travelMode = travelMode;
      request_options.unitSystem = unitSystem;
  
      delete request_options.callback;
      delete request_options.error;
  
      var self = this,
          service = new google.maps.DirectionsService();
  
      service.route(request_options, function (result, status) {
          if (status === google.maps.DirectionsStatus.OK) {
              for (var r in result.routes) {
                  if (result.routes.hasOwnProperty(r)) {
                      self.routes.push(result.routes[r]);
                  }
              }
  
              if (options.callback) {
                  options.callback(self.routes);
              }
          }
          else {
              if (options.error) {
                  options.error(result, status);
              }
          }
      });
  };
  
  GMaps.prototype.removeRoutes = function () {
      this.routes = [];
  };
  
  GMaps.prototype.getElevations = function (options) {
      options = extend_object({
          locations: [],
          path: false,
          samples: 256
      }, options);
  
      if (options.locations.length > 0) {
          if (options.locations[0].length > 0) {
              options.locations = array_flat(array_map([options.locations], arrayToLatLng, false));
          }
      }
  
      var callback = options.callback;
      delete options.callback;
  
      var service = new google.maps.ElevationService();
  
      //location request
      if (!options.path) {
          delete options.path;
          delete options.samples;
  
          service.getElevationForLocations(options, function (result, status) {
              if (callback && typeof(callback) === "function") {
                  callback(result, status);
              }
          });
          //path request
      } else {
          var pathRequest = {
              path: options.locations,
              samples: options.samples
          };
  
          service.getElevationAlongPath(pathRequest, function (result, status) {
              if (callback && typeof(callback) === "function") {
                  callback(result, status);
              }
          });
      }
  };
  
  GMaps.prototype.cleanRoute = GMaps.prototype.removePolylines;
  
  GMaps.prototype.drawRoute = function (options) {
      var self = this;
  
      this.getRoutes({
          origin: options.origin,
          destination: options.destination,
          travelMode: options.travelMode,
          waypoints: options.waypoints,
          unitSystem: options.unitSystem,
          error: options.error,
          callback: function (e) {
              if (e.length > 0) {
                  self.drawPolyline({
                      path: e[e.length - 1].overview_path,
                      strokeColor: options.strokeColor,
                      strokeOpacity: options.strokeOpacity,
                      strokeWeight: options.strokeWeight
                  });
  
                  if (options.callback) {
                      options.callback(e[e.length - 1]);
                  }
              }
          }
      });
  };
  
  GMaps.prototype.travelRoute = function (options) {
      if (options.origin && options.destination) {
          this.getRoutes({
              origin: options.origin,
              destination: options.destination,
              travelMode: options.travelMode,
              waypoints: options.waypoints,
              error: options.error,
              callback: function (e) {
                  //start callback
                  if (e.length > 0 && options.start) {
                      options.start(e[e.length - 1]);
                  }
  
                  //step callback
                  if (e.length > 0 && options.step) {
                      var route = e[e.length - 1];
                      if (route.legs.length > 0) {
                          var steps = route.legs[0].steps;
                          for (var i = 0, step; step = steps[i]; i++) {
                              step.step_number = i;
                              options.step(step, (route.legs[0].steps.length - 1));
                          }
                      }
                  }
  
                  //end callback
                  if (e.length > 0 && options.end) {
                      options.end(e[e.length - 1]);
                  }
              }
          });
      }
      else if (options.route) {
          if (options.route.legs.length > 0) {
              var steps = options.route.legs[0].steps;
              for (var i = 0, step; step = steps[i]; i++) {
                  step.step_number = i;
                  options.step(step);
              }
          }
      }
  };
  
  GMaps.prototype.drawSteppedRoute = function (options) {
      var self = this;
  
      if (options.origin && options.destination) {
          this.getRoutes({
              origin: options.origin,
              destination: options.destination,
              travelMode: options.travelMode,
              waypoints: options.waypoints,
              error: options.error,
              callback: function (e) {
                  //start callback
                  if (e.length > 0 && options.start) {
                      options.start(e[e.length - 1]);
                  }
  
                  //step callback
                  if (e.length > 0 && options.step) {
                      var route = e[e.length - 1];
                      if (route.legs.length > 0) {
                          var steps = route.legs[0].steps;
                          for (var i = 0, step; step = steps[i]; i++) {
                              step.step_number = i;
                              self.drawPolyline({
                                  path: step.path,
                                  strokeColor: options.strokeColor,
                                  strokeOpacity: options.strokeOpacity,
                                  strokeWeight: options.strokeWeight
                              });
                              options.step(step, (route.legs[0].steps.length - 1));
                          }
                      }
                  }
  
                  //end callback
                  if (e.length > 0 && options.end) {
                      options.end(e[e.length - 1]);
                  }
              }
          });
      }
      else if (options.route) {
          if (options.route.legs.length > 0) {
              var steps = options.route.legs[0].steps;
              for (var i = 0, step; step = steps[i]; i++) {
                  step.step_number = i;
                  self.drawPolyline({
                      path: step.path,
                      strokeColor: options.strokeColor,
                      strokeOpacity: options.strokeOpacity,
                      strokeWeight: options.strokeWeight
                  });
                  options.step(step);
              }
          }
      }
  };
  
  GMaps.Route = function (options) {
      this.origin = options.origin;
      this.destination = options.destination;
      this.waypoints = options.waypoints;
  
      this.map = options.map;
      this.route = options.route;
      this.step_count = 0;
      this.steps = this.route.legs[0].steps;
      this.steps_length = this.steps.length;
  
      this.polyline = this.map.drawPolyline({
          path: new google.maps.MVCArray(),
          strokeColor: options.strokeColor,
          strokeOpacity: options.strokeOpacity,
          strokeWeight: options.strokeWeight
      }).getPath();
  };
  
  GMaps.Route.prototype.getRoute = function (options) {
      var self = this;
  
      this.map.getRoutes({
          origin: this.origin,
          destination: this.destination,
          travelMode: options.travelMode,
          waypoints: this.waypoints || [],
          error: options.error,
          callback: function () {
              self.route = e[0];
  
              if (options.callback) {
                  options.callback.call(self);
              }
          }
      });
  };
  
  GMaps.Route.prototype.back = function () {
      if (this.step_count > 0) {
          this.step_count--;
          var path = this.route.legs[0].steps[this.step_count].path;
  
          for (var p in path) {
              if (path.hasOwnProperty(p)) {
                  this.polyline.pop();
              }
          }
      }
  };
  
  GMaps.Route.prototype.forward = function () {
      if (this.step_count < this.steps_length) {
          var path = this.route.legs[0].steps[this.step_count].path;
  
          for (var p in path) {
              if (path.hasOwnProperty(p)) {
                  this.polyline.push(path[p]);
              }
          }
          this.step_count++;
      }
  };
  