docs: function(tile) {
          
          var replacingCls = 'olTileReplacing';
  
          tile.onLoadStart = function() {
              //if that was first tile then trigger a 'loadstart' on the layer
              if (this.loading === false) {
                  this.loading = true;
                  this.events.triggerEvent("loadstart");
              }
              this.events.triggerEvent("tileloadstart", {tile: tile});
              this.numLoadingTiles++;
              if (!this.singleTile && this.backBuffer && this.gridResolution === this.backBufferResolution) {
                  OpenLayers.Element.addClass(tile.getTile(), replacingCls);
              }
          };
        
          tile.onLoadEnd = function(evt) {
              this.numLoadingTiles--;
              var aborted = evt.type === 'unload';
              this.events.triggerEvent("tileloaded", {
                  tile: tile,
                  aborted: aborted
              });
              if (!this.singleTile && !aborted && this.backBuffer && this.gridResolution === this.backBufferResolution) {
                  var tileDiv = tile.getTile();
                  if (OpenLayers.Element.getStyle(tileDiv, 'display') === 'none') {
                      var bufferTile = document.getElementById(tile.id + '_bb');
                      if (bufferTile) {
                          bufferTile.parentNode.removeChild(bufferTile);
                      }
                  }
                  OpenLayers.Element.removeClass(tileDiv, replacingCls);
              }
              //if that was the last tile, then trigger a 'loadend' on the layer
              if (this.numLoadingTiles === 0) {
                  if (this.backBuffer) {
                      if (this.backBuffer.childNodes.length === 0) {
                          // no tiles transitioning, remove immediately
                          this.removeBackBuffer();
                      } else {
                          // wait until transition has ended or delay has passed
                          this._transitionElement = aborted ?
                              this.div.lastChild : tile.imgDiv;
                          var transitionendEvents = this.transitionendEvents;
                          for (var i=transitionendEvents.length-1; i>=0; --i) {
                              OpenLayers.Event.observe(this._transitionElement,
                                  transitionendEvents[i],
                                  this._removeBackBuffer);
                          }
                          // the removal of the back buffer is delayed to prevent
                          // flash effects due to the animation of tile displaying
                          this.backBufferTimerId = window.setTimeout(
                              this._removeBackBuffer, this.removeBackBufferDelay
                          );
                      }
                  }
                  this.loading = false;
                  this.events.triggerEvent("loadend");
              }
          };
          
          tile.onLoadError = function() {
              this.events.triggerEvent("tileerror", {tile: tile});
          };
          
          tile.events.on({
              "loadstart": tile.onLoadStart,
              "loadend": tile.onLoadEnd,
              "unload": tile.onLoadEnd,
              "loaderror": tile.onLoadError,
              scope: this
          });
      }