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) {
          var polyline_options = {
            path: e[e.length - 1].overview_path,
            strokeColor: options.strokeColor,
            strokeOpacity: options.strokeOpacity,
            strokeWeight: options.strokeWeight
          };
  
          if (options.hasOwnProperty("icons")) {
            polyline_options.icons = options.icons;
          }
  
          self.drawPolyline(polyline_options);
          
          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,
        unitSystem: options.unitSystem,
        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;
                var polyline_options = {
                  path: step.path,
                  strokeColor: options.strokeColor,
                  strokeOpacity: options.strokeOpacity,
                  strokeWeight: options.strokeWeight
                };
  
                if (options.hasOwnProperty("icons")) {
                  polyline_options.icons = options.icons;
                }
  
                self.drawPolyline(polyline_options);
                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;
          var polyline_options = {
            path: step.path,
            strokeColor: options.strokeColor,
            strokeOpacity: options.strokeOpacity,
            strokeWeight: options.strokeWeight
          };
  
          if (options.hasOwnProperty("icons")) {
            polyline_options.icons = options.icons;
          }
  
          self.drawPolyline(polyline_options);
          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;
  
    var polyline_options = {
      path: new google.maps.MVCArray(),
      strokeColor: options.strokeColor,
      strokeOpacity: options.strokeOpacity,
      strokeWeight: options.strokeWeight
    };
  
    if (options.hasOwnProperty("icons")) {
      polyline_options.icons = options.icons;
    }
  
    this.polyline = this.map.drawPolyline(polyline_options).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++;
    }
  };
  