/*	SWFObject v2.2 <http://code.google.com/p/swfobject/> 
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
*/
var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();/* 
 * MarkerManager, v1.0
 * Copyright (c) 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 *
 *
 * Author: Doug Ricket, others
 * 
 * Marker manager is an interface between the map and the user, designed
 * to manage adding and removing many points when the viewport changes.
 *
 *
 * Algorithm: The MM places its markers onto a grid, similar to the map tiles.
 * When the user moves the viewport, the MM computes which grid cells have
 * entered or left the viewport, and shows or hides all the markers in those
 * cells.
 * (If the users scrolls the viewport beyond the markers that are loaded,
 * no markers will be visible until the EVENT_moveend triggers an update.)
 *
 * In practical consequences, this allows 10,000 markers to be distributed over
 * a large area, and as long as only 100-200 are visible in any given viewport,
 * the user will see good performance corresponding to the 100 visible markers,
 * rather than poor performance corresponding to the total 10,000 markers.
 *
 * Note that some code is optimized for speed over space,
 * with the goal of accommodating thousands of markers.
 *
 */



/**
 * Creates a new MarkerManager that will show/hide markers on a map.
 *
 * @constructor
 * @param {Map} map The map to manage.
 * @param {Object} opt_opts A container for optional arguments:
 *   {Number} maxZoom The maximum zoom level for which to create tiles.
 *   {Number} borderPadding The width in pixels beyond the map border,
 *                   where markers should be display.
 *   {Boolean} trackMarkers Whether or not this manager should track marker
 *                   movements.
 */
function MarkerManager(map, opt_opts) {
  var me = this;
  me.map_ = map;
  me.mapZoom_ = map.getZoom();
  me.projection_ = map.getCurrentMapType().getProjection();

  opt_opts = opt_opts || {};
  me.tileSize_ = MarkerManager.DEFAULT_TILE_SIZE_;
  
  var maxZoom = MarkerManager.DEFAULT_MAX_ZOOM_;
  if(opt_opts.maxZoom != undefined) {
    maxZoom = opt_opts.maxZoom;
  }
  me.maxZoom_ = maxZoom;

  me.trackMarkers_ = opt_opts.trackMarkers;

  var padding;
  if (typeof opt_opts.borderPadding == "number") {
    padding = opt_opts.borderPadding;
  } else {
    padding = MarkerManager.DEFAULT_BORDER_PADDING_;
  }
  // The padding in pixels beyond the viewport, where we will pre-load markers.
  me.swPadding_ = new GSize(-padding, padding);
  me.nePadding_ = new GSize(padding, -padding);
  me.borderPadding_ = padding;

  me.gridWidth_ = [];

  me.grid_ = [];
  me.grid_[maxZoom] = [];
  me.numMarkers_ = [];
  me.numMarkers_[maxZoom] = 0;

  GEvent.bind(map, "moveend", me, me.onMapMoveEnd_);

  // NOTE: These two closures provide easy access to the map.
  // They are used as callbacks, not as methods.
  me.removeOverlay_ = function(marker) {
    map.removeOverlay(marker);
    me.shownMarkers_--;
  };
  me.addOverlay_ = function(marker) {
    map.addOverlay(marker);
    me.shownMarkers_++;
  };

  me.resetManager_();
  me.shownMarkers_ = 0;

  me.shownBounds_ = me.getMapGridBounds_();
};

// Static constants:
MarkerManager.DEFAULT_TILE_SIZE_ = 1024;
MarkerManager.DEFAULT_MAX_ZOOM_ = 17;
MarkerManager.DEFAULT_BORDER_PADDING_ = 100;
MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE = 256;


/**
 * Initializes MarkerManager arrays for all zoom levels
 * Called by constructor and by clearAllMarkers
 */ 
MarkerManager.prototype.resetManager_ = function() {
  var me = this;
  var mapWidth = MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;
  for (var zoom = 0; zoom <= me.maxZoom_; ++zoom) {
    me.grid_[zoom] = [];
    me.numMarkers_[zoom] = 0;
    me.gridWidth_[zoom] = Math.ceil(mapWidth/me.tileSize_);
    mapWidth <<= 1;
  }
};

/**
 * Removes all currently displayed markers
 * and calls resetManager to clear arrays
 */
MarkerManager.prototype.clearMarkers = function() {
  var me = this;
  me.processAll_(me.shownBounds_, me.removeOverlay_);
  me.resetManager_();
};


/**
 * Gets the tile coordinate for a given latlng point.
 *
 * @param {LatLng} latlng The geographical point.
 * @param {Number} zoom The zoom level.
 * @param {GSize} padding The padding used to shift the pixel coordinate.
 *               Used for expanding a bounds to include an extra padding
 *               of pixels surrounding the bounds.
 * @return {GPoint} The point in tile coordinates.
 *
 */
MarkerManager.prototype.getTilePoint_ = function(latlng, zoom, padding) {
  var pixelPoint = this.projection_.fromLatLngToPixel(latlng, zoom);
  return new GPoint(
      Math.floor((pixelPoint.x + padding.width) / this.tileSize_),
      Math.floor((pixelPoint.y + padding.height) / this.tileSize_));
};


/**
 * Finds the appropriate place to add the marker to the grid.
 * Optimized for speed; does not actually add the marker to the map.
 * Designed for batch-processing thousands of markers.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom for displaying the marker.
 * @param {Number} maxZoom The maximum zoom for displaying the marker.
 */
MarkerManager.prototype.addMarkerBatch_ = function(marker, minZoom, maxZoom) {
  var mPoint = marker.getPoint();
  // Tracking markers is expensive, so we do this only if the
  // user explicitly requested it when creating marker manager.
  if (this.trackMarkers_) {
    GEvent.bind(marker, "changed", this, this.onMarkerMoved_);
  }

  var gridPoint = this.getTilePoint_(mPoint, maxZoom, GSize.ZERO);

  for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
    var cell = this.getGridCellCreate_(gridPoint.x, gridPoint.y, zoom);
    cell.push(marker);

    gridPoint.x = gridPoint.x >> 1;
    gridPoint.y = gridPoint.y >> 1;
  }
};


/**
 * Returns whether or not the given point is visible in the shown bounds. This
 * is a helper method that takes care of the corner case, when shownBounds have
 * negative minX value.
 *
 * @param {Point} point a point on a grid.
 * @return {Boolean} Whether or not the given point is visible in the currently
 * shown bounds.
 */
MarkerManager.prototype.isGridPointVisible_ = function(point) {
  var me = this;
  var vertical = me.shownBounds_.minY <= point.y &&
      point.y <= me.shownBounds_.maxY;
  var minX = me.shownBounds_.minX;
  var horizontal = minX <= point.x && point.x <= me.shownBounds_.maxX;
  if (!horizontal && minX < 0) {
    // Shifts the negative part of the rectangle. As point.x is always less
    // than grid width, only test shifted minX .. 0 part of the shown bounds.
    var width = me.gridWidth_[me.shownBounds_.z];
    horizontal = minX + width <= point.x && point.x <= width - 1;
  }
  return vertical && horizontal;
}


/**
 * Reacts to a notification from a marker that it has moved to a new location.
 * It scans the grid all all zoom levels and moves the marker from the old grid
 * location to a new grid location.
 *
 * @param {Marker} marker The marker that moved.
 * @param {LatLng} oldPoint The old position of the marker.
 * @param {LatLng} newPoint The new position of the marker.
 */
