text: d3.scale.linear = function() {
    var domain = [0, 1],
        range = [0, 1],
        interpolate = d3.interpolate,
        clamp = false,
        output,
        input;
  
    function rescale() {
      var linear = domain.length == 2 ? d3_scale_bilinear : d3_scale_polylinear,
          uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
      output = linear(domain, range, uninterpolate, interpolate);
      input = linear(range, domain, uninterpolate, d3.interpolate);
      return scale;
    }
  
    function scale(x) {
      return output(x);
    }
  
    // Note: requires range is coercible to number!
    scale.invert = function(y) {
      return input(y);
    };
  
    scale.domain = function(x) {
      if (!arguments.length) return domain;
      domain = x.map(Number);
      return rescale();
    };
  
    scale.range = function(x) {
      if (!arguments.length) return range;
      range = x;
      return rescale();
    };
  
    scale.rangeRound = function(x) {
      return scale.range(x).interpolate(d3.interpolateRound);
    };
  
    scale.clamp = function(x) {
      if (!arguments.length) return clamp;
      clamp = x;
      return rescale();
    };
  
    scale.interpolate = function(x) {
      if (!arguments.length) return interpolate;
      interpolate = x;
      return rescale();
    };
  
    scale.ticks = function(m) {
      return d3_scale_linearTicks(domain, m);
    };
  
    scale.tickFormat = function(m) {
      return d3_scale_linearTickFormat(domain, m);
    };
  
    scale.nice = function() {
      d3_scale_nice(domain, d3_scale_linearNice);
      return rescale();
    };
  
    return rescale();
  };
  
  function d3_scale_linearRebind(scale, linear) {
    scale.range = d3.rebind(scale, linear.range);
    scale.rangeRound = d3.rebind(scale, linear.rangeRound);
    scale.interpolate = d3.rebind(scale, linear.interpolate);
    scale.clamp = d3.rebind(scale, linear.clamp);
    return scale;
  };
  
  function d3_scale_linearNice(dx) {
    dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
    return {
      floor: function(x) { return Math.floor(x / dx) * dx; },
      ceil: function(x) { return Math.ceil(x / dx) * dx; }
    };
  }
  
  // TODO Dates? Ugh.
  function d3_scale_linearTickRange(domain, m) {
    var extent = d3_scaleExtent(domain),
        span = extent[1] - extent[0],
        step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)),
        err = m / span * step;
  
    // Filter ticks to get closer to the desired count.
    if (err <= .15) step *= 10;
    else if (err <= .35) step *= 5;
    else if (err <= .75) step *= 2;
  
    // Round start and stop values to step interval.
    extent[0] = Math.ceil(extent[0] / step) * step;
    extent[1] = Math.floor(extent[1] / step) * step + step * .5; // inclusive
    extent[2] = step;
    return extent;
  }
  
  function d3_scale_linearTicks(domain, m) {
    return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
  }
  
  function d3_scale_linearTickFormat(domain, m) {
    return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
  }
  