anchor.diff:    }
   
     if (params.containsKey("x") && params.containsKey("y") && params.containsKey("r")) {
  -   return new Camera(new Complex(params["x"], params["y"]), params["r"]);
  +    return new Camera(new Complex(params["x"], params["y"]), params["r"]);
     } else {
       return Camera.start;
     }
   }
   
  -saveCamera(Camera next) {
  -  var state = "#x=${next.center.real}&y=${next.center.imag}&r=${next.radius}";
  -  window.location.hash = state;
  +Camera lastSaved;
  +
  +updateCamera(Camera next) {
  +  var newHash = "#x=${next.center.real}&y=${next.center.imag}&r=${next.radius}";
  +  var url = window.location.href;
  +  if (url.contains("#")) {
  +    url = url.substring(0, url.indexOf("#"));
  +  }
  +  url += newHash;
  +  if (lastSaved != null && lastSaved.radius == next.radius) {
  +    window.history.replaceState(null,  "", url);
  +  } else {
  +    window.history.pushState(null,  "", url);
  +  }
  +  lastSaved = next;
   }
   
   render() {
     var camera = loadCamera();
     getRoot("#container")
  -    .mount(new MandelbrotApp(startCamera: camera, save: saveCamera));
  +    .mount(new MandelbrotApp(startCamera: camera, onCameraChange: updateCamera));
   }
   
   main() {
     render();
     window.onHashChange.listen((_) {
  +    lastSaved = null;
       render();
     });
   }
  
positive.code: // Views
  //
  
  typedef SaveCameraHandler(Camera next);
  
  class MandelbrotApp extends AnimatedTag {
    final Camera startCamera;
    final SaveCameraHandler save;
  
    const MandelbrotApp({this.startCamera: Camera.start, this.save});
  
    @override
    Place start() => new Place(startCamera);
  
    @override
    bool shouldRestart(Place p, AnimatedTag prev) {
      if (prev is MandelbrotApp) {
        return prev.startCamera != startCamera;
      } else {
        return true;
      }
    }
  
    @override
    Tag renderAt(Place<Camera> p) {
  
      void onClick(Complex newCenter) {
        p.nextState = p.nextState.pan(newCenter);
      }
  
      void zoom(num scaleAmount) {
        p.nextState = p.nextState.zoom(scaleAmount);
        if (save != null) {
          save(p.nextState);
        }
      }
  
      var camera = p.state;
      return $.Div(inner: [
        new MandelbrotView(center: camera.center, radius: camera.radius, onClick: onClick),
        $.Div(inner: [
          $.Button(onClick: (_) => zoom(0.5), inner: "Zoom In"),
          $.Button(onClick: (_) => zoom(2.0), inner: "Zoom Out"),
        ]),
        $.Div(inner: [
          "Center: ${camera.center} Radius: ${camera.radius}"
        ]),
        $.Div(inner: "Click image to recenter")
      ]);
  
negative.code:   Camera zoom(num scaleFactor) => new Camera(center, radius * scaleFactor);
  
    @override
    operator==(other) => (other is Camera) && center == other.center && radius == other.radius;
  
    @override
    get hashCode => center.hashCode ^ radius.hashCode;
  
    @override
    toString() => "Camera(${center}, ${radius})";
  
    @override
    clone() => this;
  
    static const start = const Camera(const Complex(0, 0), 2.0);
  }
  