MarkerManager.prototype.onMarkerMoved_ = function(marker, oldPoint, newPoint) {
  // NOTE: We do not know the minimum or maximum zoom the marker was
  // added at, so we start at the absolute maximum. Whenever we successfully
  // remove a marker at a given zoom, we add it at the new grid coordinates.
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var oldGrid = me.getTilePoint_(oldPoint, zoom, GSize.ZERO);
  var newGrid = me.getTilePoint_(newPoint, zoom, GSize.ZERO);
  while (zoom >= 0 && (oldGrid.x != newGrid.x || oldGrid.y != newGrid.y)) {
    var cell = me.getGridCellNoCreate_(oldGrid.x, oldGrid.y, zoom);
    if (cell) {
      if (me.removeFromArray(cell, marker)) {
        me.getGridCellCreate_(newGrid.x, newGrid.y, zoom).push(marker);
      }
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. Markers that moved into
    // the shown bounds are added to the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(oldGrid)) {
        if (!me.isGridPointVisible_(newGrid)) {
          me.removeOverlay_(marker);
          changed = true;
        }
      } else {
        if (me.isGridPointVisible_(newGrid)) {
          me.addOverlay_(marker);
          changed = true;
        }
      }
    }
    oldGrid.x = oldGrid.x >> 1;
    oldGrid.y = oldGrid.y >> 1;
    newGrid.x = newGrid.x >> 1;
    newGrid.y = newGrid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Searches at every zoom level to find grid cell
 * that marker would be in, removes from that array if found.
 * Also removes marker with removeOverlay if visible.
 * @param {GMarker} marker The marker to delete.
 */
MarkerManager.prototype.removeMarker = function(marker) {
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var point = marker.getPoint();
  var grid = me.getTilePoint_(point, zoom, GSize.ZERO);
  while (zoom >= 0) {
    var cell = me.getGridCellNoCreate_(grid.x, grid.y, zoom);

    if (cell) {
      me.removeFromArray(cell, marker);
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(grid)) {
          me.removeOverlay_(marker);
          changed = true;
      } 
    }
    grid.x = grid.x >> 1;
    grid.y = grid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Add many markers at once.
 * Does not actually update the map, just the internal grid.
 *
 * @param {Array of Marker} markers The markers to add.
 * @param {Number} minZoom The minimum zoom level to display the markers.
 * @param {Number} opt_maxZoom The maximum zoom level to display the markers.
 */
MarkerManager.prototype.addMarkers = function(markers, minZoom, opt_maxZoom) {
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  for (var i = markers.length - 1; i >= 0; i--) {
    this.addMarkerBatch_(markers[i], minZoom, maxZoom);
  }

  this.numMarkers_[minZoom] += markers.length;
};


/**
 * Returns the value of the optional maximum zoom. This method is defined so
 * that we have just one place where optional maximum zoom is calculated.
 *
 * @param {Number} opt_maxZoom The optinal maximum zoom.
 * @return The maximum zoom.
 */
MarkerManager.prototype.getOptMaxZoom_ = function(opt_maxZoom) {
  return opt_maxZoom != undefined ? opt_maxZoom : this.maxZoom_;
}


/**
 * Calculates the total number of markers potentially visible at a given
 * zoom level.
 *
 * @param {Number} zoom The zoom level to check.
 */
MarkerManager.prototype.getMarkerCount = function(zoom) {
  var total = 0;
  for (var z = 0; z <= zoom; z++) {
    total += this.numMarkers_[z];
  }
  return total;
};


/**
 * Add a single marker to the map.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom level to display the marker.
 * @param {Number} opt_maxZoom The maximum zoom level to display the marker.
 */
MarkerManager.prototype.addMarker = function(marker, minZoom, opt_maxZoom) {
  var me = this;
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  me.addMarkerBatch_(marker, minZoom, maxZoom);
  var gridPoint = me.getTilePoint_(marker.getPoint(), me.mapZoom_, GSize.ZERO);
  if(me.isGridPointVisible_(gridPoint) && 
     minZoom <= me.shownBounds_.z &&
     me.shownBounds_.z <= maxZoom ) {
    me.addOverlay_(marker);
    me.notifyListeners_();
  }
  this.numMarkers_[minZoom]++;
};

/**
 * Returns true if this bounds (inclusively) contains the given point.
 * @param {Point} point  The point to test.
 * @return {Boolean} This Bounds contains the given Point.
 */
GBounds.prototype.containsPoint = function(point) {
  var outer = this;
  return (outer.minX <= point.x &&
          outer.maxX >= point.x &&
          outer.minY <= point.y &&
          outer.maxY >= point.y);
}

/**
 * Get a cell in the grid, creating it first if necessary.
 *
 * Optimization candidate
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  if (!gridCol) {
    gridCol = grid[x] = [];
    return gridCol[y] = [];
  }
  var gridCell = gridCol[y];
  if (!gridCell) {
    return gridCol[y] = [];
  }
  return gridCell;
};


/**
 * Get a cell in the grid, returning undefined if it does not exist.
 *
 * NOTE: Optimized for speed -- otherwise could combine with getGridCellCreate_.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellNoCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  return gridCol ? gridCol[y] : undefined;
};


/**
 * Turns at geographical bounds into a grid-space bounds.
 *
 * @param {LatLngBounds} bounds The geographical bounds.
 * @param {Number} zoom The zoom level of the bounds.
 * @param {GSize} swPadding The padding in pixels to extend beyond the
 * given bounds.
 * @param {GSize} nePadding The padding in pixels to extend beyond the
 * given bounds.
 * @return {GBounds} The bounds in grid space.
 */
MarkerManager.prototype.getGridBounds_ = function(bounds, zoom, swPadding,
                                                  nePadding) {
  zoom = Math.min(zoom, this.maxZoom_);
  
  var bl = bounds.getSouthWest();
  var tr = bounds.getNorthEast();
  var sw = this.getTilePoint_(bl, zoom, swPadding);
  var ne = this.getTilePoint_(tr, zoom, nePadding);
  var gw = this.gridWidth_[zoom];
  
  // Crossing the prime meridian requires correction of bounds.
  if (tr.lng() < bl.lng() || ne.x < sw.x) {
    sw.x -= gw;
  }
  if (ne.x - sw.x  + 1 >= gw) {
    // Computed grid bounds are larger than the world; truncate.
    sw.x = 0;
    ne.x = gw - 1;
  }
  var gridBounds = new GBounds([sw, ne]);
  gridBounds.z = zoom;
  return gridBounds;
};


/**
 * Gets the grid-space bounds for the current map viewport.
 *
 * @return {Bounds} The bounds in grid space.
 */
MarkerManager.prototype.getMapGridBounds_ = function() {
  var me = this;
  return me.getGridBounds_(me.map_.getBounds(), me.mapZoom_,
                           me.swPadding_, me.nePadding_);
};


/**
 * Event listener for map:movend.
 * NOTE: Use a timeout so that the user is not blocked
 * from moving the map.
 *
 */
MarkerManager.prototype.onMapMoveEnd_ = function() {
  var me = this;
  me.objectSetTimeout_(this, this.updateMarkers_, 0);
};


/**
 * Call a function or evaluate an expression after a specified number of
 * milliseconds.
 *
 * Equivalent to the standard window.setTimeout function, but the given
 * function executes as a method of this instance. So the function passed to
 * objectSetTimeout can contain references to this.
 *    objectSetTimeout(this, function() { alert(this.x) }, 1000);
 *
 * @param {Object} object  The target object.
 * @param {Function} command  The command to run.
 * @param {Number} milliseconds  The delay.
 * @return {Boolean}  Success.
 */
MarkerManager.prototype.objectSetTimeout_ = function(object, command, milliseconds) {
  return window.setTimeout(function() {
    command.call(object);
  }, milliseconds);
};


/**
 * Refresh forces the marker-manager into a good state.
 * <ol>
 *   <li>If never before initialized, shows all the markers.</li>
 *   <li>If previously initialized, removes and re-adds all markers.</li>
 * </ol>
 */
MarkerManager.prototype.refresh = function() {
  var me = this;
  if (me.shownMarkers_ > 0) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
  }
  me.processAll_(me.shownBounds_, me.addOverlay_);
  me.notifyListeners_();
};


/**
 * After the viewport may have changed, add or remove markers as needed.
 */
MarkerManager.prototype.updateMarkers_ = function() {
  var me = this;
  me.mapZoom_ = this.map_.getZoom();
  var newBounds = me.getMapGridBounds_();
  
  // If the move does not include new grid sections,
  // we have no work to do:
  if (newBounds.equals(me.shownBounds_) && newBounds.z == me.shownBounds_.z) {
    return;
  }

  if (newBounds.z != me.shownBounds_.z) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
    me.processAll_(newBounds, me.addOverlay_);
  } else {
    // Remove markers:
    me.rectangleDiff_(me.shownBounds_, newBounds, me.removeCellMarkers_);

    // Add markers:
    me.rectangleDiff_(newBounds, me.shownBounds_, me.addCellMarkers_);
  }
  me.shownBounds_ = newBounds;

  me.notifyListeners_();
};


/**
 * Notify listeners when the state of what is displayed changes.
 */
MarkerManager.prototype.notifyListeners_ = function() {
  GEvent.trigger(this, "changed", this.shownBounds_, this.shownMarkers_);
};


/**
 * Process all markers in the bounds provided, using a callback.
 *
 * @param {Bounds} bounds The bounds in grid space.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processAll_ = function(bounds, callback) {
  for (var x = bounds.minX; x <= bounds.maxX; x++) {
    for (var y = bounds.minY; y <= bounds.maxY; y++) {
      this.processCellMarkers_(x, y,  bounds.z, callback);
    }
  }
};


/**
 * Process all markers in the grid cell, using a callback.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processCellMarkers_ = function(x, y, z, callback) {
  var cell = this.getGridCellNoCreate_(x, y, z);
  if (cell) {
    for (var i = cell.length - 1; i >= 0; i--) {
      callback(cell[i]);
    }
  }
};


/**
 * Remove all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.removeCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.removeOverlay_);
};


/**
 * Add all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.addCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.addOverlay_);
};


/**
 * Use the rectangleDiffCoords function to process all grid cells
 * that are in bounds1 but not bounds2, using a callback, and using
 * the current MarkerManager object as the instance.
 *
 * Pass the z parameter to the callback in addition to x and y.
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate (x, y, z).
 */
MarkerManager.prototype.rectangleDiff_ = function(bounds1, bounds2, callback) {
  var me = this;
  me.rectangleDiffCoords(bounds1, bounds2, function(x, y) {
    callback.apply(me, [x, y, bounds1.z]);
  });
};


/**
 * Calls the function for all points in bounds1, not in bounds2
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate.
 */
MarkerManager.prototype.rectangleDiffCoords = function(bounds1, bounds2, callback) {
  var minX1 = bounds1.minX;
  var minY1 = bounds1.minY;
  var maxX1 = bounds1.maxX;
  var maxY1 = bounds1.maxY;
  var minX2 = bounds2.minX;
  var minY2 = bounds2.minY;
  var maxX2 = bounds2.maxX;
  var maxY2 = bounds2.maxY;

  for (var x = minX1; x <= maxX1; x++) {  // All x in R1
    // All above:
    for (var y = minY1; y <= maxY1 && y < minY2; y++) {  // y in R1 above R2
      callback(x, y);
    }
    // All below:
    for (var y = Math.max(maxY2 + 1, minY1);  // y in R1 below R2
         y <= maxY1; y++) {
      callback(x, y);
    }
  }

  for (var y = Math.max(minY1, minY2);
       y <= Math.min(maxY1, maxY2); y++) {  // All y in R2 and in R1
    // Strictly left:
    for (var x = Math.min(maxX1 + 1, minX2) - 1;
         x >= minX1; x--) {  // x in R1 left of R2
      callback(x, y);
    }
    // Strictly right:
    for (var x = Math.max(minX1, maxX2 + 1);  // x in R1 right of R2
         x <= maxX1; x++) {
      callback(x, y);
    }
  }
};


/**
 * Removes value from array. O(N).
 *
 * @param {Array} array  The array to modify.
 * @param {any} value  The value to remove.
 * @param {Boolean} opt_notype  Flag to disable type checking in equality.
 * @return {Number}  The number of instances of value that were removed.
 */
MarkerManager.prototype.removeFromArray = function(array, value, opt_notype) {
  var shift = 0;
  for (var i = 0; i < array.length; ++i) {
    if (array[i] === value || (opt_notype && array[i] == value)) {
      array.splice(i--, 1);
      shift++;
    }
  }
  return shift;
};
var CS = {};

/** @namespace */
CS.Tiles = {};
CS.Controls = {};
CS.Host = 'http://cityscanner.nnow.ru';
CS.Panoramas = {};

/** @ignore */
Function.prototype.scope = function(o){
    var fn = this;
    return function(){
        return fn.apply(o, arguments);
    };
};

/** @ignore */
CS.jsonp = function(url,params,func){
    cnt = +new Date;
    var callback = 'csjsonp_'+cnt;
    params_url = '';
    
    /*if (toString.call(params) === "[object Function]"){
        func = params;
        params = {};
    }*/
    
    params['callback']=callback; params['_']=cnt;
    for (k in params){
        params_url+=encodeURIComponent(k) + '=' + encodeURIComponent(params[k])+'&';
    }
    params_url.lenght-=1;
    url = (CS.Host+'/api'+url+'?'+params_url).replace(/%20/g, "+");
    
    var head = document.getElementsByTagName("head")[0];
    var script = document.createElement("script");
    script.src = url;
    script.type = 'text/javascript';
    head.appendChild( script );
    
    window[ callback ] = function(tmp){
				data = tmp;
				func(data);

				window[ callback ] = undefined;
				try{ delete window[ callback ]; } catch(e){}
				if ( head ){head.removeChild( script );}
    };
}

/** @ignore */
CS.getcookie=function(name) {
	var cookie = " " + document.cookie;
	var search = " " + name + "=";
	var setStr = null;
	var offset = 0;
	var end = 0;
	if (cookie.length > 0) {
		offset = cookie.indexOf(search);
		if (offset != -1) {
			offset += search.length;
			end = cookie.indexOf(";", offset)
			if (end == -1) {
				end = cookie.length;
			}
			setStr = unescape(cookie.substring(offset, end));
		}
	}
	return(setStr);
}

/** @ignore */
CS.setcookie=function(name, value, expires, path, domain, secure) {
      document.cookie = name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

/**
 * @description Двумерная координата (нужна для представления пиксельных размеров и пиксельных координат)
 * @param {Number} x координата x
 * @param {Number} y координата y
 * @property {Number} x координата x
 * @property {Number} y координата y
 * @class
 */
CS.XY = function(x,y){
    this.x = x;
    this.y = y;
}
/**
 * @description сравнивает текущую точку с xy
 * @param {CS.XY} xy
 */
CS.XY.prototype.equals = function(xy){
    return this.x == point.x && this.y == point.y;
}
/** @description возвращает строковое представление точки в виде "x,y"*/
CS.XY.prototype.toString = function(){
    return this.x+','+this.y;
}

/**
 * @description Изображение для {@link CS.Marker}.icon или {@link CS.Marker}.shadow
 * @param {String} url url изображения
 * @param {CS.XY} [size] размер изображения в пикселях (по умолчанию 40,40)
 * @param {CS.XY} [anchor] пиксельная координата относительно левого верхнего угла изображения, в которой он привязан к карте (по умолчанию size.x/2,size.y/2)
 * @property {String} url url изображения
 * @property {CS.XY} size размер изображения в пикселях
 * @property {CS.XY} anchor пиксельная координата относительно левого верхнего угла изображения, в которой он привязан к карте
 * @class
 */
CS.Image = function(url,size,anchor){ 
    this.url = url;
    this.size = size || new CS.XY(40,40);
    this.anchor = anchor || new CS.XY(this.size.x/2,this.size.y/2);
}
CS.Event = new function(){
    this.triggers={};
};
CS.Event.add = function(object,event,trigger){
    if(this.triggers[object] && this.triggers[object][event]){
        this.triggers[object][event].push(trigger);
    }else{
        this.triggers[object]={};
        this.triggers[object][event]=[trigger];
    }
    
    return this.triggers[object][event][-1];
}
CS.Event.remove = function(){

}
CS.Event.clear=function(){
    this.triggers={};
}
CS.Event.trigger=function(object,event){
    if (this.triggers[object] && this.triggers[object][event]){
        for(var t=0; t<this.triggers[object][event].length; ++t){
            this.triggers[object][event][t]();
        }
    }
}


//CS.EventObj = function(){this.events = {};}

/*CS.EventObj.prototype.bind = function(events){
    for (event in events){
        this.events[event]={
            bind : function(func){this.fire = func},
            fire : function(){},
            del : function(){this.fire = function(){}},
        }
    }

}*/

/*CS.EventObj.prototype._gbind = function(eventobj,events){
    var gbind = {'click': function(func){ return GEvent.addListener(
                        eventobj, this._event, function(_overlay, latlng){func(new CS.LngLat(0,0,latlng))})},
                 'dragstart':function(func){return GEvent.addListener(
                        eventobj, this._event, func)},};
    
    for (event in events){
        this.events[event]={
            _listener : null,
            _event : event,
            _bind : gbind[event],
            fire : function(){},
            bind : function(func){
                    this.fire = func;
                    this._listener =  this._bind(func);
                },
            del : function(){if(this._listener){GEvent.removeListener(this._listener);}this.fire = function(){}},
        }
    }

}*/
////////////////////////////////////////////////////////////
//// Map on top google map
////////////////////////////////////////////////////////////

/*Events*/
CS.EventHandler = function(eventlistener){
    this._eventlistener = eventlistener;
}
CS.EventHandler.prototype.remove = function(){
    GEvent.removeListener(this._eventlistener);
}

CS.Events = function(obj){
    this._eventobj = obj;
}
CS.Events.prototype.click = function(func, d){
    return new CS.EventHandler(GEvent.addListener(this._eventobj, 'click', 
            function(_overlay,ll){
                if (ll != undefined){ll=new CS.LngLat(0,0,ll)}
                //console.log('click ghandler data:'+d);
                func(ll, d/*, _overlay*/);
            }));
}
CS.Events.prototype.dragstart = function(func, data){
    return new CS.EventHandler(GEvent.addListener(this._eventobj, 'dragstart',
            function(){
                func(data);
            }));
}

/**
 * @description Долгота/Широта
 * @param lng долгота
 * @param lat широта
 * @class
 */
CS.LngLat = function(lng,lat,_copy){
    if (_copy){
        this._latlng = _copy;
    }else{
        this._latlng = new GLatLng(lat,lng,false);
    }
}
/** @description возвращает широту*/
CS.LngLat.prototype.lat = function(){
    return this._latlng.lat();
}
/** @description возвращает долготу*/
CS.LngLat.prototype.lng = function(){
    return this._latlng.lng();
}
CS.LngLat.prototype.toUrlValue = function(){
    //влияет на common.js из utlis.js
    //нужно поменять порядок на lnglat
    return this._latlng.toUrlValue();
}
CS.LngLat.prototype.toString = function(){
    return '('+this._latlng.lng()+','+this._latlng.lat()+')';
}
/** @ignore */
CS.LngLat.prototype.moveByAzimuth = function(azimuth, radius, zoom){
    var normalProj = G_NORMAL_MAP.getProjection();
    var pt = normalProj.fromLatLngToPixel(this._latlng,  zoom);
    var y = pt.y + radius * Math.sin(az * Math.PI/180);
	var x = pt.x + radius * Math.cos(az * Math.PI/180);

	return new CS.LngLat(0,0,normalProj.fromPixelToLatLng(new GPoint(x,y), zoom));
}

/**
 * @description Маркер
 * @param params
 * @param {CS.LngLat} params.lnglat координата маркера
 * @param {CS.Image|String} param.icon основное изображение {@link CS.Image} или url
 * @param {CS.Image|String} param.shadow теневое изображение {@link CS.Image} или url
 * @param {String} [param.title] подсказка к маркеру
 * @param {Boolean} [param.draggable] определяет, могут ли пользователи перемещать маркер (по умолчанию false)
 * @param {Boolean} [param.clickable] определяет, реагирует ли маркер на щелчок по нему(по умолчанию true)
 * @param {Number} [param.zindex] zindex
 * @class
 */
CS.Marker = function(params){
    
    this._overlay = new GMarker(params.lnglat._latlng, {
        'title': params.title || '',
        'draggable': params.draggable!=undefined?params.draggable:false,
        'clickable': params.clickable!=undefined?params.clickable:true,
        'icon': this._initicon(params.icon,params.shadow),
        'zIndexProcess':function(marker,b){return GOverlay.getZIndex(marker.getPoint().lat())+(params.zindex || 0);}
    });
    this.events = new CS.Events(this._overlay);
}
CS.Marker.prototype._initicon = function(csicon,csshadow){
    if(typeof(csicon)=='string'){csicon=new CS.Image(csicon)}
    if(typeof(csshadow)=='string'){csshadow=new CS.Image(csshadow)}
    
    icon = new GIcon();
    icon.image = csicon.url;
    icon.shadow = csshadow.url;
    icon.iconSize = new GSize(csicon.size.x,csicon.size.y);
    icon.shadowSize = new GSize(csshadow.size.x,csshadow.size.y);
    icon.iconAnchor = new GPoint(csicon.anchor.x,csicon.anchor.y);
    return icon;
}
/**
 * @description меняет позицию маркера если передать lnglat, в противном случае возвращает текущую
 * @param {CS.LngLat} [lnglat]
 */
CS.Marker.prototype.lnglat = function(lnglat){
    if (lnglat){
        this._overlay.setLatLng(lnglat._latlng);
    }else{
        return new CS.LngLat(0,0,this._overlay.getLatLng());
    }
}
/** @description показывает маркер*/
CS.Marker.prototype.show = function(){
    this._overlay.show();
}
/** @description скрывает маркер*/
CS.Marker.prototype.hide = function(){
    this._overlay.hide();
}
CS.Marker.prototype.draggable = function(draggable){
    if(draggable){
        //enableDragging() Для этого маркер должен быть инициализирован с GMarkerOptions.draggable = true
        //disableDragging()
    }else{
        return this._overlay.draggable();
    }
}
/** 
 * @description меняет изображение маркера
 * @param {String} url URL нового изображения
 */
CS.Marker.prototype.icon = function(url){
    this._overlay.setImage(url);
}


/**
 * @description Менеджер маркеров для управления отображения большого кол-ва маркеров на основе видимых границ карты
 * @param {CS.Map|CS.BaseMap} map объект карты
 * @class
 */
CS.Manager = function(map){
    this._mgr = new MarkerManager(map._map);
    this._overlays = [];
}
/**
 * @description добавляет маркер в менеджер маркеров
 * @param {CS.Marker} marker маркер
 */
CS.Manager.prototype.add = function(marker){
    this._overlays.push(marker._overlay);
}
/**
 * @description удаляет маркер из менеджера маркеров
 * @param {CS.Marker} marker маркер
 */
CS.Manager.prototype.remove = function(marker){
    this._mgr.removeMarker(marker._overlay);
}
/** @description удаляет все маркеры из менеджера маркеров */
CS.Manager.prototype.clear = function(){
    this._mgr.clearMarkers();
}
/** @description обновляет маркеры на карте */
CS.Manager.prototype.refresh = function(){
    this._mgr.addMarkers(this._overlays, 1);
    this._mgr.refresh();
    this._overlays = [];
}

/**
 * @description базовый класс который вы можете использовать для написания своих типов тайлов
 * @param params
 * @param {String} params.title заголовок для типа карты
 * @param {Boolean} params.transperent прозрачны ли тайлы?
 * @param {String} params.urlTemplate адрес вида 'path/to/maptiles/{PROJ}/{Z}_{X}_{Y}.png'
 * @param {String} params.copyright копирайт
 * @param {Integer} params.minZoomLevel минимальный зум
 * @param {Integer} params.maxZoomLevel максимальный зум
 */
CS.Tiles.Base = function (params){
    var cr = new GCopyrightCollection(params.copyright);
    cr.addCopyright(new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180), new GLatLng(90,180)), 0, " "));
    return {params : params,
            _tiles : new GTileLayer(cr,params.minZoomLevel,params.maxZoomLevel,
                                    {tileUrlTemplate:params.urlTemplate.replace(/{PROJ}/,'google'), isPng:true})}
}
/**
 * @description тайлы по умолчанию для карты в зависимости от того какой сейчас используется АПИ(гугл или яндекс)
 */
CS.Tiles.Default = function(){
    return {params : {title:'Default'},
            _tiles : G_NORMAL_MAP.getTileLayers()[0]}
}



/**
 * @description Объект карты
 * @param [orig_map] оригинальный объект с картой, например, GMap2; если параметр передан, остальные параметры игнорируются
 * @param dom_id dom элемент для вставки
 * @param params параметры
 * @param params.tiles массив типов тайлов
 * @class
 */
CS.BaseMap = function(orig_map, dom_id, params){
    if (!arguments.length) 
        return;
    if (orig_map)
    {
      this._map = orig_map;
      window.setTimeout(function(){
        this.mgr = new CS.Manager(this); 
      }.scope(this), 0);
    }
    else
    {
      this._map = null;
      var maptypes = [];
      for (var t=0; t<params.tiles.length; ++t){
          maptypes.push(new GMapType([params.tiles[t]._tiles],G_NORMAL_MAP.getProjection(),params.tiles[t].params.title));
      }

      if (GBrowserIsCompatible()) {
          this._map = new GMap2(document.getElementById(dom_id), { mapTypes : maptypes });
          this._map.disableDoubleClickZoom();
          this._map.enableScrollWheelZoom();
          this._map.addControl(new GSmallZoomControl());
          
          // Marker Manager
          window.setTimeout(function(){
              this.mgr = new CS.Manager(this); 
          }.scope(this), 0);
      }
      else {
          alert("Sorry, the Google Maps API is not compatible with this browser.");
      }
    }
    
    //this._gbind(this._map,{'click','dragstart'});
    this.events = new CS.Events(this._map);
       
    //$('body').unload(GUnload);
}
//CS.BaseMap.prototype = new CS.EventObj();

CS.BaseMap.prototype._setcenter = function(lnglat,zoom){
    this._map.setCenter(lnglat._latlng,zoom);
}
CS.BaseMap.prototype._getcenter = function(){
    return new CS.LngLat(0,0,this._map.getCenter());
}
/**
 * @description устанавливает центр карты в новую позицию если передать lnglat, в противном случае возвращает текущую
 * @param {CS.LngLat} [lnglat] широта/долгота
 * @param {Integer} [zoom] зум
 */
CS.BaseMap.prototype.center = function(lnglat,zoom){
    if(lnglat){
        this._setcenter(lnglat,zoom);
    }else{
        return this._getcenter();
    }
}
/**
 * @description устанавливает зум для карты если передать zoom, в противном случае возвращает текущий
 * @param {Integer} [zoom]
 */
CS.BaseMap.prototype.zoom = function(zoom){
    if(zoom){
        this._map.setZoom(zoom);
    }else{
        return this._map.getZoom();
    }
}
/**
 * @description устанавливает минимальный зум если передать minzoom, в противном случае возвращает текущий
 * @param {Integer} [minzoom] минимальное значение зума для карты(1-17)
 */
CS.BaseMap.prototype.minzoom = function(minzoom){
    if (minzoom){
        var mt = this._map.getMapTypes();
        for (var i = 0; i < mt.length; i++) {
            mt[i].getMinimumResolution = function(){
                return minzoom;
            }
        }
    }else{
        return this._map.getCurrentMapType().getMinimumResolution();
    }
}
/**
 * @description устанавливает максимальный зум если передать maxzoom, в противном случае возвращает текущий
 * @param {Integer} [maxzoom] максимальное значение зума для карты(1-17)
 */
CS.BaseMap.prototype.maxzoom = function(maxzoom){
    if (maxzoom){
        var mt = this._map.getMapTypes();
        for (var i = 0; i < mt.length; i++) {
            mt[i].getMaximumResolution = function(){
                return maxzoom;
            }
        }
    }else{
        return this._map.getCurrentMapType().getMaximumResolution();
    }
}

/**
 * @description проверяет содержит ли карта в видимой области lnglat
 * @param {CS.LngLat} lnglat долгота/широта
 */
CS.BaseMap.prototype.contains = function(lnglat){
    return this._map.getBounds().containsLatLng(lnglat._latlng);
}

/**
 * @description добавляет на карту оверлей
 * @param {CS.Marker} overlay оверлей(на данный момент единственный тип оверлеев это маркеры)
 */
CS.BaseMap.prototype.addoverlay = function(overlay){
    this._map.addOverlay(overlay._overlay);
}
/**
 * @description добавляет на карту еще один тип тайлов поверх предыдущих
 * @param {CS.Tiles} tiles тип тайлов
 */
CS.BaseMap.prototype.addtiles = function(tiles){
    this._map.addOverlay(new GTileLayerOverlay(tiles._tiles));
}

CS.BaseMap.prototype._createIcon = function (icons){
    if (icons){
        icon = new GIcon();
        icon.image = icons[0];
        icon.shadow = icons[1];
        icon.iconSize = new GSize(icons[2], icons[3]);
		icon.iconAnchor = new GPoint(icons[2]/2, icons[3]/2);
		
        return icon;
    }else{
        return new GIcon(G_DEFAULT_ICON);
    }
}
/** @ignore */
CS.BaseMap.prototype.createMarker = function(lnglat, title, icons, editable, markerFunction, data){   
    gmarker = new GMarker(lnglat._latlng, {
        'title': title,
        'draggable': editable,
        'icon': this._createIcon(icons)
    });

    var marker = new CS.Marker(gmarker);
    marker.events.click(markerFunction, data);

    return marker;
}

CS.BaseMap.prototype.refresh = function(){}
CS.BaseMap.prototype.resize = function(){
    this._map.checkResize();
}
/** @description тайлы OpenStreetMap */
CS.Tiles.OpenStreet = function(){
    return new this.Base({title: 'OpenStreetMap',
            transperent: false,
            urlTemplate: 'http://b.tile.cloudmade.com/ce768d88758f5a9c925fbff9a4a34e40/4424/256/{Z}/{X}/{Y}.png',
            copyright: 'Map data <a href=\"http://creativecommons.org/licenses/by-sa/2.0/\">CCBYSA</a> 2009 <a href=\"http://openstreetmap.org\">OpenStreetMap.org</a> contributors',
            minZoomLevel:1,
            maxZoomLevel:17,
            api_key:null})
}
/** @description тайлы покрытия панорамной съемкой */
CS.Tiles.CityScanner = function(){
    return new this.Base({title: 'CityScanner',
            transperent: true, 
            urlTemplate: CS.Host+'/static/media/map_tiles/{PROJ}/{Z}_{X}_{Y}.png',
            copyright: '',
            minZoomLevel:13,
            maxZoomLevel:17,
            api_key:null})
}
CS.Tiles.Google = function(){
    return new this.Base({title: 'Google',
            transperent: false,
            urlTemplate: 'http://mt1.google.com/vt/lyrs=m@113&hl=ru&x={X}&y={Y}&z={Z}&s=Galileo',
            copyright: '',
            minZoomLevel:13,
            maxZoomLevel:17,
            api_key:null})
}

/**
 * @description Объект карты
 * @augments CS.BaseMap
 * @param dom_id dom элемент для вставки
 * @param params параметры
 * @param [orig_map] оригинальный объект с картой, например, GMap2; если параметр передан, остальные параметры игнорируются
 * @param {Interger} [params.zoom] зум карты, по умолчанию 14
 * @param {String} [params.city] короткое обозначение города(латинским), по умолчанию 'ekb'
 * @param {CS.LngLat} [params.center] центр карты, по умолчанию CS.LngLat('60.663757','56.928491')
 * @param [params.tiles] массив типов тайлов, по умолчанию [CS.Tiles.Default()]
 * @property {String} city короткое обозначение города(латинским)
 * @class
 */
CS.Map = function(orig_map, dom_id, params){
    
    if(!params){params = {}};
    if (!orig_map) params.tiles = params.tiles || [CS.Tiles.Default()];
    
    CS.BaseMap.call(this, orig_map, dom_id, params);
    
    if (!orig_map) this.center(params.center || new CS.LngLat('60.663757','56.928491'), params.zoom || 14);
    this.city = params.city || 'nn';
}
CS.Map.prototype = new CS.BaseMap();
CS.Map.prototype.constructor = CS.BaseMap;

/**
 * @param address адрес без города
 * @param f обработчик
 */
CS.Map.prototype.geocoding = function (address, f){    
    CS.jsonp('/geocoding/',{'address': address, 'city': this.city},function(pnt){
        var lnglat = null;
        if (pnt){
            lnglat = new CS.LngLat(pnt[0],pnt[1]);
        }
        f(lnglat);
    });
}
/**
 * @description возвращает список тегов
 * @param f
 */
CS.Map.prototype.tags = function(f){
    CS.jsonp('/tags/',{'city':this.city},f);
}

CS.Map.prototype.search = function (params,f){
    params.city = this.city;
    params.latest = params.latest || 0;
    params.q = params.q || '';
    CS.jsonp('/search/',params,function(resp){
        if (resp.lnglat){
            resp.lnglat = new CS.LngLat(resp.lnglat[0],resp.lnglat[1]);
        }
        f(resp);
    });
}
/*formatDate = function (string) {
    var regexp = "([0-9]{4})-0?([1-9]+)-([0-9]{2}) " +
        "([0-9]{2}:[0-9]{2}):[0-9]{2}";

	var months=[ 
	'января',
	'февраля',
	'марта',
	'апреля',
	'мая',
	'июня',
	'июля',
	'августа',
	'сентября',
	'октября',
	'ноября',
	'декабря'
	]
	
	var d = string.match(new RegExp(regexp));
	if (!d) return '';
	return d[3]+' '+months[parseInt(d[2])-1]+' '+d[1]+' г. в '+d[4];
}*/

/**
 * @description Объект панорамы
 * @param dom_id dom элемент для вставки
 * @param params параметры
 * @param params.city короткое обозначение города(латинским)
 * @param [params.pano] id стартовой панорамы
 * @param [params.poi] имя стартовой poi
 * @param [params.hlookat] горизонтальный угол разворота панорамы
 * @param [params.vlookat] вертикальный угол разворота панорамы
 * @param [params.fov] зум
 * @property {String} dom_id dom элемент связанный с объектом панорамы
 * @property {String} params.city короткое обозначение города(латинским)
 * @class
 */
CS.BasePano = function(dom_id, params){
    if (!arguments.length) {return}

    this.kr = null;
    this.dom_id = dom_id;
    CS.Panoramas[dom_id]=this;
    
    this.params = {'get_xml': params.get_xml || CS.Host+'/api/get_xml/',
                    'get_xml_static': params.get_xml_static || CS.Host+'/get_xml/static/',
                    'city':params.city};
    var swfparams = {'license':CS.Host+'/static/media/swf/pano.license'};
    if (params.poi || params.pano){
        if (params.pano){swfparams['pano'] = this.params.get_xml+'%3Fid='+params.pano+'%26dom_id='+this.dom_id; this.params.mode='pano'}
        else if (params.poi){swfparams['pano'] = this.params.get_xml_static+'interiors/' + params.poi + '.xml'; this.params.mode='poi'}
        if (params.hlookat) {swfparams['view.hlookat']=params.hlookat;}
        if (params.vlookat) {swfparams['view.vlookat']=params.vlookat;}
        if (params.fov) {swfparams['view.fov']=params.fov;}
    }else{
        swfparams['pano'] = this.params.get_xml+'%3Fcity='+this.params.city+'%26dom_id='+this.dom_id;
    }
    
	if (swfobject.hasFlashPlayerVersion("6.0.0")){
        swfobject.embedSWF(CS.Host+'/static/media/swf/pano108.swf',
                           this.dom_id,
                           document.getElementById(this.dom_id).style['width'],
                           document.getElementById(this.dom_id).style['height'],
                           '9.0.28', CS.Host+'/static/media/js/swfobject21/expressInstall.swf', 
                           swfparams, 
                           {allowfullscreen: true, bgcolor: '#000000', wmode: 'window', allowscriptaccess: 'always'},
                           {id: this.dom_id, name: this.dom_id},function(e){this._onembed(e)}.scope(this)
                           );
        //this._initplugins();
        /*var flashvars = '';
        for (var k in swfparams){
            flashvars += "&" + k + "=" + swfparams[k];
        }
        var par = {allowfullscreen: true, bgcolor: '#000000', wmode: 'window', flashvars:flashvars};
        var att = { data: this.params.swfpath, 
                            width: document.getElementById(this.dom_id).style['width'],
                            height: document.getElementById(this.dom_id).style['height'],
                            id: this.dom_id, name: this.dom_id};
        this.kr = swfobject.createSWF(att, par, this.dom_id);
        console.log(this.kr);*/
    }else{
        document.getElementById(this.dom_id).innerHTML = 'Требуется Flash Player версии не ниже 9.0.28';
    }
}

/*
CS.BasePano.prototype.addzoom = function(){
    this.kr.call('addplugin(zoombuttons)');
    this.kr.set('plugin[zoombuttons].url',CS.Host+'/static/media/swf/plugins-1.0.8/zoombuttons.swf');
    this.kr.set('plugin[zoombuttons].keep','true');
    this.kr.set('plugin[zoombuttons].modebutton','false');
}

*/

CS.BasePano.prototype._initplugins = function(){

    if (this.kr.get('control.mousetype')=='drag2d'){
	this.kr.set('plugin[viewmode_moveto].visible','true');
    }
    else {
	this.kr.set('plugin[viewmode_drag2d].visible','true');
    }
    this.kr.set('plugin[zoombuttons].visible','true');
}

CS.BasePano.prototype._onembed=function(e){
    //console.log(e.success);
    if (e.success) {
        //this.kr = e.ref;
        this.kr = document.getElementById(this.dom_id);
        //this.kr = swfobject.getObjectById(e.id);
        
        //console.log(this.kr.set);
        //this.kr.set('plugin[viewmode_'+this.kr.get('control.mousetype')+'].visible','true');
        /*vm = $.cookie('kr_viewmode');
        if (vm) {
            this.kr.set('control.mousetype', vm);
            this.kr.set('plugin[viewmode_'+vm+'].visible','true');
        }else{
            this.kr.set('plugin[viewmode_'+this.kr.get('control.mousetype')+'].visible','true');
        }*/
    }
}

CS.BasePano.prototype._init=function(){
    vm = CS.getcookie('kr_viewmode');
    if (vm) {
      this.kr.set('control.mousetype', vm);
    }
    this._initplugins();
}

/** @description переключает режимы управления панорамой */
CS.BasePano.prototype.toggle_mousemode=function(){
    if (this.kr.get('control.mousetype')=='moveto'){
      this.kr.set('control.mousetype','drag2d');
      this.kr.set('plugin[viewmode_moveto].visible','false');
      this.kr.set('plugin[viewmode_drag2d].visible','true');
      CS.setcookie('kr_viewmode','drag2d',"Mon, 01-Jan-2020 00:00:00 GMT");
    }else{
      this.kr.set('control.mousetype','moveto');
      this.kr.set('plugin[viewmode_drag2d].visible','false');
      this.kr.set('plugin[viewmode_moveto].visible','true');
      CS.setcookie('kr_viewmode','moveto',"Mon, 01-Jan-2020 00:00:00 GMT");
    }
}
/**
 * @description загружает панораму
 * @param id id панорамы
 * @param {CS.LngLat} lookto направление разворота панорамы
 */
CS.BasePano.prototype.setpano=function(id,lookto){
    var url = "?id="+id+'&dom_id='+this.dom_id;
    if (lookto){url += "&lookto="+lookto;}

    this.kr.call("loadpano("+url+",null,MERGE,BLEND(1))");
}
/**
 * @description передает в обраточик id ближайшей к lnglat панорамы или undefined если ничего не найдено
 * @param {CS.LngLat} lnglat долгота/широта
 * @param f обработчик
 */
CS.BasePano.prototype.getpanoBylnglat=function(lnglat,f){
    CS.jsonp('/get_panoid_bylnglat/',{'lnglat':lnglat, 'city':this.params.city}, f);
}
/**
 * @description загружает панораму ближайшую к lnglat
 * @param {CS.LngLat} lnglat долгота/широта
 */
CS.BasePano.prototype.setpanoBylnglat=function(lnglat){
    this.getpanoBylnglat(lnglat,function(id){if(id){this.setpano(id,lnglat)}}.scope(this));
}

CS.BasePano.prototype.setpoi=function(xml){
    this.kr.call("loadpano(/static/" + xml+",null,MERGE,BLEND(1))");
}


/**
 * @description устанавливает вертикальный угол наклона камеры если передать vlookat, в противном случае возвращает текущий
 * @param {Integer} [vlookat]
 */
CS.BasePano.prototype.vlookat=function(vlookat){
  if (this.kr.get){
    if(vlookat){
        this.kr.set('view.vlookat',vlookat);
    }else{
        return this.kr.get('view.vlookat');
    }
  }
  else return false;    
}

/**
 * @description устанавливает горизонтальный угол наклона камеры если передать hlookat, в противном случае возвращает текущий
 * @param {Integer} [hlookat]
 */
CS.BasePano.prototype.hlookat=function(hlookat){
  if (this.kr.get){
    if(hlookat){
        this.kr.set('view.hlookat',hlookat);
    }else{
        return this.kr.get('view.hlookat');
    }
  }
  else return false;    
}

/**
 * @description устанавливает угол обзора камеры (зум) если передать fov, в противном случае возвращает текущий
 * @param {Integer} [fov]
 */
CS.BasePano.prototype.fov=function(fov){
  if (this.kr.get){
    if(fov){
        this.kr.set('view.fov',fov);
    }else{
        return this.kr.get('view.fov');
    }
  }
  else return false;
}
    
/**
 * @description возвращает id текущей панорамы
 */
CS.BasePano.prototype.getcurrentpano=function(){
  if (this.kr.get){
    return this.kr.get('data[pano_id].content');
  }
  else return false;   
}    

/**
 * @description Объект панорамы для использования вместе с {@link CS.Map}
 * @augments CS.BasePano
 * @property {CS.Marker} radar маркер который отображает координаты текущей панорамы и ее направление на карте
 * @property {CS.Map|CS.BaseMap} map карта с которой взаимодействует панорама
 * @param dom_id dom элемент для вставки
 * @param params параметры
 * @param {CS.Map|CS.BaseMap} params.map объект карты, если не переданы параметры стартовой панорамы, загружется ближайшая к map.center()
 * @class
 */
CS.Pano = function(dom_id,params){
    this.map = params.map;
    params.city = this.map.city;
    if(!params.pano && !params.poi){
        CS.jsonp('/get_panoid_bylnglat/',{'lnglat':this.map.center(), 'city':params.city}, function(id){
            if(id){params.pano = id}
            else {params.pano = 14000}
            CS.BasePano.call(this, dom_id, params);
        }.scope(this));
    }else{
        CS.BasePano.call(this, dom_id, params);
    }
        
    this.lastHlookat = null;
    this.lastFov = null;
    this.radar = null;
}
CS.Pano.prototype = new CS.BasePano();

/**
 * @description возвращает permalink на текущую панораму с учетом разворота и зума
 * @param {Boolean} [rel] возвращать короткую ссылку (без основной части с доменным именем и решетки) или нет
 */
CS.Pano.prototype.permalink=function(rel){
  if (rel) url=''; else url=window.location.href.split('#')[0]+"#";
  url = url + 'h=' + this.kr.get("view.hlookat") + '&v=' + this.kr.get("view.vlookat") + '&z=' + this.kr.get("view.fov"); 
	if (this.mode == 'pano') {
		return url + '&id=' + this.kr.get("data[pano_id].content");
	}else if(this.mode == 'poi'){
        var ll=this.map.center().toUrlValue();
		return url + '&iid=' + this.kr.get("data[pano_name].content")+'&ll='+ll;
	}
}


CS.Pano.prototype._updateRadar = function(){
	if (this.kr.get && this.radar) {
		hlookat=this.kr.get('view.hlookat');
		fov=this.kr.get('view.fov')*(1+this.kr.get('view.fisheye'));
		if (!this.lastHlookat || Math.abs(hlookat - this.lastHlookat)%360 > 5 || Math.abs(fov - this.lastFov) > 5) {
			this.lastHlookat=hlookat;
			this.lastFov=fov;
			viewAzimuth = Number(this.kr.get('data[azimuth].content')) + 180 + this.kr.get('view.hlookat');
			viewAzimuth = (viewAzimuth+(Math.floor(Math.abs(viewAzimuth) / 360)+2)*360+22.5)%360;
			viewAzimuth = 45 * Math.floor(viewAzimuth / 45);
			this.radar.icon(CS.Host+"/static/media/images/point"+viewAzimuth+".png");
		}
	}
	/*else
	{
	    clearInterval(this._radarinterval);
	}*/
}
CS.Pano.prototype._radar = function(ll){
    if(!this.radar && this.map){
        this.radar = new CS.Marker({lnglat: ll,
                                icon: new CS.Image(CS.Host+'/static/media/images/point.png',new CS.XY(100,100)),
                                shadow: new CS.Image('',new CS.XY(0,0),new CS.XY(0,0)),
                                clickable: false,
                                zindex: 255});
        this.map.addoverlay(this.radar);
        //this._radarinterval=setInterval("CS.Panoramas['"+this.dom_id+"']._updateRadar()", 100);
    }
}

CS.Pano.prototype.panochanged = function(id, lng, lat){
    this.mode = 'pano';
    this._init();
    ll = new CS.LngLat(lng,lat);
    this._radar(ll);
    this.radar.lnglat(ll);
    this.radar.show();
    if(this.map){this.map.center(ll);}
}
CS.Pano.prototype.poichanged = function(){
    this.mode = 'poi';
    //this._init();
}

/*Pano*/
/*CS.Pano = function(dom_id, width, height, 
                startpano_type, startpano, startpano_hlook, startpano_vlook, startpano_fov, 
                get_xml_url, get_static_xml_url){
	var pano_params={};
	this.kr = null;
	this.dom_id = dom_id;
	
	get_xml_url = get_xml_url || '/get_xml/';
	get_static_xml_url = get_static_xml_url || '/get_xml/static/';
	
	
	if (startpano && startpano_type) {
        if (startpano_type == 'street') {
            pano_params['pano'] = get_xml_url + '?id=' + startpano;
        }else if (startpano_type == 'interior'){
            pano_params['pano'] = get_static_xml_url + 'interiors/' + startpano + '.xml';
        }
        
        if (startpano_hlook) {pano_params['view.hlookat']=startpano_hlook;}
        if (startpano_vlook) {pano_params['view.vlookat']=startpano_vlook;}
        if (startpano_fov) {pano_params['view.fov']=startpano_fov;}
	}else{
        pano_params['pano'] = get_xml_url+'?city='+CITY;
    }
	
   console.log(pano_params);
    if (swfobject.hasFlashPlayerVersion("6.0.0")) {
        swfobject.embedSWF('/media/swf/pano.swf', this.dom_id, width, height, '9.0.28', '/media/js/swfobject21/expressInstall.swf', 
		pano_params, {
            allowfullscreen: true,
            bgcolor: '#000000',
            wmode: 'window'
        }, {
            id: this.dom_id,
            name: this.dom_id
        });
        
    }
    else {
        document.getElementById(this.dom_id).innerHTML = '<table width="640" height="480" style="color:black"><tr valign="middle"><td><center>ОШИБКА:<br><br>Требуется Flash Player версии не ниже 9.<br><br><br><a href="http://www.adobe.com/go/getflashplayer/"  target="_blank"><IMG SRC="http://www.macromedia.com/images/shared/download_buttons/get_flash_player.gif" BORDER="1"></a><br>...нажмите для скачивания...<br><br><br><br></center></td></tr></table>';
    }
}

CS.Pano.prototype.visible=function(visible){
    if (visible){
        if ($.browser.msie){
		    $('#pano-wrapper').css('overflow','visible');
		    $('#'+this.dom_id).css('margin-right','0px');
		    $('#'+this.dom_id).css('float','none');
        }else{
		    $('#'+this.dom_id).css('visibility','visible');
        }
    }else{
        if ($.browser.msie){
		    $('#pano-wrapper').css('overflow','hidden');
		    $('#'+this.dom_id).css('margin-right','-10000px');
		    $('#'+this.dom_id).css('float','right');
        }else{
		    $('#'+this.dom_id).css('visibility','hidden');
        }
    }
}

CS.Pano.prototype.setpano=function(id,lookto){
    var url = "?id=" + id;
    if (lookto) {url+="&lookto="+lookto;}

    ui.foldMapWithoutTimeout();
    this.kr.call("loadpano("+url+",null,MERGE,BLEND(1))");
}

CS.Pano.prototype.setpanoBylnglat=function(lnglat){
    $.getJSON(CS.Host+'/static/get_panoid_bylnglat/?callback=?&lnglat='+lnglat+'&city='+CITY, function(id){
        if(id){this.setpano(id,lnglat);}
    }.scope(this));
}

CS.Pano.prototype.setpoi=function(xml){
    ui.foldMapWithoutTimeout();
    this.kr.call("loadpano(/static/" + xml+",null,MERGE,BLEND(1))");
}
CS.Pano.prototype.panochanged = function(id, lng, lat){
    if (!this.kr) {
	    //first run	
		this.kr = $('object#pano')[0];
    }
    ui.replaceWithLink();
    m.center(new CS.LngLat(lng,lat));

	$('div#current-info').html("Панорама была снята "+formatDate(p.kr.get('data[created]').content));
    ui.initViewmode();  
    this.mode='street';
}

CS.Pano.prototype.poichanged = function(){
  if (!this.kr) {
    //first run
    this.kr = $('object#pano')[0];
  }  
  ui.replaceWithLink();

  $('div#current-info').html('');
  m.radarMarker.hide();
  this.mode='interior';
  ui.initViewmode();  
}

CS.Pano.prototype.getPermalink=function(){
    href = window.location.href.split('#')[0];
	if (this.mode == 'street') {
		return href + '#h=' + this.kr.get("view.hlookat") + '&v=' + this.kr.get("view.vlookat") + '&z=' + this.kr.get("view.fov") + '&id=' + this.kr.get("data[pano_id].content");
	}else{
        var ll=m.center().toUrlValue();
		return href + '#h=' + this.kr.get("view.hlookat") + '&v=' + this.kr.get("view.vlookat") + '&z=' + this.kr.get("view.fov") + '&iid=' + this.kr.get("data[pano_name].content")+'&ll='+ll;
	}
}*/

