Index: /extensions/rv_gmaps/branches/2.1/admin/admin.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin.php	(revision 8301)
@@ -0,0 +1,31 @@
+<?php 
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+$template->set_filename('plugin_admin_content', dirname(__FILE__).'/admin.tpl');
+
+if (!isset($_GET['tab']))
+  $page['tab'] = 'config';
+else
+  $page['tab'] = $_GET['tab'];
+
+$my_base_url = get_admin_plugin_menu_link(__FILE__);
+
+$tabsheet = new tabsheet();
+$tabsheet->add( 'config', 'Configuration', add_url_params( $my_base_url, array('tab'=>'config') ) );
+$tabsheet->add( 'edit', 'Edit', add_url_params( $my_base_url, array('tab'=>'edit') ) );
+$tabsheet->add( 'sync', 'Synchronize', add_url_params( $my_base_url, array('tab'=>'sync') ) );
+$tabsheet->select($page['tab']);
+
+$tabsheet->assign();
+
+$my_base_url = $tabsheet->sheets[ $page['tab'] ]['url'];
+$template->set_filename( 'tab_data', dirname(__FILE__).'/admin_'.$page['tab'].'.tpl' );
+include_once( dirname(__FILE__).'/admin_'.$page['tab'].'.php');
+$template->assign_var_from_handle( 'TAB_DATA', 'tab_data');
+$template->assign_var_from_handle( 'ADMIN_CONTENT', 'plugin_admin_content');
+
+if ( empty($conf['gmaps_api_key']) )
+  $page['infos'][] = 'Please define the Google maps api key';
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/admin/admin.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin.tpl	(revision 8301)
@@ -0,0 +1,5 @@
+<div class="titrePage">
+  <h2>RV Maps & Earth {$TABSHEET_TITLE}</h2>
+</div>
+
+{$TAB_DATA}
Index: /extensions/rv_gmaps/branches/2.1/admin/admin_config.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin_config.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin_config.php	(revision 8301)
@@ -0,0 +1,66 @@
+<?php 
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+include_once( dirname(__FILE__).'/../include/functions_map.php' );
+
+if ( isset($_POST['submit']) and !is_adviser() )
+{
+  $query = '
+UPDATE '.CONFIG_TABLE.'
+  SET value="'.$_POST['gmaps_api_key'].'"
+  WHERE param="gmaps_api_key"
+  LIMIT 1';
+  pwg_query($query);
+  list($conf['gmaps_api_key']) = array_from_query('SELECT value FROM '.CONFIG_TABLE.' WHERE param="gmaps_api_key"', 'value');
+
+  $gm_config = rvm_get_config();
+
+  $n  = intval($_POST['nb_markers']);
+  if ($n>0)
+    $gm_config['nb_markers'] = $n;
+  else
+    $page['errors'][] = 'The number of markers must be >0';
+
+  $n  = intval($_POST['nb_images_per_marker']);
+  if ($n>1)
+    $gm_config['nb_images_per_marker'] = $n;
+  else
+    $page['errors'][] = 'The number of iamges per marker must be >1';
+
+  $gm_config['marker_icon'] = $_POST['marker_icon'];
+  mkgetdir( dirname(rvm_get_config_file_name()) );
+  $fp = fopen( rvm_get_config_file_name(), 'w');
+  fwrite( $fp, serialize($gm_config) );
+  fclose($fp);
+}
+
+$query = 'SELECT COUNT(*) FROM '.IMAGES_TABLE.' WHERE lat IS NOT NULL';
+list($nb_geotagged) = mysql_fetch_array( pwg_query($query) );
+
+$template->assign(
+    array(
+      'NB_GEOTAGGED' => $nb_geotagged,
+      'GMAPS_API_KEY' => $conf['gmaps_api_key'],
+      'NB_MARKERS' => rvm_get_config_var('nb_markers',40),
+      'NB_IMAGES_PER_MARKER' => rvm_get_config_var('nb_images_per_marker',20),
+    )
+  );
+
+$path=PHPWG_PLUGINS_PATH.$rvm_dir.'/template/markers/';
+$dir_contents = opendir($path);
+while (($filename = readdir($dir_contents)) !== false)
+{
+  if (!is_file($path.'/'.$filename) or get_extension($filename)!='tpl')
+    continue;
+  $filename = get_filename_wo_extension( $filename );
+  $template->append('marker_icons',
+      array(
+        $filename => str_replace( '_', ' ', $filename),
+      ),
+      true
+    );
+}
+$template->assign('selected_marker_icon', rvm_get_config_var('marker_icon', '') );
+
+closedir($dir_contents);
+?>
Index: /extensions/rv_gmaps/branches/2.1/admin/admin_config.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin_config.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin_config.tpl	(revision 8301)
@@ -0,0 +1,55 @@
+
+You have {$NB_GEOTAGGED} geotagged images.
+
+<form method="post" action="" class="properties">
+<fieldset>
+  <legend>Map configuration</legend>
+  <ul>
+  
+  <li>
+  <label>
+    Google Maps API Key:
+    <input type="text" size="48" name="gmaps_api_key" value="{$GMAPS_API_KEY}" />
+  </label>
+    <br/>Signup for the key here: <a href="http://www.google.com/apis/maps/signup.html" target="_blank">http://www.google.com/apis/maps/signup.html</a>.
+  </li>
+  
+  <br/>
+  
+  <li>
+  <label>
+    Maximum number of markers to show:
+    <input type="text" size="3" name="nb_markers" value="{$NB_MARKERS}" />
+  </label>
+    <br/><small>The images will be "clustered" based on this number and the visible region on the map.</small>
+  </li>
+  
+  <br/>
+  
+  <li>
+  <label>
+    Maximum number of images per marker:
+    <input type="text" size="3" name="nb_images_per_marker" value="{$NB_IMAGES_PER_MARKER}" />
+  </label>
+    <br/><small>When a marker is clicked, the user will be able to navigate images in the info window. This data is sent to the browser once for all the markers. If you have many images, reduce this number in order to reduce traffic and speed up data decoding on the browser side.</small>
+  </li>
+
+  <br/>
+
+  <li>
+  <label>
+    Marker image:
+    <select name="marker_icon">
+      <option value="">Default</option>
+      {html_options options=$marker_icons selected=$selected_marker_icon}
+    </select>
+  </label>
+  </li>
+
+  </ul>
+
+  <p>
+    <input class="submit" type="submit" value="{'Submit'|@translate}" name="submit" {$TAG_INPUT_ENABLED}/>
+  </p>
+</fieldset>
+</form>
Index: /extensions/rv_gmaps/branches/2.1/admin/admin_edit.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin_edit.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin_edit.php	(revision 8301)
@@ -0,0 +1,141 @@
+<?php 
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+$admin_url = PHPWG_ROOT_PATH.'admin.php';
+
+if ( !isset($_GET['cat']) )
+  $_GET['cat'] = 'caddie';
+$_GET['mode'] = 'map';
+include (PHPWG_ROOT_PATH.'admin/element_set.php');
+
+$template->concat('TABSHEET_TITLE', ' '.l10n_dec('%d image', '%d images', count($page['cat_elements_id'])).' - '.$page['title']);
+
+if ( isset($_POST['submit']) and !is_adviser() )
+{
+  $collection = array();
+
+  switch ($_POST['target'])
+  {
+    case 'all' :
+      $collection = $page['cat_elements_id'];
+      break;
+    case 'selection' :
+      if (!isset($_POST['selection']) or count($_POST['selection']) == 0)
+        array_push($page['errors'], l10n('Select at least one picture'));
+      else
+        $collection = $_POST['selection'];
+      break;
+  }
+  if ( count($collection)>0 )
+  {
+    $lat = trim($_POST['lat']);
+    $lon = trim($_POST['lon']);
+
+    if ( strlen($lat)>0 and strlen($lon)>0 )
+    {
+      if ( (double)$lat<=90 and (double)$lat>=-90
+          and (double)$lon<=180 and (double)$lat>=-180 )
+        $update_query = 'lat='.$lat.', lon='.$lon;
+      else
+        $page['errors'][] = 'Invalid lat or lon value';
+    }
+    elseif ( strlen($lat)==0 and strlen($lon)==0 )
+      $update_query = 'lat=NULL, lon=NULL';
+    else
+      $page['errors'][] = 'Both lat/lon must be empty or not empty';
+
+    if (isset($update_query))
+    {
+      $update_query = '
+UPDATE '.IMAGES_TABLE.' SET '.$update_query.'
+  WHERE id IN ('.implode(',',$collection).')';
+      pwg_query($update_query);
+      rvm_invalidate_cache();
+    }
+  }
+}
+
+
+$template->append(
+  'specials',
+  array(
+		$admin_url.get_query_string_diff(array('start','cat')).'&amp;cat=caddie' => l10n('Caddie')
+    ),
+	true
+  );
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+;';
+$result = pwg_query($query);
+$categories = array();
+$selecteds = array();
+if (!empty($result))
+{
+  while ($row = mysql_fetch_assoc($result))
+  {
+    $url = $admin_url.get_query_string_diff(array('start','cat')).'&amp;cat='.$row['id'];
+    if ( $row['id']==$_GET['cat'] ) $selecteds[] = $url;
+    $row['id']=$url;
+    array_push($categories, $row);
+  }
+}
+usort($categories, 'global_rank_compare');
+display_select_categories($categories, $selecteds, 'categories', false);
+
+if (!empty($_GET['display']))
+{
+  if ('all' == $_GET['display'])
+    $page['nb_images'] = count($page['cat_elements_id']);
+  else
+    $page['nb_images'] = intval($_GET['display']);
+}
+else
+  $page['nb_images'] = 20;
+
+if ( !empty($page['cat_elements_id']) )
+{
+  $nav_bar = create_navigation_bar(
+    $admin_url.get_query_string_diff(array('start')),
+    count($page['cat_elements_id']),
+    $page['start'],
+    $page['nb_images']
+    );
+  $template->assign('navbar', $nav_bar);
+}
+
+$images=array();
+if ( !empty($page['cat_elements_id']) )
+{
+  $query='
+SELECT id,tn_ext,name,path,file,lat,lon FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',',$page['cat_elements_id']).')
+  '.$conf['order_by'].'
+  LIMIT '.$page['start'].', '.$page['nb_images'].'
+;';
+  $result = pwg_query($query);
+  while ( $row=mysql_fetch_assoc($result) )
+    $images[] = $row;
+}
+
+foreach ($images as $image)
+{
+	$tpl_var = array_merge( $image,
+      array(
+        'U_TN' => get_thumbnail_url($image),
+        'TITLE' => get_thumbnail_title($image)
+      )
+    );
+  if ( isset($image['lat']) )
+    $tpl_var['U_MAP'] = rvm_make_map_picture_url( array('image_id'=>$image['id'], 'image_file'=>$image['file']) );
+	$template->append('thumbnails', $tpl_var);
+}
+
+$template->assign(
+    array(
+      'U_DISPLAY'=> $admin_url.get_query_string_diff(array('display'))
+    ) 
+  );
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/admin/admin_edit.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin_edit.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin_edit.tpl	(revision 8301)
@@ -0,0 +1,74 @@
+
+<form>
+Set:
+<select onchange="document.location = this.options[this.selectedIndex].value;">
+  <optgroup label="Specials">
+    {html_options options=$specials}
+  </optgroup>
+  <optgroup label="{'Categories'|@translate}">
+  	{html_options options=$categories selected=$categories_selected}
+  </optgroup>
+  <!-- <optgroup label="{'Tags'|@translate}"></optgroup> -->
+</select>
+</form>
+
+<fieldset>
+  <legend>{'Display options'|@translate}</legend>
+  <p>{'elements per page'|@translate}:
+      <a href="{$U_DISPLAY}&amp;display=20">20</a>
+    | <a href="{$U_DISPLAY}&amp;display=50">50</a>
+    | <a href="{$U_DISPLAY}&amp;display=100">100</a>
+    | <a href="{$U_DISPLAY}&amp;display=all">{'all'|@translate}</a>
+  </p>
+</fieldset>
+
+<form action="" method="post">
+
+<fieldset>
+	<legend>{'Elements'|@translate}</legend>
+
+	{if !empty($navbar) }{include file='navigation_bar.tpl'}{/if}
+  {if not empty($thumbnails)}
+	<ul class="thumbnails">
+		{foreach from=$thumbnails item=thumbnail}
+		<li><span class="wrap1">
+			<label>
+				<span class="wrap2"><span>
+					<img src="{$thumbnail.U_TN}" alt="{$thumbnail.file}" title="{$thumbnail.TITLE}" class="thumbnail" />
+				</span></span>
+				<input type="checkbox" name="selection[]" value="{$thumbnail.id}" />
+			</label>
+
+			<span class="thumbLegend">
+			{if isset($thumbnail.U_MAP)}
+			<a href="{$thumbnail.U_MAP}" target="_blank">{$thumbnail.lat},{$thumbnail.lon}</a>
+			{/if}
+			</span>
+
+			</span>
+		</li>
+		{/foreach}
+	</ul>
+	{/if}
+</fieldset>
+
+
+<fieldset>
+  <legend>{'Form'|@translate}</legend>
+
+  <label>Latitude (-90=S to 90=N)
+    <input type="text" size="8" name="lat" />
+  </label>
+  <label>Longitude (-180=E to 180=W)
+    <input type="text" size="9" name="lon" />
+  </label>
+  <p>
+    {'target'|@translate}
+    <label><input type="radio" name="target" value="all" /> {'all'|@translate}</label>
+    <label><input type="radio" name="target" value="selection" checked="checked" /> {'selection'|@translate}</label>
+  </p>
+
+  <p><input class="submit" type="submit" value="{'Submit'|@translate}" name="submit" {$TAG_INPUT_ENABLED}/></p>
+</fieldset>
+
+</form>
Index: /extensions/rv_gmaps/branches/2.1/admin/admin_sync.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin_sync.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin_sync.php	(revision 8301)
@@ -0,0 +1,147 @@
+<?php
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+function parse_fract( $f )
+{
+  $nd = explode( '/', $f );
+  return $nd[0]/$nd[1];
+}
+
+function parse_lat_lon( $arr )
+{
+  $v=0;
+  $v += parse_fract( $arr[0] );
+  $v += parse_fract( $arr[1] )/60;
+  $v += parse_fract( $arr[2] )/3600;
+  return $v;
+}
+
+if ( isset($_POST['submit']) )
+  $sync_options = array(
+    'simulate' => is_adviser() ? true : isset($_POST['simulate']),
+		'use_high' => isset($_POST['use_high']),
+    'cat_id' => isset($_POST['cat_id']) ? (int)$_POST['cat_id'] : 0,
+    'subcats_included' => isset($_POST['subcats_included']),
+    );
+else
+  $sync_options = array(
+    'simulate' => true,
+		'use_high' => true,
+    'cat_id' => 0,
+    'subcats_included' => true,
+    );
+
+
+if ( isset($_POST['submit']) )
+{
+	include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
+
+  $where_clauses = array();
+  if ( $sync_options['cat_id']!=0 )
+  {
+    $query='
+SELECT id FROM '.CATEGORIES_TABLE.'
+  WHERE ';
+    if ( $sync_options['subcats_included'])
+      $query .= 'uppercats REGEXP \'(^|,)'.$sync_options['cat_id'].'(,|$)\'';
+    else
+      $query .= 'id='.$sync_options['cat_id'];
+    $cat_ids = array_from_query($query, 'id');
+
+    $query='
+SELECT id,path,lat,lon,has_high
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=image_id
+  WHERE category_id IN ('.implode(',', $cat_ids).')
+  GROUP BY id';
+  }
+  else
+  {
+    $query='
+SELECT id,path,lat,lon,has_high
+  FROM '.IMAGES_TABLE;
+  }
+
+  $images = hash_from_query( $query, 'id');
+  $datas = array();
+  $errors = array();
+  foreach ($images as $image)
+  {
+		$filename = $image['path'];
+		if ($sync_options['use_high'] and $image['has_high']=='true')
+			$filename = get_high_path($image);
+		$exif = @read_exif_data( $filename );
+		if ( empty($exif) )
+			continue;
+		$exif = array_intersect_key( $exif, array_flip( array('GPSLatitudeRef', 'GPSLatitude', 'GPSLongitudeRef', 'GPSLongitude') ) );
+		if ( count($exif)!=4 )
+			continue;
+		if ( !in_array($exif['GPSLatitudeRef'], array('S', 'N') ) )
+		{
+			$errors[] = $filename. ': GPSLatitudeRef not S or N';
+			continue;
+		}
+		if ( !in_array($exif['GPSLongitudeRef'], array('W', 'E') ) )
+		{
+			$errors[] = $filename. ': GPSLongitudeRef not W or E';
+			continue;
+		}
+		if (!is_array($exif['GPSLatitude']) or !is_array($exif['GPSLongitude']) )
+		{
+			$errors[] = $filename. ': GPSLatitude and GPSLongitude are not arrays';
+			continue;
+		}
+		$lat = parse_lat_lon( $exif['GPSLatitude'] );
+		if ( $exif['GPSLatitudeRef']=='S' )
+			$lat = -$lat;
+		$lon = parse_lat_lon( $exif['GPSLongitude'] );
+		if ( $exif['GPSLongitudeRef']=='W' )
+			$lon = -$lon;
+		$datas[] = array (
+			'id' => $image['id'],
+			'lat' => $lat,
+			'lon' => $lon,
+			);
+  }
+  $template->assign( 'sync_errors', $errors );
+
+  if ( count($datas)>0 and !$sync_options['simulate'] )
+  {
+    mass_updates(
+        IMAGES_TABLE,
+        array(
+          'primary' => array('id'),
+          'update'  => array('lat', 'lon')
+        ),
+        $datas
+      );
+    rvm_invalidate_cache();
+  }
+
+  $template->assign(
+    'metadata_result',
+    array(
+      'NB_ELEMENTS_DONE' => count($datas),
+      'NB_ELEMENTS_CANDIDATES' => count($images),
+      'NB_ERRORS' => count($errors),
+      ));
+
+}
+
+
+$query = '
+SELECT id,
+  CONCAT(name, IF(dir IS NULL, " (V)", "") ) AS name,
+  uppercats, global_rank
+  FROM '.CATEGORIES_TABLE;
+display_select_cat_wrapper($query,
+                           array( $sync_options['cat_id'] ),
+                           'categories',
+                           false);
+$template->assign(
+    array(
+      'SUBCATS_INCLUDED_CHECKED' => $sync_options['subcats_included'] ? 'checked="checked"' : '',
+			'USE_HIGH_CHECKED' => $sync_options['use_high'] ? 'checked="checked"' : ''
+    )
+  );
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/admin/admin_sync.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/admin/admin_sync.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/admin/admin_sync.tpl	(revision 8301)
@@ -0,0 +1,49 @@
+<p>Synchronization of EXIF gps metadata information with the database.</p>
+
+{if isset($metadata_result)}
+<h3>{'Metadata synchronization results'|@translate}</h3>
+<ul>
+	<li>{$metadata_result.NB_ELEMENTS_DONE} {'elements updated in the database'|@translate}</li>
+	<li>{$metadata_result.NB_ELEMENTS_CANDIDATES} {'images candidates for metadata synchronization'|@translate}</li>
+	<li>{$metadata_result.NB_ERRORS} {'errors during synchronization'|@translate}</li>
+</ul>
+{/if}
+
+{if not empty($sync_errors)}
+<h3>{'Error list'|@translate}</h3>
+<div class="errors">
+<ul>
+  {foreach from=$sync_error item=error}
+	<li>{$error}</li>
+	{/foreach}
+</ul>
+</div>
+{/if}
+
+<form action="" method="post" id="update">
+
+  <fieldset id="syncOptions">
+    <legend>synchronization options</legend>
+    <ul>
+      <li><label><input type="checkbox" name="simulate" value="1" checked="checked" {$TAG_INPUT_ENABLED} /> {'only perform a simulation (no change in database will be made)'|@translate}</label></li>
+			<li><label><input type="checkbox" name="use_high" value="1" {$USE_HIGH_CHECKED} /> use high resolution images if available</label></li>
+    </ul>
+  </fieldset>
+
+  <fieldset id="catSubset">
+    <legend>{'reduce to single existing categories'|@translate}</legend>
+    <ul>
+    <li>
+    <select class="categoryList" name="cat_id" size="10">
+    	{html_options options=$categories selected=$categories_selected}
+    </select>
+    </li>
+
+    <li><label><input type="checkbox" name="subcats_included" value="1" {$SUBCATS_INCLUDED_CHECKED} /> {'Search in subcategories'|@translate}</label></li>
+    </ul>
+  </fieldset>
+
+  <p>
+    <input class="submit" type="submit" value="{'Submit'|@translate}" name="submit" />
+  </p>
+</form>
Index: /extensions/rv_gmaps/branches/2.1/changelog.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/changelog.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/changelog.txt	(revision 8301)
@@ -0,0 +1,84 @@
+2.1.c
+- do not use prototype anymore (replaced by jQuery + jQuery nyromodal)
+
+2.1.b
+- allow gps exif metadata synchronisation with high resolution images
+- fixed admin navigation bar
+- compatible with extended description
+- upgrade prototype
+- language updates
+
+2.1.a
+- compatibility with piwigo 2.1
+- rolled back dirty fix in previos version (google corrected the issue)
+	
+2.0.d
+  - hungarian translation thanks to external contributors
+  - the map uses now the 3D Large map control as on google maps website
+  - dirty fix for bug inroduced in api version 2.185 (and up to 2.193 as of now online) - http://code.google.com/p/gmaps-api-issues/issues/detail?id=2009&q=apitype%3AJavascript&colspec=ID%20Type%20Status%20Introduced%20Fixed%20Summary%20Internal%20Stars
+
+2.0.c
+  - google maps api is loaded using the same language as piwigo
+  - polish and italian languages thanks to external contributors
+
+2.0.b
+  - remove some unused/unnecessary php code
+  - added Czech translation (thanks to Pavel B.)
+  - improve compatibility of exif gps synchronisation for images uploaded by pLoader
+
+2.0.a
+  - new PWG version compatible
+  - fix issue on the map page when left side longitude > right side longitude
+  
+1.7.h
+  - fix issue when zlib.output_compression was set in php.ini
+  - update prototype javascript to version 1.6.0.2
+  - better navigation in map list (categories & tags)
+  - compatible with pwg 1.7.2 (issue on searches with previous version)
+
+1.7.g
+  - bug - map on recent pictures had a mysql error
+  - bug - Google api ~ v2.93 the overview map (bottom right side) has changed behavior resulting in an exception
+  - added new physical map type
+  - replaced the old map type control with the new hierarchical type
+
+1.7.f
+  - localhost do not require a google api key
+  - updated calls to new version of google maps apis
+  - improved click/double click behaviour on markers
+  - update prototype javascript to version 1.5.1.1
+  - fixed small bug in javascript when recycling markers (current thumbnail index reset now)
+  
+1.7.e
+  - include french language (thanks dmaille)
+  - the marker title was not correctly set when marker recycled (used undocumented code that changed with api version); now we still use undocumented features but we "discover" the right function names at runtime
+  - output map data using the zip compression (if available)
+  - removed a sleep in the code that was used for debugging
+  
+1.7.d
+  - added some rel nofollow and meta robots noindex,nofollow
+  - attempt to remove a php warning from the admin config page on some ISPs
+
+1.7.c
+  - the map page opened from the picture page is not on google anymore
+  - the picture map page has a link "More pictures near this location"
+  - allow custom markers instead of the default one
+  - on startup, the map page is automatically centered and zoomed to the images (all cases except when viewing the entire gallery or when an url generated by Link to this page is used)
+  - improved link to this page for different map types
+  - security: checks for guests for galleries that do not allow visits as guest
+  - security: checks for adivser administrators
+  - javascript improvements to avoid memory leaks in IE
+
+1.7.b
+ - added an input to search for an address/city/country on the map page
+ - double click on a marker zooms to that location
+ - the info window automatically shows a vertical scroll bar if required
+ - performance: ability to limit the number of images shown in the info window per marker
+ - performance: do not destroy/create the markers in the browser, but reuse existing ones
+ - bug fix and improvement of the clustering algorithm
+ - added .kml extension to the file name when opening the kml file
+ - fix: kml from map page is always in flat mode (categories not structured)
+ - fix: kml from map page takes into account the current map viewport
+
+1.7.a
+ - initial release
Index: /extensions/rv_gmaps/branches/2.1/include/cluster_maker.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/include/cluster_maker.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/include/cluster_maker.php	(revision 8301)
@@ -0,0 +1,185 @@
+<?php
+
+function cluster_area_compare( &$a, &$b )
+{
+	$aa = bounds_lat_range($a['bounds']) * bounds_lon_range($a['bounds']);
+	$ab = bounds_lat_range($b['bounds']) * bounds_lon_range($b['bounds']);
+	return -$aa+$ab; // biggest first
+}
+
+class ClusterMaker
+{
+	private $_image_map;
+	private $_image_ranks;
+
+	var $bounds;
+	var $debug_str;
+
+	function make_clusters($images, $maxLatPrecision, $maxLonPrecision, $maxNbMarkers)
+	{
+		$this->_image_map = $images;
+		$this->_image_ranks = array();
+		$this->debug_str = '';
+
+		$start = get_moment();
+		$total_iterations = 0;
+		$total_generations = 0;
+
+		$this->bounds = array();
+		foreach($images as $img)
+			$this->bounds = bounds_add($this->bounds, $img['lat'], $img['lon'] );
+
+		$pending_split = array(
+				array(
+					'bounds' => $this->bounds,
+					'items' => array_keys( $this->_image_map ),
+				)
+			);
+		$result = array();
+
+		while ( count($pending_split) )
+		{
+			$total_generations++;
+			$next_level_to_split = array();
+			while ( count($pending_split) )
+			{
+				$current = array_shift( $pending_split );
+				$splitted = $this->_split_cluster($current, $maxLatPrecision, $maxLonPrecision );
+				if ( count($splitted)>1 )
+				{
+					/*echo('splitted: ' . var_export($current['bounds'],true). ' in '. count($splitted)."\n" );
+					foreach( $splitted as $k => $split )
+						echo("sub $k: " . var_export($split['bounds'],true)."\n" );*/
+					$total_iterations += count($current['items']);
+					$next_level_to_split = array_merge($next_level_to_split, $splitted );
+					if ( count($result)+count($pending_split)+count($next_level_to_split) >= $maxNbMarkers )
+					{
+						$result = array_merge($result, $pending_split, $next_level_to_split );
+						$pending_split = $next_level_to_split = array();
+						break;
+					}
+				}
+				else
+					array_push( $result, $current );
+			}
+			$pending_split = $next_level_to_split;
+			usort( $pending_split, 'cluster_area_compare' );
+		}
+		$merged = $this->_try_merge_clusters( $result, $maxLatPrecision, $maxLonPrecision );
+		$this->debug_str = get_elapsed_time($start, get_moment()) .' gen:'.$total_generations.' alg:'.count($this->_image_map).'+'.$total_iterations;
+		if ($merged)
+			$this->debug_str .= " merged:$merged";
+		$this->_image_map = null;
+		return $result;
+	}
+
+	function _try_merge_clusters(&$clusters, $maxLatPrecision, $maxLonPrecision)
+	{
+		$ret = 0;
+		for ($i=0; $i<count($clusters)-1; $i++)
+		{
+			$ci = bounds_center( $clusters[$i]['bounds'] );
+			for ($j=$i+1; $j<count($clusters); $j++)
+			{
+				$cj = bounds_center( $clusters[$j]['bounds'] );
+				if ( abs($ci['lat']-$cj['lat']) < $maxLatPrecision/2
+					and abs($ci['lon']-$cj['lon']) < $maxLonPrecision/2 )
+				{
+					//print_r( "i=$i; j=$j \n"); var_export( $clusters[$i]['bounds'] ); var_export( $clusters[$j]['bounds'] );
+					$clusters[$i]['items'] = array_merge( $clusters[$i]['items'], $clusters[$j]['items'] );
+					if ( empty($this->_image_ranks) )
+						$this->_image_ranks = array_flip( array_keys($this->_image_map) );
+					usort( $clusters[$i]['items'], array($this, '_image_rank_compare') );
+					$clusters[$i]['bounds'] = bounds_union($clusters[$i]['bounds'], $clusters[$j]['bounds'] );
+					array_splice( $clusters, $j, 1);
+					$j--;
+					$ci = bounds_center( $clusters[$i]['bounds'] );
+					$ret++;
+				}
+			}
+		}
+		return $ret;
+	}
+
+	function _image_rank_compare($a, $b)
+	{
+		return $this->_image_ranks[$a] - $this->_image_ranks[$b];
+	}
+
+	function _split_cluster($cluster, $maxLatPrecision, $maxLonPrecision)
+	{
+		$latRange = bounds_lat_range($cluster['bounds']);
+		$lonRange = bounds_lon_range($cluster['bounds']);
+
+		$lat_nb_tiles = max( 1, $latRange/$maxLatPrecision );
+		$lon_nb_tiles = max( 1, $lonRange/$maxLonPrecision );
+		//echo('lat_nb '.$lat_nb_tiles.' lon_nb '.$lon_nb_tiles."\n");
+		if ($lat_nb_tiles<2 and $lon_nb_tiles<2)
+			return array();
+
+		$ll_tile_factor = $lat_nb_tiles/$lon_nb_tiles;
+
+		if ($ll_tile_factor > 3)
+		{ // 1x3
+			$lat_step = $latRange/3;
+			$lon_step = $lonRange;
+		}
+		elseif ($ll_tile_factor < 1/3)
+		{ // 3x1
+			$lat_step = $latRange;
+			$lon_step = $lonRange/3;
+		}
+		elseif ($ll_tile_factor > 2)
+		{ // 2x3
+			$lat_step = max( $latRange/3, $maxLatPrecision );
+			$lon_step = max( $lonRange/2, $maxLonPrecision );
+		}
+		elseif ($ll_tile_factor < 1/2)
+		{ // 3x2
+			$lat_step = max( $latRange/2, $maxLatPrecision );
+			$lon_step = max( $lonRange/3, $maxLonPrecision );
+		}
+		else
+		{ // 3x3
+			$lat_step = max( $latRange/3, $maxLatPrecision );
+			$lon_step = max( $lonRange/3, $maxLonPrecision );
+		}
+
+		if ( $cluster['bounds']['count'] > 200 )
+		{
+			if ($lat_step>4*$maxLatPrecision) $lat_step = $lat_step/2;
+			if ($lon_step>4*$maxLonPrecision) $lon_step = $lon_step/2;
+		}
+
+		$lat_step += 1e-7;
+		$lon_step += 1e-7;
+		//echo ( "$lat_step $latRange x $lon_step $lonRange tiles $lat_nb_tiles x $lon_nb_tiles\n" );
+
+		$lon_nb_tiles = ceil( $lonRange / $lon_step );
+
+		$clusters = array();
+		foreach ( $cluster['items'] as $id )
+		{
+			$lon = $this->_image_map[$id]['lon'];
+			$lat = $this->_image_map[$id]['lat'];
+
+			$idx_lon = floor ( ( $lon - $cluster['bounds']['w'] ) / $lon_step );
+			$idx_lat = floor ( ( $lat - $cluster['bounds']['s'] ) / $lat_step );
+
+			$idx = $lon_nb_tiles * $idx_lat + $idx_lon;
+
+			if ( !isset($clusters[$idx]) )
+			{
+				$clusters[$idx] = array(
+					'bounds'  => array(),
+					'items'   => array(),
+					);
+			}
+			array_push( $clusters[$idx]['items'], $id );
+			$clusters[$idx]['bounds'] = bounds_add( $clusters[$idx]['bounds'] , $lat, $lon );
+		}
+		return $clusters;
+	}
+}
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/include/functions.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/include/functions.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/include/functions.php	(revision 8301)
@@ -0,0 +1,106 @@
+<?php
+
+function rvm_get_cache_file_name()
+{
+	global $conf;
+	$dir = $conf['local_data_dir'];
+	return $dir.'/tmp/_rvgm_cat_cache.dat';
+}
+
+function rvm_invalidate_cache()
+{
+	@unlink(  rvm_get_cache_file_name() );
+}
+
+function rvm_load_language()
+{
+	global $lang,$lang_info,$conf;
+	if ( isset($lang['Map']) or ($lang_info['code']=='en' and !$conf['debug_l10n']) )
+		return;
+	load_language('lang', dirname(__FILE__).'/../');
+}
+
+function rvm_items_have_latlon($items)
+{
+  $query = '
+SELECT id FROM '.IMAGES_TABLE.'
+WHERE lat IS NOT NULL
+  AND id IN ('.implode(',', $items).')
+ORDER BY NULL
+LIMIT 0,1';
+	if ( mysql_num_rows(pwg_query($query))> 0)
+		return true;
+	return false;
+}
+
+function rvm_make_map_picture_url($params)
+{
+	global $conf;
+	if ( empty($conf['gmaps_api_key']) and $_SERVER['SERVER_ADDR']!='127.0.0.1' )
+		return "";
+	$map_url = make_picture_url($params);
+	return add_url_params($map_url, array('map'=>null) );
+}
+
+function rvm_duplicate_map_picture_url()
+{
+	global $conf;
+	if ( empty($conf['gmaps_api_key']) and $_SERVER['SERVER_ADDR']!='127.0.0.1' )
+		return "";
+	$map_url = duplicate_picture_url();
+	return add_url_params($map_url, array('map'=>null) );
+}
+
+function rvm_make_map_index_url($params=array())
+{
+	global $conf, $rvm_dir;
+	if ( empty($conf['gmaps_api_key']) and $_SERVER['SERVER_ADDR']!='127.0.0.1' )
+		return "";
+	$url = get_root_url().'map';
+	if ($conf['php_extension_in_urls'])
+		$url .= '.php';
+	if ($conf['question_mark_in_urls'])
+		$url .= '?';
+	$url .= make_section_in_url($params);
+	$url = add_well_known_params_in_url($url, array_intersect_key($params, array('flat'=>1) ) );
+	return $url;
+}
+
+function rvm_duplicate_map_index_url($redefined=array(), $removed=array())
+{
+	return rvm_make_map_index_url(
+		params_for_duplication($redefined, $removed)
+		);
+}
+
+function rvm_duplicate_kml_index_url($redefined=array(), $removed=array())
+{
+	return rvm_make_kml_index_url(
+		params_for_duplication($redefined, $removed)
+		);
+}
+
+function rvm_make_kml_index_url($params)
+{
+	global $conf, $rvm_dir;
+	$url = get_root_url().'plugins/'.$rvm_dir.'/kml.php';
+	if ($conf['question_mark_in_urls'])
+		$url .= '?';
+
+	$url .= make_section_in_url($params);
+	unset( $params['start'] );
+	if ( 'categories'!=$params['section']) unset( $params['flat'] );
+	$url = add_well_known_params_in_url($url, $params);
+	$get_params = array();
+	if ( isset($params['box']) and !empty($params['box']) )
+	{
+		include_once( dirname(__FILE__).'/functions_map.php' );
+		if ( ! bounds_is_world($params['box']) )
+			$get_params['box'] = bounds_to_url($params['box']);
+	}
+	if ( isset($params['ll']) and !empty($params['ll']) )
+		$get_params['ll'] = $params['ll']['lat'].','.$params['ll']['lon'];
+	$url = add_url_params($url, $get_params );
+	return $url;
+}
+?>
Index: /extensions/rv_gmaps/branches/2.1/include/functions_map.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/include/functions_map.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/include/functions_map.php	(revision 8301)
@@ -0,0 +1,566 @@
+<?php
+/* Reminder about urls
+map      unused but passes flat to map_data ...
+map_data automatic show flat, start is unused
+mapl     automatic show flat, start is used in GET only (blowup)
+kml      if flat network links, start is unused*/
+
+function rvm_get_config_file_name()
+{
+  global $page, $conf;
+  unset( $page['__rvm_config__'] );
+  return $conf['local_data_dir'].'/plugins/'.basename(dirname(dirname(__FILE__))).'.dat';
+}
+
+function rvm_get_config()
+{
+  global $page;
+  if (isset($page['__rvm_config__']))
+    return $page['__rvm_config__'];
+  $x = @file_get_contents( rvm_get_config_file_name() );
+  if ($x!==false)
+    $page['__rvm_config__'] = unserialize($x);
+  if ( !is_array(@$page['__rvm_config__']) )
+    $page['__rvm_config__'] = array();
+  return $page['__rvm_config__'];
+}
+
+function rvm_get_config_var($var, $default)
+{
+  global $page;
+  if (!isset($page['__rvm_config__']))
+    rvm_get_config();
+  if ( array_key_exists($var,$page['__rvm_config__']) )
+    return $page['__rvm_config__'][$var];
+  return $default;
+}
+
+function rvm_parse_map_data_url($tokens, &$next_token)
+{
+  $page=array();
+
+  $page = array_merge($page, parse_section_url($tokens, $next_token) );
+  if ( !isset($page['section']) )
+    $page['section'] = 'categories';
+
+  $page = array_merge( $page, parse_well_known_params_url( $tokens, $next_token) );
+  $page['start']=0;
+  $page['box'] = rvm_bounds_from_url( @$_GET['box'] );
+  return $page;
+}
+
+function rvm_parse_kml_url($tokens, &$next_token)
+{
+  $page=array();
+
+  $page = array_merge($page, parse_section_url($tokens, $next_token) );
+  if ( !isset($page['section']) )
+    $page['section'] = 'categories';
+
+  $page = array_merge( $page, parse_well_known_params_url( $tokens, $next_token) );
+  $page['start']=0;
+  $page['box'] = rvm_bounds_from_url( @$_GET['box'] );
+  if ( isset($_GET['ll']) )
+    $page['ll'] = rvm_ll_from_url( $_GET['ll'] );
+  return $page;
+}
+
+function rvm_duplicate_blowup_url($redefined=array(), $removed=array())
+{
+  return rvm_make_blowup_url(
+    params_for_duplication($redefined, $removed)
+    );
+}
+
+function rvm_make_blowup_url($params)
+{
+  global $conf, $rvm_dir;
+  if ( file_exists(PHPWG_ROOT_PATH.'mapl.php') )
+    $url = get_root_url().'mapl';
+  else
+    $url = get_root_url().'plugins/'.$rvm_dir.'/mapl';
+  if ($conf['php_extension_in_urls'])
+    $url .= '.php';
+  if ($conf['question_mark_in_urls'])
+    $url .= '?';
+  $url .= make_section_in_url($params);
+  $url = add_well_known_params_in_url($url, array_intersect_key($params, array('flat'=>1) ) );
+
+  $get_params = array();
+  if ( isset($params['box']) and !empty($params['box']) and !bounds_is_world($params['box']) )
+    $get_params['box'] = bounds_to_url($params['box']);
+  elseif ( isset($params['ll']) and !empty($params['ll']) )
+    $get_params['ll'] = $params['ll']['lat'].','.$params['ll']['lon'];
+  if ( isset($params['start']) and $params['start']>0 )
+    $get_params['start'] = $params['start'];
+  $url = add_url_params($url, $get_params );
+  return $url;
+}
+
+function rvm_parse_blowup_url($tokens, &$next_token)
+{
+  $page=array();
+  $page = array_merge($page, parse_section_url($tokens, $next_token) );
+  if ( !isset($page['section']) )
+    $page['section'] = 'categories';
+  $page = array_merge( $page, parse_well_known_params_url( $tokens, $next_token) );
+  $page['start']=0;
+  if ( isset($_GET['start']) )
+    $page['start']=$_GET['start'];
+  $page['box'] = rvm_bounds_from_url( @$_GET['box'] );
+  if ( isset($_GET['ll']) )
+    $page['ll'] = rvm_ll_from_url( $_GET['ll'] );
+  return $page;
+}
+
+function rvm_bounds_from_url($str)
+{
+  if ( !isset($str) or strlen($str)==0 )
+    return null;
+  $r = explode(',', $str );
+  if ( count($r) != 4)
+    bad_request( $str.' is not a valid geographical bound' );
+  $b = array(
+      's' => $r[0],
+      'w' => $r[1],
+      'n' => $r[2],
+      'e' => $r[3],
+    );
+  return $b;
+}
+
+function rvm_bounds_to_sql( $b )
+{
+  if ( !isset($b) or empty($b) )
+    return null;
+  $sql_where = 'i.lat BETWEEN '.$b['s'].' AND '.($b['n']);
+  $sql_where .= ' AND ';
+  if ($b['e'] >= $b['w'])
+    $sql_where .= 'i.lon BETWEEN '.$b['w'].' AND '.($b['e']);
+  else
+    $sql_where .= 'i.lon NOT BETWEEN '.($b['e']+1e-7).' AND '.($b['w']-1e-7);
+  return $sql_where;
+}
+
+function bounds_to_url($b, $p = 6 )
+{
+  if ( empty($b) )
+    return '';
+  return round($b['s'],$p).','.round($b['w'],$p).','.round($b['n'],$p).','.round($b['e'],$p);
+}
+
+function rvm_ll_from_url($str)
+{
+  if ( !isset($str) or strlen($str)==0 )
+    return null;
+  $r = explode(',', $str );
+  if ( count($r) != 2)
+    bad_request( $str.' is not a valid geographical position' );
+  $b = array('lat'=>$r[0],'lon'=>$r[1]);
+  return $b;
+}
+
+function rvm_ll_to_sql( $ll, &$order_by )
+{
+  $cos_lat = max( 1e-2, cos($ll['lat']*M_PI/180) );
+  $dlat = 3; // 1 degree is approx between 111 and 116 km
+  $dlon = min( 3/$cos_lat, 180 );
+  $bounds = array(
+      's' => $ll['lat'] - $dlat,
+      'w' => $ll['lon'] - $dlon,
+      'n' => $ll['lat'] + $dlat,
+      'e' => $ll['lon'] + $dlon,
+    );
+  if ($bounds['s']<-90) $bounds['s']=-90;
+  if ($bounds['w']<-180) $bounds['w']+=360;
+  if ($bounds['n']>90) $bounds['n']=90;
+  if ($bounds['e']>180) $bounds['e']-=360;
+  $where_sql = rvm_bounds_to_sql( $bounds );
+  $order_by = 'ORDER BY POW('.$ll['lat'].'-i.lat,2)+POW('.$cos_lat.'*('.$ll['lon'].'-i.lon),2)';
+  return $where_sql;
+}
+
+
+function bounds_is_world( $b )
+{
+  if (empty($b)) return false;
+  return $b['n']>=90 and $b['s']<=-90 and $b['w']<=-180 and $b['e']>=180;
+}
+
+function bounds_add($bounds, $lat, $lon)
+{
+  if ( empty($bounds) )
+  {
+    $bounds = array(
+      's' => $lat,
+      'n' => $lat,
+      'w' => $lon,
+      'e' => $lon,
+      'count' => 1
+      );
+  }
+  else
+  {
+    if ( $lat>$bounds['n'] )
+      $bounds['n']=$lat;
+    elseif ( $lat<$bounds['s'] )
+      $bounds['s']=$lat;
+    if ( $lon>$bounds['e'] )
+      $bounds['e']=$lon;
+    elseif ( $lon<$bounds['w'] )
+      $bounds['w']=$lon;
+    $bounds['count']=$bounds['count']+1;
+  }
+
+  return $bounds;
+}
+
+function bounds_union($b1, $b2)
+{
+  $total_count = $b1['count'] + $b2['count'];
+  $res =
+    array_merge(
+      $b1,
+      array(
+        's' => min( $b1['s'], $b2['s'] ),
+        'n' => max( $b1['n'], $b2['n'] ),
+        'w' => min( $b1['w'], $b2['w'] ),
+        'e' => max( $b1['e'], $b2['e'] ),
+        'count' => $total_count,
+      )
+    );
+  if ( isset($b2['min_date']) )
+    $res = array_merge(
+      $res,
+      array(
+        'min_date' => min( $b1['min_date'], $b2['max_date'] ),
+        'max_date' => max( $b1['max_date'], $b2['max_date'] ),
+      )
+    );
+  return $res;
+}
+
+function bounds_center($b)
+{
+  if (empty($b))
+    return array();
+  return array(
+    'lat' => ($b['s']+$b['n'])/2,
+    'lon' => ($b['w']+$b['e'])/2,
+    );
+}
+
+function bounds_sw($b)
+{
+  if (empty($b))
+    return array();
+  return array(
+    'lat' => $b['s'],
+    'lon' => $b['w'],
+    );
+}
+
+function bounds_ne($b)
+{
+  if (empty($b))
+    return array();
+  return array(
+    'lat' => $b['n'],
+    'lon' => $b['e'],
+    );
+}
+
+
+function bounds_lat_range($b)
+{
+  if (empty($b))
+    return 0;
+  return $b['n'] - $b['s'];
+}
+
+function bounds_lon_range($b)
+{
+  if (empty($b))
+    return 0;
+  return $b['e'] - $b['w'];
+}
+
+
+function rvm_get_cat_bounds()
+{
+  $cache_file_name = rvm_get_cache_file_name();
+  if ( file_exists($cache_file_name) )
+  {
+    return unserialize( file_get_contents($cache_file_name) );
+  }
+  $forbidden = get_sql_condition_FandF(
+        array
+          (
+            'forbidden_categories' => 'category_id',
+            'visible_categories' => 'category_id',
+            'visible_images' => 'i.id'
+          ),
+        'AND'
+    );
+
+  $query = '
+SELECT category_id cat_id, uppercats, MAX(lat) AS n, MIN(lat) AS s, MAX(lon) AS e, MIN(lon) AS w, COUNT(i.id) count, MIN(i.date_creation) min_date, MAX(i.date_creation) max_date
+  FROM
+    '.CATEGORIES_TABLE.' as c
+      INNER JOIN
+    '.IMAGE_CATEGORY_TABLE.' ON category_id = c.id
+      INNER JOIN
+    '.IMAGES_TABLE.' i ON image_id=i.id
+  WHERE lat IS NOT NULL '.$forbidden.'
+  GROUP BY category_id
+;';
+
+  $result = pwg_query($query);
+  $uppercats_list = array();
+  $cat_bounds = array();
+  while ($row = mysql_fetch_assoc($result))
+  {
+    array_push($uppercats_list, $row['uppercats']);
+    $cat_id = $row['cat_id'];
+    unset( $row['cat_id'], $row['uppercats'] );
+    $cat_bounds[ $cat_id ] = $row;
+    $cat_bounds[ $cat_id ]['self'] = $row;
+  }
+  natsort($uppercats_list);
+  //echo "<pre>" . var_export($uppercats_list,true);
+
+  foreach ( array_reverse($uppercats_list) as $uppercats)
+  {
+    $cat_ids = explode(',', $uppercats);
+    $bounds = $cat_bounds[ $cat_ids[count($cat_ids)-1] ];
+    for ($i=count($cat_ids)-2; $i>=0; $i--)
+    {
+      $this_bounds = @$cat_bounds[ $cat_ids[$i] ];
+      if ( !isset($this_bounds) )
+      {
+        $this_bounds = $bounds;
+        unset($this_bounds['self']);
+      }
+      else
+      {
+//        if ($cat_ids[$i]==43) echo "<pre>Before\n" . var_export($this_bounds,true);
+//        if ($cat_ids[$i]==43) echo "<pre>Union\n" . var_export($bounds,true);
+        $this_bounds = bounds_union($this_bounds, $bounds);
+      }
+      $this_bounds['nb_cats'] = 1 + @$this_bounds['nb_cats'];
+//      if ($cat_ids[$i]==43) echo "<pre>" . var_export($this_bounds,true);
+      $cat_bounds[ $cat_ids[$i] ] = $this_bounds;
+    }
+  }
+  //echo "<pre>" . var_export($cat_bounds,true);
+	mkgetdir( dirname($cache_file_name) );
+  $file = fopen($cache_file_name , 'w' );
+  fwrite($file, serialize($cat_bounds) );
+  fclose( $file );
+
+  return $cat_bounds;
+}
+
+
+function marray_from_query($query)
+{
+  $ret = array();
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_assoc($result))
+    $ret[] = $row;
+  return $ret;
+}
+
+define('RVM_BUILD_ARRAY',     0);
+define('RVM_BUILD_HASH',      1);
+define('RVM_BUILD_AGGREGATE', 2);
+
+function rvm_build_section_items($img_fields, $where_sql, $mode, $order_by=null)
+{
+  global $page, $conf, $user;
+
+  $page['items'] = array();
+
+  if (empty($where_sql))
+    $where_sql .= 'i.lat IS NOT NULL';
+  $where_sql_images_only = $where_sql;
+  $where_sql .= get_sql_condition_FandF(
+      array
+        (
+          'forbidden_categories' => 'category_id',
+          'visible_categories' => 'category_id',
+          'visible_images' => 'i.id'
+        ),
+      "\n  AND"
+  );
+
+  switch ($mode)
+  {
+    case RVM_BUILD_ARRAY:
+      $func = 'marray_from_query';
+      $group_by = '
+  GROUP BY i.id';
+      break;
+    case RVM_BUILD_HASH:
+      $func = create_function( '$q', 'return hash_from_query($q, "id");' );
+      $group_by = '
+  GROUP BY i.id';
+      break;
+    case RVM_BUILD_AGGREGATE:
+      $func = 'marray_from_query';
+      $group_by = '';
+      break;
+  }
+
+  if ($mode != RVM_BUILD_AGGREGATE )
+  {
+    if ($order_by==null and pwg_get_session_var('image_order',0) > 0)
+    {
+      $orders = get_category_preferred_image_orders();
+
+      $conf['order_by'] = str_replace(
+        'ORDER BY ',
+        'ORDER BY '.$orders[ pwg_get_session_var('image_order',0) ][1].',',
+        $conf['order_by']
+        );
+      $page['super_order_by'] = true;
+    }
+    elseif ($order_by!=null)
+    {
+      $conf['order_by']=$order_by;
+      $page['super_order_by'] = true;
+    }
+    elseif ( 'categories' == $page['section'] and isset($page['category']['image_order']) )
+    {
+      $conf['order_by'] = 'ORDER BY '.$page['category']['image_order'];
+    }
+  }
+  else
+  {
+    $conf['order_by'] = 'ORDER BY NULL';
+    $page['super_order_by'] = true;
+  }
+
+  if ('categories' == $page['section'])
+  {
+    if ( isset($page['flat']) or isset($page['category']) )
+    {
+      if (isset($page['flat']))
+      {
+        if ( isset($page['category']) )
+        {
+          $subcat_ids = get_subcat_ids( array($page['category']['id']) );
+          $where_sql .= ' AND category_id IN ('.implode(',',$subcat_ids).')';
+        }
+      }
+      else
+      {
+        $where_sql .= ' AND category_id='.$page['category']['id'];
+      }
+
+      $query='
+SELECT '.$img_fields.'
+  FROM '.IMAGES_TABLE.' i INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON i.id=image_id
+  WHERE '.$where_sql.$group_by.'
+  '.$conf['order_by'];
+
+      $page['items'] = $func($query);
+    }
+    if ( isset($page['category']) )
+    {
+      $page['title'] = $page['category']['name'];
+      $page['comment'] = $page['category']['comment'];
+    }
+    else
+      $page['title'] = $conf['gallery_title'];
+  }
+  else if ('tags' == $page['section'])
+  {
+    $items = get_image_ids_for_tags( array($page['tags'][0]['id']) );
+    if ( !empty($items) )
+    {
+      $query = '
+SELECT '.$img_fields.'
+  FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.IMAGES_TABLE.' i ON i.id=image_id
+  WHERE '.$where_sql.'
+    AND image_id IN ('.implode(',', $items).')'
+  .$group_by.'
+  '.$conf['order_by'];
+
+      $page['items'] = $func($query);
+    }
+    $page['title'] = strip_tags( get_tags_content_title() );
+  }
+  elseif ('search' == $page['section'])
+  {
+    include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' );
+    $search_result = get_search_results($page['search'], @$page['super_order_by'], $where_sql_images_only);
+    if ( !empty($search_result['items']) )
+    {
+      $query = '
+SELECT '.$img_fields.'
+  FROM '.IMAGES_TABLE.' i
+  WHERE id IN ('.implode(',', $search_result['items']).')'
+  .$group_by.'
+  '.$conf['order_by'].'
+;';
+
+      if ($mode != RVM_BUILD_AGGREGATE )
+      {
+        $page['items'] = hash_from_query($query, 'id' );
+
+        global $item_ranks;
+        $item_ranks = array_flip($search_result['items']);
+        function cmp_item_hash($a, $b)
+        {
+          global $item_ranks;
+          return $item_ranks [ $a['id'] ] - $item_ranks [ $b['id'] ];
+        }
+        uasort( $page['items'], 'cmp_item_hash' );
+        unset( $item_ranks );
+      }
+      else
+        $page['items'] = $func($query);
+    }
+
+    $page['title'] = l10n('search_result');
+  }
+  elseif ('recent_pics' == $page['section'])
+  {
+    $conf['order_by'] = ' ORDER BY hit DESC, file ASC';
+
+    $query ='
+SELECT '.$img_fields.'
+  FROM '.IMAGES_TABLE.' i
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  WHERE date_available >= SUBDATE(
+      CURRENT_DATE,INTERVAL '.$user['recent_period'].' DAY)
+    AND '.$where_sql
+  .$group_by.'
+  '.$conf['order_by'].'
+  LIMIT 0, '.$conf['top_number'].'
+;';
+
+    $page['items'] = $func($query);
+    $page['title'] = l10n('recent_pics_cat');
+  }
+  else if ('list'==$page['section'])
+  {
+    $query ='
+SELECT '.$img_fields.'
+  FROM '.IMAGES_TABLE.' i
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  WHERE image_id IN ('.implode(',', $page['list']).')
+    AND '.$where_sql
+  .$group_by.'
+  '.$conf['order_by'].'
+;';
+
+    $page['items'] = $func($query);
+    $page['title'] = l10n('random_cat');
+  }
+  else
+    fatal_error( 'section '.$page['section']. ' not handled '. __FILE__);
+}
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/include/picture_map.inc.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/include/picture_map.inc.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/include/picture_map.inc.php	(revision 8301)
@@ -0,0 +1,63 @@
+<?php
+global $page, $template, $conf, $rvm_dir;
+
+$template->concat('PLUGIN_PICTURE_ACTIONS', '
+  <a href="'.duplicate_picture_url().'" title="'.l10n('return to normal view mode').'"><img src="'.get_absolute_root_url(false).'plugins/'.$rvm_dir.'/icons/map_m.png" class="button" alt="map"></a>
+  ');
+
+$template->assign(
+  array(
+    'RVM_PLUGIN_VERSION' => RVM_PLUGIN_VERSION,
+    'GMAPS_API_KEY' => $conf['gmaps_api_key'],
+    'PLUGIN_ROOT_URL' => get_absolute_root_url().'plugins/'.$rvm_dir,
+  )
+  );
+
+$page['meta_robots']=array('noindex'=>1, 'nofollow'=>1);
+
+
+add_event_handler(
+  'render_element_content',
+  'rvm_picture_map_content',
+  EVENT_HANDLER_PRIORITY_NEUTRAL-5,
+  2
+  );
+
+add_event_handler( 'loc_end_picture', 'rvm_end_picture'  );
+
+
+function rvm_picture_map_content($content, $picture)
+{
+  include_once( dirname(__FILE__) .'/functions_map.php');
+  global $template;
+  $template->set_filename( 'map_content', dirname(__FILE__).'/../template/picture_map_content.tpl' );
+  $template->assign(
+    array(
+      'TN_SRC' => $picture['thumbnail'],
+      'U_NO_MAP' => duplicate_picture_url(),
+      'U_BLOWUP' => rvm_make_blowup_url( array('ll'=>$picture), array('start','box') ),
+      'COMMENT_IMG' => trigger_event('render_element_description', $picture['comment'])
+    )
+  );
+  if ( isset($picture['lat']) )
+  {
+    $template->assign( 'coordinates',
+        array(
+          'LAT' => $picture['lat'],
+          'LON' => $picture['lon'],
+        )
+      );
+  }
+  return $template->parse( 'map_content', true);
+}
+
+function rvm_end_picture()
+{
+  global $template;
+  $template->assign( 'COMMENT_IMG', null);  // no legend below picture (we put it left)
+  $rating = & $template->get_template_vars('rating');
+  if (isset($rating))
+    $rating['F_ACTION'] = add_url_params( $rating['F_ACTION'], array('map'=>null) );
+}
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/kml.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/kml.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/kml.php	(revision 8301)
@@ -0,0 +1,182 @@
+<?php
+define('PHPWG_ROOT_PATH','../../');
+
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+if (!isset($rvm_dir))
+  access_denied( 'Plugin not installed' );
+
+include_once( dirname(__FILE__) .'/include/functions_map.php');
+include_once( dirname(__FILE__) .'/include/functions.php');
+
+rvm_load_language();
+set_make_full_url();
+
+$section = '';
+if ( $conf['question_mark_in_urls']==false and
+     isset($_SERVER["PATH_INFO"]) and !empty($_SERVER["PATH_INFO"]) )
+{
+  $section = $_SERVER["PATH_INFO"];
+  $section = str_replace('//', '/', $section);
+}
+else
+{
+  foreach ($_GET as $key=>$value)
+  {
+    if (!strlen($value)) $section=$key;
+    break;
+  }
+}
+// deleting first "/" if displayed
+$tokens = explode(
+  '/',
+  preg_replace('#^/#', '', $section)
+  );
+$next_token = 0;
+$result = rvm_parse_kml_url($tokens, $next_token);
+$page = array_merge( $page, $result );
+
+$order_by=null;
+if ( isset($page['ll']) )
+  $where_sql = rvm_ll_to_sql($page['ll'], $order_by);
+else
+  $where_sql = rvm_bounds_to_sql( $page['box'] );
+
+
+$img_fields = ' i.id,i.tn_ext,i.name,i.comment,i.file,i.path,i.lat,i.lon,i.date_creation';
+
+rvm_build_section_items($img_fields, $where_sql, RVM_BUILD_ARRAY, $order_by);
+
+
+$dataTpl = new Template( PHPWG_ROOT_PATH );
+$dataTpl->set_filename('main', dirname(__FILE__).'/template/earth_kml.tpl' );
+
+$dataTpl->assign(
+  array(
+    'PAGE_TITLE' => strip_tags(@$page['title']),
+    'CONTENT_ENCODING' => get_pwg_charset(),
+    'PAGE_COMMENT' => strip_tags( @$page['comment'], '<a><br><p><b><i><small><strong><font>'),
+    'U_INDEX' => duplicate_index_url( array('start'=>0) ),
+  )
+);
+
+if ( !empty($page['items']) )
+  $dataTpl->assign( 'NB_ITEMS_DESC', sprintf( l10n('%d images'), count($page['items']) ).'<br/>' );
+
+
+// +-----------------------------------------------------------------------+
+// |              sub categories network links                             |
+// +-----------------------------------------------------------------------+
+if ( 'categories'==$page['section'] and !isset($page['flat']) )
+{
+  $query = '
+SELECT id, name, permalink, comment, uppercats, representative_picture_id
+  FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.'
+  ON id = cat_id and user_id = '.$user['id'].'
+  WHERE id_uppercat '.
+  (!isset($page['category']) ? 'is NULL' : '= '.$page['category']['id']).'
+  ORDER BY rank
+;';
+//  echo "<pre>" . var_export($query,true);
+  $result = pwg_query($query);
+  $categories = array();
+  $thumbnail_ids=array();
+  while ($row = mysql_fetch_assoc($result))
+  {
+    array_push($categories, $row);
+    if (isset($row['representative_picture_id']) and is_numeric($row['representative_picture_id']))
+      array_push($thumbnail_ids, $row['representative_picture_id'] );
+  }
+  $thumbnail_src_of = array();
+  if ( count($thumbnail_ids) )
+  {
+    $query = '
+SELECT id, path, tn_ext
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $thumbnail_ids).')';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_assoc($result))
+      $thumbnail_src_of[$row['id']] = get_thumbnail_url($row);
+    unset($thumbnail_ids);
+  }
+
+  $cat_bounds = rvm_get_cat_bounds();
+
+  foreach ($categories as $category)
+  {
+    if ( !isset( $cat_bounds[ $category['id'] ] ) )
+      continue; // without geo tagged images
+
+    $bounds = $cat_bounds[ $category['id'] ];
+
+    if ( isset($bounds['self']) )
+    {
+      $count_desc = l10n_dec('%d image', '%d images', $bounds['self']['count']);
+      if ( $bounds['self']['count'] == $bounds['count'] )
+        $count_desc .= ' '.l10n('images_available_cpl');
+      else
+        $count_desc .= '/'.l10n_dec('%d image', '%d images', $bounds['count']).' '.l10n_dec('images_available_cat','images_available_cats', $bounds['nb_cats'] );
+    }
+    else
+      $count_desc = l10n_dec('%d image', '%d images', $bounds['count'])
+        .' '.l10n_dec('images_available_cat','images_available_cats', $bounds['nb_cats'] );
+
+		$tpl_var = array(
+				'NAME'    => $category['name'],
+				'COMMENT' => trigger_event('render_category_literal_description', trigger_event('render_category_description', @$category['comment']) ),
+				'U_CATEGORY' => make_index_url( array('category'=>$category) ),
+				'U_KML'   => rvm_make_kml_index_url( array('section'=>'categories', 'category'=>$category) ),
+				'U_MAP'   => rvm_make_map_index_url( array('section'=>'categories', 'category'=>$category) ),
+				'COUNT_DESC' => $count_desc,
+				'region'  => $bounds,
+      );
+    if ( isset( $thumbnail_src_of[$category['representative_picture_id']] ) )
+      $tpl_var['TN_SRC'] = $thumbnail_src_of[$category['representative_picture_id']];
+
+    $dataTpl->append( 'categories', $tpl_var );
+  }
+}
+
+
+
+// +-----------------------------------------------------------------------+
+// | generate content for items                                            |
+// +-----------------------------------------------------------------------+
+$bounds = array();
+foreach( $page['items'] as $img )
+{
+	$bounds = bounds_add($bounds, $img['lat'], $img['lon']);
+	$page_url = duplicate_picture_url(array('image_id' => $img['id'],'image_file' => $img['file']),  array('start') );
+
+	if (!empty( $img['name'] ) )
+		$title = $img['name'];
+	else
+		$title = str_replace('_', ' ', get_filename_wo_extension($img['file']));
+
+  $tpl_var = array(
+      'U_PAGE'=> $page_url,
+      'TN_SRC'  => get_thumbnail_url($img),
+      'TITLE'  => $title,
+      'DESCRIPTION'  => trigger_event('render_element_description', $img['comment']),
+      'LAT'   => $img['lat'],
+      'LON'   => $img['lon'],
+      'DATE_CREATION' => $img['date_creation'],
+    );
+	$dataTpl->append('images', $tpl_var);
+}
+
+if ( !empty($bounds) )
+  $dataTpl->assign( 'region', $bounds );
+
+/*header('Cache-Control: public' );
+header('Expires: '.gmdate('D, d M Y H:i:s', time()+600).' GMT');
+header('Pragma:');*/
+header('Content-Disposition: inline; filename="'.str2url($page['title']).'.kml";' );
+header('Content-Type: application/vnd.google-earth.kml+xml; charset='.get_pwg_charset());
+if (isset($_GET['debug']))
+  header('Content-Type: text/xml; charset='.get_pwg_charset());
+
+
+$dataTpl->pparse('main');
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/cs_CZ/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/cs_CZ/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/cs_CZ/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Mapa';
+
+$lang['displays %s on a map']='zobrazí %s na mapě';
+$lang['opens %s in Google Earth']='otevře %s v aplikaci Google Earth (kterou musíte mít nainstalovánu v počítači)';
+
+$lang['Go to']='Jít na';
+
+$lang['go to %s']='jít na %s';
+$lang['displays all images on a map']='zobrazí všechny fotografie na mapě';
+$lang['Viewing']='Prohlížení';
+$lang['Link to this page']='Odkaz na tuto stránku';
+$lang['Show all']='Zobrazit vše';
+$lang['show all pictures around this location']='zobrazit fotografie v okolí';
+$lang['Search a location...']='Najít polohu...';
+
+$lang['Loading']='Nahrávání';
+$lang['Failed']='Nepodařilo se';
+
+$lang['Prev']='Předcházející';
+$lang['Next']='Další';
+$lang['out of %d']='z %d';
+
+$lang['More pictures near this location']='Více fotografií v okolí';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/de_DE/description.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/de_DE/description.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/de_DE/description.txt	(revision 8301)
@@ -0,0 +1,1 @@
+Erweitert Ihre Galerie mit Google Maps und Google Earth  ...
Index: /extensions/rv_gmaps/branches/2.1/language/de_DE/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/de_DE/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/de_DE/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Karte';
+
+$lang['displays %s on a map']='zeigt %s auf einer Karte an';
+$lang['opens %s in Google Earth']='öffnet %s in Google Earth (muss bei Ihnen installiert sein)';
+
+$lang['Go to']='Geht nach';
+
+$lang['go to %s']='Geht nach %s';
+$lang['displays all images on a map']='Zeigt alle Bilder auf einer Karte';
+$lang['Viewing']='Vorschau';
+$lang['Link to this page']='Link zu dieser Seite';
+$lang['Show all']='Zeigt Alle';
+$lang['show all pictures around this location']='zeigt alle Bilder rund um dieser Position';
+$lang['Search a location...']='Suche eine Position...';
+
+$lang['Loading']='lädt';
+$lang['Failed']='Fehlgeschlagen';
+
+$lang['Prev']='Vorherige';
+$lang['Next']='Nächste';
+$lang['out of %d']='aus %d';
+
+$lang['More pictures near this location']='Mehr Bilder in der Nähe dieser Position';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/en_UK/description.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/en_UK/description.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/en_UK/description.txt	(revision 8301)
@@ -0,0 +1,1 @@
+Extend your gallery with Google Maps and Google Earth ...
Index: /extensions/rv_gmaps/branches/2.1/language/en_UK/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/en_UK/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/en_UK/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Map';
+
+$lang['displays %s on a map']='displays %s on a map';
+$lang['opens %s in Google Earth']='opens %s in Google Earth (must be installed on your machine)';
+
+$lang['Go to']='Go to';
+
+$lang['go to %s']='go to %s';
+$lang['displays all images on a map']='displays all images on a map';
+$lang['Viewing']='Viewing';
+$lang['Link to this page']='Link to this page';
+$lang['Show all']='Show all';
+$lang['show all pictures around this location']='show all pictures around this location';
+$lang['Search a location...']='Search a location...';
+
+$lang['Loading']='Loading';
+$lang['Failed']='Failed';
+
+$lang['Prev']='Prev';
+$lang['Next']='Next';
+$lang['out of %d']='out of %d';
+
+$lang['More pictures near this location']='More pictures near this location';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/es_ES/description.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/es_ES/description.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/es_ES/description.txt	(revision 8301)
@@ -0,0 +1,1 @@
+Amplíe su galería con Mapas de Google y la Tierra Google...
Index: /extensions/rv_gmaps/branches/2.1/language/es_ES/index.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/es_ES/index.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/es_ES/index.php	(revision 8301)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/es_ES/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/es_ES/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/es_ES/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Mapa';
+
+$lang['displays %s on a map']='Visualizar %s sobre el mapa';
+$lang['opens %s in Google Earth']='Abre %s con Google Earth (Debe estar instalado en su PC)';
+
+$lang['Go to']='Ir a';
+
+$lang['go to %s']='ir a %s';
+$lang['displays all images on a map']='Visualizar todas las imágenes en la mapa';
+$lang['Viewing']='Vista de conjunto';
+$lang['Link to this page']='Enlaces hacia esta página';
+$lang['Show all']='Presenta todo';
+$lang['show all pictures around this location']='Presenta todas las imágenes cerca de estas coordenadas';
+$lang['Search a location...']='Buscar un lugar...';
+
+$lang['Loading']='Carga';
+$lang['Failed']='Fracaso';
+
+$lang['Prev']='Prece';
+$lang['Next']='Sigui';
+$lang['out of %d']='sobre %d';
+
+$lang['More pictures near this location']='Más imágenes cerca de este lugar';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/fr_FR/description.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/fr_FR/description.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/fr_FR/description.txt	(revision 8301)
@@ -0,0 +1,1 @@
+Utiliser dans la galerie Google Maps et Google Earth ..
Index: /extensions/rv_gmaps/branches/2.1/language/fr_FR/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/fr_FR/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/fr_FR/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Carte';
+
+$lang['displays %s on a map']='afficher %s sur la carte';
+$lang['opens %s in Google Earth']='Ouvre %s avec Google Earth (doit être installé sur votre PC)';
+
+$lang['Go to']='Aller à';
+
+$lang['go to %s']='aller à %s';
+$lang['displays all images on a map']='affiche toutes les images sur la carte';
+$lang['Viewing']='Aperçu';
+$lang['Link to this page']='Lien vers cette page';
+$lang['Show all']='Présente tout';
+$lang['show all pictures around this location']='Présente toutes les images à proximité de ces coordonnées';
+$lang['Search a location...']='Rechercher un lieu...';
+
+$lang['Loading']='Chargement';
+$lang['Failed']='Echec';
+
+$lang['Prev']='Préc';
+$lang['Next']='Suiv';
+$lang['out of %d']='sur %d';
+
+$lang['More pictures near this location']='Plus d\'images près de ce lieu';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/hu_HU/description.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/hu_HU/description.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/hu_HU/description.txt	(revision 8301)
@@ -0,0 +1,1 @@
+Galéria bővítése Goole Térkép és Föld...
Index: /extensions/rv_gmaps/branches/2.1/language/hu_HU/index.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/hu_HU/index.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/hu_HU/index.php	(revision 8301)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/hu_HU/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/hu_HU/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/hu_HU/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Térkép';
+
+$lang['displays %s on a map']='%s megjelenítése a térképen';
+$lang['opens %s in Google Earth']='%s megnyitása a Google Föld-ben (Telepíteni kell a számítógépre)';
+
+$lang['Go to']='Ugrás';
+
+$lang['go to %s']='ugrás %s';
+$lang['displays all images on a map']='megjeleníti az összes képet a térképen';
+$lang['Viewing']='Megnéz';
+$lang['Link to this page']='Link az oldalra';
+$lang['Show all']='Összes megjelenítése';
+$lang['show all pictures around this location']='Összes kép mellé ezeket a koordinátákat';
+$lang['Search a location...']='Hely keresése...';
+
+$lang['Loading']='Töltés';
+$lang['Failed']='Sikertelen';
+
+$lang['Prev']='Vissza';
+$lang['Next']='Tovább';
+$lang['out of %d']='ki %d-től';
+
+$lang['More pictures near this location']='További képek a hely közelében';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/it_IT/description.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/it_IT/description.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/it_IT/description.txt	(revision 8301)
@@ -0,0 +1,1 @@
+Permette di visualizzare le immagini su una mappa Google Maps e/o Google Earth
Index: /extensions/rv_gmaps/branches/2.1/language/it_IT/index.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/it_IT/index.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/it_IT/index.php	(revision 8301)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 4072 2009-10-20 20:27:54Z ddtddt $
+// | last update   : $Date: 2009-10-20 22:27:54 +0200 (mar. 20 oct. 2009) $
+// | last modifier : $Author: ddtddt $
+// | revision      : $Revision: 4072 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/it_IT/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/it_IT/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/it_IT/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Cartine';
+
+$lang['displays %s on a map']='visualizzare %s sulla cartina';
+$lang['opens %s in Google Earth']='Aprire %s con Google Earth (deve essere installato sul vostro PC)';
+
+$lang['Go to']='Andare a';
+
+$lang['go to %s']='andare a %s';
+$lang['displays all images on a map']='visualizzare tutte le immagini sulla cartina';
+$lang['Viewing']='Anteprima';
+$lang['Link to this page']='Link verso questa pagina';
+$lang['Show all']='Presenta tutto';
+$lang['show all pictures around this location']='Presenta tutte le immagini in prossimità di queste coordinate';
+$lang['Search a location...']='Cecare un luogo...';
+
+$lang['Loading']='Caricamento';
+$lang['Failed']='Insucesso';
+
+$lang['Prev']='Prec';
+$lang['Next']='Succ';
+$lang['out of %d']='su %d';
+
+$lang['More pictures near this location']='Più immagini vicino a questo luogo';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/lv_LV/description.txt
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/lv_LV/description.txt	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/lv_LV/description.txt	(revision 8301)
@@ -0,0 +1,1 @@
+Paplašini savu galeriju ar Google Maps un Google Earth ...
Index: /extensions/rv_gmaps/branches/2.1/language/lv_LV/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/lv_LV/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/lv_LV/lang.php	(revision 8301)
@@ -0,0 +1,25 @@
+<?php
+$lang['Map']='Karte';
+
+$lang['displays %s on a map']='rāda %s uz kartes';
+$lang['opens %s in Google Earth']='atver %s iekš Google Earth (jābūt uzinstalētam)';
+
+$lang['Go to']='Iet uz';
+
+$lang['go to %s']='iet uz %s';
+$lang['displays all images on a map']='attēlo visus attēlus uz kartes';
+$lang['Viewing']='Aplūkošana';
+$lang['Link to this page']='Saite uz šo lapu';
+$lang['Show all']='Rādīt visu';
+$lang['show all pictures around this location']='rādīt visus attēlus ap šo (vietu) lokāciju';
+$lang['Search a location...']='Meklēt lokāciju...';
+
+$lang['Loading']='Lādēšana';
+$lang['Failed']='Kļūme';
+
+$lang['Prev']='Iepriekšējais';
+$lang['Next']='Nākamais';
+$lang['out of %d']='ārpus %d';
+
+$lang['More pictures near this location']='Vairāk attēlu ap šo vietu (lokāciju)';
+?>
Index: /extensions/rv_gmaps/branches/2.1/language/pl_PL/lang.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/language/pl_PL/lang.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/language/pl_PL/lang.php	(revision 8301)
@@ -0,0 +1,26 @@
+<?php
+//Polish translation by voyteckst
+$lang['Map']='Mapa';
+
+$lang['displays %s on a map']='wyświetla %s na mapie';
+$lang['opens %s in Google Earth']='otwiera %s w Google Earth (aplikacjam musi być zainstalowana na komputerze)';
+
+$lang['Go to']='Przejdź do';
+
+$lang['go to %s']='przejdź do %s';
+$lang['displays all images on a map']='wyświetla wszystkie obrazy na mapie';
+$lang['Viewing']='Przeglądanie';
+$lang['Link to this page']='Link do tej strony';
+$lang['Show all']='Pokaż wszystko';
+$lang['show all pictures around this location']='pokaż wszystkie obrazy w pobliżu tej lokalizacji';
+$lang['Search a location...']='Szukaj lokalizacji...';
+
+$lang['Loading']='Wczytywanie';
+$lang['Failed']='Błąd';
+
+$lang['Prev']='Poprzednie';
+$lang['Next']='Nastepne';
+$lang['out of %d']='z %d';
+
+$lang['More pictures near this location']='Więcej obrazów w pobliżu tej lokalizacji';
+?>
Index: /extensions/rv_gmaps/branches/2.1/main.inc.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/main.inc.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/main.inc.php	(revision 8301)
@@ -0,0 +1,136 @@
+<?php /*
+Plugin Name: RV Maps&Earth
+Version: 2.1.b
+Description: Extend your gallery with Google Maps and Google Earth ...
+Plugin URI: http://piwigo.org/ext/extension_view.php?eid=122
+Author: rvelices
+Author URI: http://www.modusoptimus.com/
+*/
+define( 'RVM_PLUGIN_VERSION', '2.1.b');
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+add_event_handler('loc_end_index', 'rvm_end_index' );
+add_event_handler('loc_begin_index_category_thumbnails', 'rvm_index_cat_thumbs_displayed');
+add_event_handler('loc_begin_index_thumbnails', 'rvm_begin_index_thumbnails');
+
+add_event_handler('picture_pictures_data', 'rvm_picture_pictures_data' );
+add_event_handler('get_admin_plugin_menu_links', 'rvm_plugin_admin_menu' );
+
+global $rvm_dir;
+$rvm_dir = basename( dirname(__FILE__) );
+
+
+function rvm_index_cat_thumbs_displayed()
+{
+	global $page;
+	$page['rvm_cat_thumbs_displayed'] = true;
+}
+
+function rvm_begin_index_thumbnails( $pictures )
+{
+	global $page;
+	foreach ($pictures as $picture)
+	{
+		if ( isset($picture['lat']) )
+		{
+			$page['rvm_items_have_latlon'] = true;
+			break;
+		}
+	}
+}
+
+function rvm_end_index()
+{
+	global $page, $filter, $template, $rvm_dir;
+
+	//if ( !is_admin() ) return; // TEMP
+	if ( isset($page['chronology_field']) || $filter['enabled'] )
+		return;
+
+	if ( 'categories' == @$page['section'])
+	{ // flat or no flat ; has subcats or not;  ?
+		if ( ! @$page['rvm_cat_thumbs_displayed'] and empty($page['items']) )
+			return;
+	}
+	else
+	{
+		if (
+			!in_array( @$page['section'], array('tags','search','recent_pics','list') )
+			)
+			return;
+		if ( empty($page['items']) )
+			return;
+	}
+
+	include_once( dirname(__FILE__) .'/include/functions.php');
+
+	if ( !empty($page['items']) )
+	{
+		if (!@$page['rvm_items_have_latlon'] and ! rvm_items_have_latlon( $page['items'] ) )
+			return;
+	}
+	rvm_load_language();
+
+	$map_url = rvm_duplicate_map_index_url( array(), array('start') );
+	if ( !empty($map_url) )
+	{
+		$link_title = sprintf( l10n('displays %s on a map'), strip_tags($page['title']) );
+		$template->concat( 'PLUGIN_INDEX_ACTIONS' ,'
+<li><a href="'.$map_url.'" title="'.$link_title.'" rel="nofollow"><img src="'.get_absolute_root_url(false).'plugins/'.$rvm_dir.'/icons/map_m.png" class="button" alt="map"></a></li>
+');
+ 	}
+
+//  if ( empty($map_url) )
+	{
+		$kml_url = rvm_duplicate_kml_index_url( array(), array('start') );
+		$link_title = sprintf( l10n('opens %s in Google Earth'), strip_tags($page['title']) );
+		$template->concat( 'PLUGIN_INDEX_ACTIONS' ,'
+<li><a href="'.$kml_url.'" title="'.$link_title.'" rel="nofollow" type="application/vnd.google-earth.kml+xml"><img src="'.get_absolute_root_url(false).'plugins/'.$rvm_dir.'/icons/earth_m.png" class="button" alt="earth"></a></li>
+');
+	}
+}
+
+function rvm_picture_pictures_data($pictures)
+{
+	if ( isset($pictures['current']['lat']) and isset($pictures['current']['lon']) )
+	{
+		global $template;
+		$template->append('head_elements', '<meta name="geo.position" content="'.$pictures['current']['lat'].';'.$pictures['current']['lon'].'">' );
+		include_once( dirname(__FILE__) .'/include/functions.php');
+		rvm_load_language();
+		if ( isset($_GET['map']) )
+			include_once( dirname(__FILE__) .'/include/picture_map.inc.php');
+		else
+		{
+			global $rvm_dir;
+			$map_url = rvm_duplicate_map_picture_url();
+			if (!empty($map_url))
+			{
+				$link_title = sprintf( l10n('displays %s on a map'), strip_tags($pictures['current']['name']) );
+				$template->concat('PLUGIN_PICTURE_ACTIONS', '
+<a href="'.$map_url.'" title="'.$link_title.'" rel="nofollow" target="_top"><img src="'.get_absolute_root_url(false).'plugins/'.$rvm_dir.'/icons/map_m.png" class="button" alt="map"></a>
+');
+			}
+		}
+	}
+	else
+		if ( isset($_GET['map']) )
+			redirect( duplicate_picture_url() );
+	return $pictures;
+}
+
+function rvm_plugin_admin_menu($menu)
+{
+	include_once( dirname(__FILE__) .'/include/functions.php');
+	add_event_handler('invalidate_user_cache', 'rvm_invalidate_cache' );
+
+	array_push($menu,
+			array(
+				'NAME' => 'Maps & Earth',
+				'URL' => get_admin_plugin_menu_link(dirname(__FILE__).'/admin/admin.php')
+			)
+		);
+	return $menu;
+}
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/maintain.inc.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/maintain.inc.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/maintain.inc.php	(revision 8301)
@@ -0,0 +1,76 @@
+<?php
+function plugin_install()
+{
+  $q = '
+ALTER TABLE '.IMAGES_TABLE.' ADD COLUMN `lat` DOUBLE(8,6)';
+  pwg_query($q);
+  
+  $q = '
+ALTER TABLE '.IMAGES_TABLE.' ADD INDEX images_lat(`lat`)';
+  pwg_query($q);
+
+  $q = '
+ALTER TABLE '.IMAGES_TABLE.' ADD COLUMN `lon` DOUBLE(9,6)';
+  pwg_query($q);
+  
+  $q = '
+INSERT INTO '.CONFIG_TABLE.' (param,value,comment)
+  VALUES
+  ("gmaps_api_key","","Google Maps API key")
+;';
+  pwg_query($q);
+}
+
+function plugin_activate()
+{
+  $dir_name = basename( dirname(__FILE__) );
+  $c = <<<EOD
+<?php
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH. 'plugins/$dir_name/map.php');
+?>
+EOD;
+  $fp = fopen( PHPWG_ROOT_PATH.'map.php', 'w' );
+  fwrite( $fp, $c);
+  fclose( $fp );
+
+	$old = dirname(__FILE__).'/_rvgm_config.dat';
+	if ( is_file($old) )
+	{
+	  global $conf;
+		$dest = $conf['local_data_dir'].'/plugins/'.basename(dirname(__FILE__)).'.dat';
+	  if (!file_exists($dest) )
+	  {
+	    mkgetdir( dirname($dest) );
+	  	copy( $old, $dest );
+	  }
+	  unlink( $old );
+	}
+}
+
+function plugin_deactivate()
+{
+  @unlink( PHPWG_ROOT_PATH.'map.php' );
+  rvm_invalidate_cache();
+}
+
+function plugin_uninstall()
+{
+  $q = '
+ALTER TABLE '.IMAGES_TABLE.' DROP COLUMN `lat`';
+  pwg_query( $q );
+
+  $q = '
+ALTER TABLE '.IMAGES_TABLE.' DROP COLUMN `lon`';
+  pwg_query( $q );
+
+  $q = '
+DELETE FROM '.CONFIG_TABLE.' WHERE param="gmaps_api_key" LIMIT 1';
+  pwg_query( $q );
+  
+  global $conf;
+	$dest = $conf['local_data_dir'].'/plugins/'.basename(dirname(__FILE__)).'.dat';
+  @unlink( $dest );
+}
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/map.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/map.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/map.php	(revision 8301)
@@ -0,0 +1,89 @@
+<?php
+if ( !defined('PHPWG_ROOT_PATH') )
+  define('PHPWG_ROOT_PATH','../../');
+
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+include_once( dirname(__FILE__) .'/include/functions.php');
+include_once( dirname(__FILE__) .'/include/functions_map.php');
+
+check_status(ACCESS_GUEST);
+if (!isset($rvm_dir))
+  access_denied( 'Plugin not installed' );
+
+rvm_load_language();
+
+$section = '';
+if ( $conf['question_mark_in_urls']==false and
+     isset($_SERVER["PATH_INFO"]) and !empty($_SERVER["PATH_INFO"]) )
+{
+  $section = $_SERVER["PATH_INFO"];
+  $section = str_replace('//', '/', $section);
+  $path_count = count( explode('/', $section) );
+  $page['root_path'] = PHPWG_ROOT_PATH.str_repeat('../', $path_count-1);
+}
+else
+{
+  foreach ($_GET as $key=>$value)
+  {
+    if (!strlen($value)) $section=$key;
+    break;
+  }
+}
+
+// deleting first "/" if displayed
+$tokens = explode(
+  '/',
+  preg_replace('#^/#', '', $section)
+  );
+$next_token = 0;
+$result = rvm_parse_map_data_url($tokens, $next_token);
+$page = array_merge( $page, $result );
+
+
+if (isset($page['category']))
+  check_restrictions($page['category']['id']);
+
+if ( !isset($_GET['ll']) and ($page['section']!='categories' or isset($page['category']) ) )
+{
+  $img_fields = 'MIN(i.lat) s, MIN(i.lon) w, MAX(i.lat) n, MAX(i.lon) e';
+  $page['flat']=true;
+  rvm_build_section_items($img_fields, null, RVM_BUILD_AGGREGATE);
+  //var_export( $page['items'] );
+  if ( count($page['items']) )
+    $template->assign('initial_bounds', $page['items'][0] );
+  unset( $page['items'] );
+}
+
+
+$map_data_url  = get_absolute_root_url().'plugins/'.$rvm_dir.'/map_data.php?';
+$map_data_url .= $section;
+
+$template->set_filename( 'map', dirname(__FILE__).'/template/map.tpl' );
+
+$template->assign(
+  array(
+    'CONTENT_ENCODING' => get_pwg_charset(),
+    'RVM_PLUGIN_VERSION' => RVM_PLUGIN_VERSION,
+    'GMAPS_API_KEY' => $conf['gmaps_api_key'],
+    'PLUGIN_ROOT_URL' => get_absolute_root_url().'plugins/'.$rvm_dir,
+    'U_MAP_DATA' => $map_data_url,
+    'GALLERY_TITLE' => $conf['gallery_title'],
+    'U_HOME' => make_index_url(),
+    'U_HOME_MAP' => rvm_make_map_index_url(),
+  )
+  );
+
+$marker_js_file = rvm_get_config_var('marker_icon', '');
+if ( !empty($marker_js_file) )
+  $marker_js_file = dirname(__FILE__).'/template/markers/'.$marker_js_file.'.tpl';
+if ( !empty($marker_js_file) and file_exists($marker_js_file) )
+{
+  $template->set_filename( 'map_marker_icon', $marker_js_file );
+  $template->assign_var_from_handle('MAP_MARKER_ICON_JS', 'map_marker_icon');
+}
+else
+  $template->assign('MAP_MARKER_ICON_JS', 'return G_DEFAULT_ICON;');
+
+$template->pparse('map');
+$template->p();
+?>
Index: /extensions/rv_gmaps/branches/2.1/map_data.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/map_data.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/map_data.php	(revision 8301)
@@ -0,0 +1,184 @@
+<?php
+if ( !defined('PHPWG_ROOT_PATH') )
+  define('PHPWG_ROOT_PATH','../../');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+if (!isset($rvm_dir))
+  access_denied( 'Plugin not installed' );
+
+include_once( dirname(__FILE__) .'/include/functions_map.php');
+include_once( dirname(__FILE__) .'/include/functions.php');
+
+
+//set_make_full_url();
+$page['root_path']=get_absolute_root_url(false);
+
+$rewritten = '';
+foreach (array_keys($_GET) as $key)
+{
+  $rewritten = $key;
+  break;
+}
+// deleting first "/" if displayed
+$tokens = explode(
+  '/',
+  preg_replace('#^/#', '', $rewritten)
+  );
+$next_token = 0;
+$result = rvm_parse_map_data_url($tokens, $next_token);
+$page = array_merge( $page, $result );
+
+$where_sql = rvm_bounds_to_sql( $page['box'] );
+
+$img_fields = ' i.id,i.tn_ext,i.name,i.comment,i.path,i.lat,i.lon';
+
+$was_flat = @$page['flat'];
+$page['flat']=true;
+rvm_build_section_items($img_fields, $where_sql, RVM_BUILD_HASH);
+if (!$was_flat) unset($page['flat']);
+
+/*header('Cache-Control: public' );
+header('Expires: '.gmdate('D, d M Y H:i:s', time()+600).' GMT');
+header('Pragma:');*/
+header('Content-Type: text/plain; charset='.get_pwg_charset());
+
+if ( extension_loaded('zlib') && !ini_get('zlib.output_compression') )
+  ob_start('ob_gzhandler');
+
+$clusters = array();
+$cluster_debug = '';
+if ( !empty($page['items']) )
+{
+  include_once( dirname(__FILE__) .'/include/cluster_maker.php');
+  $cm = new ClusterMaker();
+  $clusters = $cm->make_clusters(
+      $page['items'],
+      isset($_GET['lap']) ? $_GET['lap'] : 0.01,
+      isset($_GET['lop']) ? $_GET['lop'] : 0.01,
+      isset($_GET['n']) ? $_GET['n'] : rvm_get_config_var('nb_markers',40)
+    );
+  $cluster_debug .= ' cluster: '. $cm->debug_str. ';';
+}
+
+function jsgm_position( $position )
+{
+  return 'new GLatLng(' . $position['lat'] . ',' . $position['lon'] . ')';
+}
+
+function jsgm_bounds( $bounds )
+{
+  return 'new GLatLngBounds(' . jsgm_position(bounds_sw($bounds)) . ',' . jsgm_position(bounds_ne($bounds)) . ')';
+}
+
+function jsgm_str( $str )
+{
+  return '"'. str_replace(array("\\",'"',"\n","\r","\t"), array("\\\\",'\"',"\\n","\\r","\\t"), $str) .'"';
+}
+
+$out='';
+function rvo($s) {
+  global $out; $out.=$s;
+}
+
+function rvf() {
+  global $out; echo $out; $out='';
+  ob_flush();
+}
+
+$start_output = get_moment();
+
+rvo( '{' );
+
+rvo( "\ntitle: ".jsgm_str( strip_tags(trigger_event('render_element_description', $page['title']) ) ) );
+rvo( ",\n" );
+
+rvo( "page_url: ".jsgm_str( duplicate_index_url( array('start'=>0) ) ) );
+rvo( ",\n" );
+
+rvo( "blowup_url: ".jsgm_str( rvm_duplicate_blowup_url( array('start'=>0) ) ) );
+rvo( ",\n" );
+
+rvo( "kml_url: ".jsgm_str( rvm_duplicate_kml_index_url( array('start'=>0, 'flat'=>1) ) ) );
+rvo( ",\n" );
+
+rvo( "nb_items: ".count($page['items']) );
+rvo( ",\n" );
+
+rvo( "bounds: " );
+if ( isset($cm) )
+  rvo( jsgm_bounds( $cm->bounds ) );
+else
+  rvo( "null" );
+rvo( ",\n" );
+
+
+rvo( "\nnb_clusters: ".count($clusters) );
+rvo( "," );
+
+rvo( "\nimage_clusters: [\n" );
+$i=0;
+foreach( $clusters as $c )
+{
+  if ($i) rvo( ",\n\n" );
+  rvo( "{" );
+  rvo( 'position: '. jsgm_position( bounds_center($c['bounds']) ) );
+  rvo( ",\n" );
+  rvo( 'bounds: '. jsgm_bounds( $c['bounds'] ) );
+  rvo( ",\n" );
+  rvo( 'nb_items: '.count($c['items']) );
+  rvo( ",\n" );
+
+  rvo( 'blowup_url: "'.rvm_duplicate_blowup_url(array('box'=>$c['bounds']), array('start') ). '"' );
+  rvo( ",\n" );
+
+  rvo( 'kml_url: "'.rvm_duplicate_kml_index_url(array('box'=>$c['bounds'], 'flat'=>1), array('start') ). '"' );
+  rvo( ",\n" );
+
+  $max_per_cluster = rvm_get_config_var('nb_images_per_marker',20);
+  if ( count($c['items']) >  $max_per_cluster )
+  {
+    $c['items'] = array_slice($c['items'], 0, $max_per_cluster);
+  }
+  rvo( 'items: [' );
+  for ($j=0; $j<count($c['items']); $j++)
+  {
+    $img = $page['items'] [ $c['items'][$j] ];
+    $img['file'] = basename( $img['path'] );
+    if (!empty( $img['name'] ) )
+      $title = $img['name'];
+    else
+      $title = str_replace('_', ' ', get_filename_wo_extension($img['file']));
+
+    $params = array(
+        'image_id' => $img['id'],
+        'image_file' => $img['file'],
+        'flat' => 1,
+      );
+    $page_url = duplicate_picture_url($params, array('start') );
+
+    if ($j) rvo( "," );
+    rvo( "{" );
+    rvo( "tn: ".jsgm_str( get_thumbnail_url( $img ) ) );
+    rvo( "," );
+    rvo( "name: ".jsgm_str( trigger_event('render_element_description', $title) ) );
+    rvo( "," );
+    rvo( "comment: ".jsgm_str( trigger_event('render_element_description', $img['comment']) ) );
+    rvo( "," );
+    rvo( "page_url: ".jsgm_str( $page_url ) );
+    rvo( "}" );
+  }
+  rvo( ']' );
+  rvo( "\n" );
+  rvo( "}" );
+  rvf();
+  $i++;
+}
+rvo( "] /*clusters*/\n" );
+
+$time = get_elapsed_time($t2, get_moment());
+$page['queries_time'] = number_format($page['queries_time'],3,'.',' ');
+rvo( "\n,debug:'$time; out:".get_elapsed_time($start_output,get_moment()).";$cluster_debug queries:".$page['count_queries']." in ".$page['queries_time']."s'\n" );
+
+rvo( '}' );
+rvf();
+?>
Index: /extensions/rv_gmaps/branches/2.1/mapl.php
===================================================================
--- /extensions/rv_gmaps/branches/2.1/mapl.php	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/mapl.php	(revision 8301)
@@ -0,0 +1,182 @@
+<?php
+if ( !defined('PHPWG_ROOT_PATH') )
+  define('PHPWG_ROOT_PATH','../../');
+
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+include_once( dirname(__FILE__) .'/include/functions.php');
+include_once( dirname(__FILE__) .'/include/functions_map.php');
+
+check_status(ACCESS_GUEST);
+if (!isset($rvm_dir))
+  access_denied( 'Plugin not installed' );
+
+rvm_load_language();
+
+$section = '';
+if ( $conf['question_mark_in_urls']==false and
+     isset($_SERVER["PATH_INFO"]) and !empty($_SERVER["PATH_INFO"]) )
+{
+  $section = $_SERVER["PATH_INFO"];
+  $section = str_replace('//', '/', $section);
+  if ( !isset($page['root_path']) )
+  {
+    $path_count = count( explode('/', $section) );
+    $page['root_path'] = PHPWG_ROOT_PATH.str_repeat('../', $path_count-1);
+  }
+}
+else
+{
+  foreach ($_GET as $key=>$value)
+  {
+    if (!strlen($value)) $section=$key;
+    break;
+  }
+}
+
+// deleting first "/" if displayed
+$tokens = explode(
+  '/',
+  preg_replace('#^/#', '', $section)
+  );
+$next_token = 0;
+$result = rvm_parse_blowup_url($tokens, $next_token);
+$page = array_merge( $page, $result );
+
+$order_by=null;
+if ( isset($page['ll']) )
+  $where_sql = rvm_ll_to_sql($page['ll'], $order_by);
+else
+  $where_sql = rvm_bounds_to_sql( $page['box'] );
+
+$img_fields = ' i.id,i.tn_ext,i.name,i.path,i.lat,i.lon';
+
+$was_flat = @$page['flat'];
+$page['flat']=true;
+rvm_build_section_items($img_fields, $where_sql, RVM_BUILD_HASH, $order_by);
+if (!$was_flat) unset($page['flat']);
+
+$template->set_filename( 'map', dirname(__FILE__).'/template/mapl.tpl');
+
+if (!empty($page['items']))
+{
+/* GENERATE THE CATEGORY LIST *************************************************/
+$where_sql = 'i.id IN ('.implode(',', array_keys($page['items']) ).')';
+$where_sql .= get_sql_condition_FandF(
+        array( 'forbidden_categories' => 'category_id' ),
+        ' AND'
+      );
+$query = '
+SELECT DISTINCT c.id, c.name, c.permalink, COUNT(DISTINCT i.id) counter
+  FROM '.IMAGES_TABLE.' i INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON i.id=image_id
+    INNER JOIN '.CATEGORIES_TABLE.' c ON c.id=category_id
+  WHERE '.$where_sql.'
+  GROUP BY category_id
+  ORDER BY counter DESC
+  LIMIT 0,5
+;';
+$result = pwg_query($query);
+$categories=array();
+while ($row=mysql_fetch_assoc($result))
+  array_push($categories, $row);
+$categories = add_level_to_tags($categories);
+
+foreach( $categories as $category)
+{
+  $template->append(
+    'related_categories', array(
+      'U_MAP' => rvm_make_map_index_url( array( 'category' => $category ) ),
+      'URL' => make_index_url( array( 'category' => $category ) ),
+      'NAME' => trigger_event('render_element_description', $category['name']),
+      'TITLE' => l10n_dec( '%d image', '%d images', $category['counter'] ),
+      'CLASS' => 'tagLevel'.$category['level']
+    )
+    );
+}
+
+/* GENERATE THE TAG LIST ******************************************************/
+$tags = get_common_tags( array_keys($page['items']), $conf['content_tag_cloud_items_number'], null);
+$tags = add_level_to_tags($tags);
+function counter_compare($a, $b)
+{
+  $d = $a['counter'] - $b['counter'];
+  if ($d==0)
+    return strcmp($a['name'], $b['name']);
+  return -$d;
+}
+usort($tags, 'counter_compare');
+foreach ($tags as $tag)
+{
+  $template->append(
+    'related_tags',
+    array_merge( $tag,
+      array(
+        'U_MAP' => rvm_make_map_index_url( array( 'tags' => array($tag) ) ),
+        'URL' => make_index_url( array( 'tags' => array($tag) ) ),
+        'TITLE' => l10n_dec( '%d image', '%d images', $tag['counter'] ),
+      )
+    )
+  );
+}
+} // end !empty items
+
+
+$title = '<a target="_top" title="'.sprintf( l10n('go to %s'),$page['title']).'" href="'.duplicate_index_url( array('start'=>0) ).'">'.$page['title'].'</a>';
+if ( count($page['items']) > 0)
+  $title.=' ['.count($page['items']).']';
+
+$template->assign(
+  array(
+    'PLUGIN_ROOT_URL' => get_absolute_root_url().'plugins/'.$rvm_dir,
+    'TITLE'   => $title,
+    'U_HOME'  => make_index_url(),
+    'U_KML'   => rvm_duplicate_kml_index_url( array('flat'=>1), array('start') ),
+    'KML_LINK_TITLE' => sprintf( l10n('opens %s in Google Earth'), strip_tags($page['title']) ),
+  )
+  );
+
+$url = rvm_duplicate_blowup_url(array('start'=>0));
+$navbar = create_navigation_bar($url, count( $page['items'] ), $page['start'], 48);
+$template->assign('navbar', $navbar);
+
+$page['items'] = array_slice(
+  $page['items'],
+  $page['start'],
+  48
+  );
+
+foreach ($page['items'] as $img)
+{
+  $img['file'] = basename( $img['path'] );
+  $thumbnail_url = get_thumbnail_url($img);
+  $page_url = duplicate_picture_url(
+        array(
+          'image_id' => $img['id'],
+          'image_file' => $img['file'],
+          'flat' => 1,
+        ),
+        array('start')
+      );
+  if (!empty( $img['name'] ) )
+    $title = $img['name'];
+  else
+    $title = str_replace('_', ' ', get_filename_wo_extension($img['file']));
+
+  $template->append(
+    'thumbnails',
+    array(
+      'TN_SRC'       => $thumbnail_url,
+      'URL'  => $page_url,
+      'TN_ALT'   => $img['file'],
+      'TN_TITLE'   => $title,
+      )
+    );
+}
+
+$title = $page['title'];
+$page['body_id'] = 'theMapListPage';
+
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+$template->parse('map');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+
+?>
Index: /extensions/rv_gmaps/branches/2.1/template/data_handler.js
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/data_handler.js	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/data_handler.js	(revision 8301)
@@ -0,0 +1,285 @@
+
+function PwgDataHandler( map, opts )
+{
+	this._map = map;
+	this.options = jQuery.fn.extend(
+		{
+			icon: G_DEFAULT_ICON,
+			show_all_img_src: null
+		}
+		, opts || {} );
+
+	google.maps.Event.addListener( map, "infowindowclose", function() {map.getInfoWindow().pwgMarker=null;} );
+}
+
+PwgDataHandler.prototype =  {
+
+_map: null,
+options: {},
+_markers: [],
+_navHtmlIds: ["gotoPrevImage", "gotoNextImage"],
+_timerBindPictureNavigation: null,
+_prevResult: { nb_items:0 },
+
+
+terminate: function()
+{
+	this._map = null;
+	try {
+		for (i=0; i<this._markers.length; i++)
+			this._markers[i].pwg = null;
+		this._markers.length = 0;
+	}
+	catch(e){}
+},
+
+handle: function( data )
+{
+	var i;
+	if (document.title != data.title )
+		document.title = data.title;
+	var elt = document.getElementById("aPageUrl");
+	if (elt && elt.href!=data.page_url.urlNoHtm() )
+	{
+		elt.href = data.page_url.urlNoHtm();
+		elt.innerHTML = data.title;
+		elt.title = Localization.fmt1("go to %s", data.title);
+	}
+	var elt = document.getElementById("aBlowup");
+	if (elt && elt.href!=data.blowup_url.urlNoHtm())
+		 elt.href = data.blowup_url.urlNoHtm();
+
+	var elt = document.getElementById("aKml");
+	if (elt && elt.href!=data.kml_url.urlNoHtm())
+	{
+		 elt.href = data.kml_url.urlNoHtm();
+		 elt.title = Localization.fmt1("opens %s in Google Earth", data.title);
+	}
+	var changed = true;
+	if (this._prevResult.nb_items==data.nb_items && this._markers.length==data.image_clusters.length )
+	{
+		changed = false;
+		if (this._markers.length>0 && !this._markers[0].getLatLng().equals( data.image_clusters[0].position ) )
+			changed=true;
+	}
+
+	if (changed)
+	{
+		var newMarkers = [];
+		var infoWindowMarker = this._map.getInfoWindow().pwgMarker;
+
+		for (i=0; i<data.image_clusters.length; i++)
+		{
+			var cluster = data.image_clusters[i];
+			var theTitle = "";
+			if (cluster.nb_items>1)
+				theTitle = Localization.fmt1("%d images", cluster.nb_items);
+			else
+				theTitle = cluster.items[0].name;
+
+			var marker;
+			marker = this._markers.pop();
+			if (marker && marker==infoWindowMarker)
+			{
+				this._map.removeOverlay( marker );
+				google.maps.Event.clearListeners(marker, "click" );
+				google.maps.Event.clearListeners(marker, "dblclick" );
+				this._map.getInfoWindow().pwgMarker = infoWindowMarker = null;
+				if (document.is_debug) google.maps.Log.write('removed marker with infoWindow');
+				marker = this._markers.pop();
+			}
+
+			if (!marker)
+			{
+				marker = new google.maps.Marker( cluster.position, {title:  theTitle, icon: this.options.icon } );
+				google.maps.Event.addListener( marker, "click", pwgBind(this, this._onMarkerClick, marker) );
+				google.maps.Event.addListener( marker, "dblclick", pwgBind(this, this._onMarkerDblClick, marker) );
+				this._map.addOverlay( marker );
+			}
+			else
+			{
+				marker.currentImageIndex=0;
+				marker.setLatLng( cluster.position );
+				// changing the marker title is undocumented so we hack it
+				if (!this.hack)
+				{
+					this.hack = {};
+					for (var prop in marker)
+					{
+						if ( typeof(marker[prop])!='object') continue;
+						if (!this.hack.markerHtmlElemWithTitle )
+						{
+							try {
+								if (eval("typeof marker." + prop + "[0].src") == "string" && eval("typeof marker." + prop + "[0].title") == "string" )
+									this.hack.markerHtmlElemWithTitle = prop;
+							}
+							catch (e) {}
+						}
+						if (!this.hack.markerOptions)
+							try {
+								if ( eval("typeof marker."+prop+".title")=="string" && eval("typeof marker."+prop+".src")=="undefined")
+									this.hack.markerOptions = prop;
+							}
+							catch (e) {}
+					}
+				}
+				//undocumented marker.K , marker.ch and marker.jb and marker.l
+				if (this.hack.markerOptions)
+					eval( 'marker.'+this.hack.markerOptions+'.title=theTitle');
+				if (this.hack.markerHtmlElemWithTitle)
+					eval( 'marker.'+this.hack.markerHtmlElemWithTitle+'[0].title=theTitle');
+			}
+
+			newMarkers.push(marker);
+
+			marker.pwg = {
+				nb_items: cluster.nb_items,
+				images: cluster.items,
+				bounds: cluster.bounds,
+				blowup_url: cluster.blowup_url
+				};
+		}
+
+		for (i=0; i<this._markers.length; i++)
+		{
+			this._map.removeOverlay( this._markers[i] );
+			google.maps.Event.clearListeners(this._markers[i], "click" );
+			google.maps.Event.clearListeners(this._markers[i], "dblclick" );
+		}
+
+		this._markers = newMarkers;
+
+		this._prevResult.nb_items=data.nb_items;
+	}
+
+	document.getElementById("dataLoadStatus").innerHTML = Localization.fmt1("%d images", data.nb_items);
+},
+
+_onMarkerClick: function( marker )
+{
+	if (this._map.getInfoWindow().pwgMarker == marker )
+		return; // already open
+	var content = "";
+	if ( !marker.currentImageIndex )
+		marker.currentImageIndex = 0;
+	content += '<div class="gmiw_header" style="' + (marker.pwg.images.length>1 ? '': 'display:none')+ '">';
+	content += '<span id="pwgImageCounters">'+this.buildCurrentPictureCounterHtml(marker)+'</span> ';
+	content += '<a href="javascript:void(0);" id="'+this._navHtmlIds[0]+'">';
+	content +=    '<span>'+ "&laquo; " + Localization.get('Prev') + '</span>';
+	content += '</a>';
+	content += " ";
+	content += '<a href="javascript:void(0);" id="'+this._navHtmlIds[1]+'">';
+	content +=    '<span>'+Localization.get('Next') + " &raquo;"+'</span>';
+	content += '</a>';
+	content += " ";
+	var imgShowAll = '';
+	if (this.options.show_all_img_src)
+		imgShowAll = '<img src="'+this.options.show_all_img_src+'" alt="" style="border:0" /> ';
+	content += '<a id="pwgImageBlowup" href="'+marker.pwg.blowup_url+'" onclick="return PwgDataHandler.blowupUrl(this.href);" title='+Localization.getQ('show all pictures around this location')+'>'+
+						imgShowAll+ '<span>'+Localization.get('Show all')+'</span>'+
+					'</a>';
+	content += '</div>';
+	content += '<div id="pwgImageDetail">' + this.buildCurrentPictureHtml( marker ) + '</div>';
+
+	marker.openInfoWindowHtml( content );
+
+	// bind to next / prev a little later because sometimes the nodes are not immediately created
+	if (this._timerBindPictureNavigation) clearTimeout(this._timerBindPictureNavigation);
+	this._timerBindPictureNavigation = null;
+	if (marker.pwg.images.length>1)
+		this._timerBindPictureNavigation = setTimeout( pwgBind(this, this._onTimeoutBindPictureNavigation, marker), 250 );
+},
+
+_onMarkerDblClick: function( marker )
+{
+	this._map.setCenter( marker.pwg.bounds.getCenter(), this._map.getBoundsZoomLevel( marker.pwg.bounds ) );
+},
+
+buildCurrentPictureHtml: function( marker )
+{
+	var imageDetail = marker.pwg.images[marker.currentImageIndex];
+	var res = "";
+	res += '<div class="gmiw_imageTitle">' + imageDetail.name + "</div>";
+	res +=
+'<div class="gmiw_imageContent">' +
+'<div class="gmiw_imageWrap">'+
+  '<a href="'+imageDetail.page_url+'">' +
+  '<img src="' + imageDetail.tn + '" alt="thumb" />'+
+'</a></div>' +
+'<div class="gmiw_imageComment">' + imageDetail.comment + '</div>' +
+'</div>';
+	return res;
+},
+
+buildCurrentPictureCounterHtml: function( marker )
+{
+	var res =
+		'<b>'+(marker.currentImageIndex+1)+'</b>'+
+		'/' +
+		'<b>'+marker.pwg.images.length+'</b>';
+	if (marker.pwg.nb_items>marker.pwg.images.length)
+		res+= " "+Localization.fmt1("out of %d", marker.pwg.nb_items );
+	return res;
+},
+
+
+_onTimeoutBindPictureNavigation: function( marker )
+{
+	clearTimeout(this._timerBindPictureNavigation);
+	this._timerBindPictureNavigation = null;
+	this._map.getInfoWindow().pwgMarker = marker;
+	for (var i=0; i< this._navHtmlIds.length; i++)
+	{
+		var elt = document.getElementById( this._navHtmlIds[i] );
+		if (elt)
+			google.maps.Event.addDomListener(elt, "click", pwgBind(this, this._onPictureNavigate, marker, i) );
+	}
+},
+
+_onPictureNavigate: function(marker, dir )
+{
+	if (dir==0) dir=-1;
+	marker.currentImageIndex += dir;
+	if (marker.currentImageIndex<0)
+		marker.currentImageIndex = marker.pwg.images.length-1;
+	else if (marker.currentImageIndex >= marker.pwg.images.length)
+		marker.currentImageIndex = 0;
+
+	try {
+		var elt = document.getElementById( "pwgImageDetail" );
+		elt.innerHTML = this.buildCurrentPictureHtml( marker );
+	}
+	catch (e)
+	{
+		alert (e.message);
+	}
+
+	try {
+		var elt = document.getElementById( "pwgImageCounters" );
+		elt.innerHTML = this.buildCurrentPictureCounterHtml( marker );
+	}
+	catch (e)
+	{
+		alert (e.message);
+	}
+	return false;
+}
+
+}
+
+PwgDataHandler.blowupUrl = function(theUrl)
+{
+	jQuery.fx.off = true;
+	jQuery.nyroModalManual( {
+		url: theUrl,
+		forceType: 'iframe',
+		width: 1920
+	});
+	return false;
+}
+
+
+String.prototype.urlNoHtm = function()
+{
+	return this.replace( "&amp;", "&" );
+}
Index: /extensions/rv_gmaps/branches/2.1/template/data_loader.js
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/data_loader.js	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/data_loader.js	(revision 8301)
@@ -0,0 +1,193 @@
+function PwgDataLoader( map, opts )
+{
+	this._map = map;
+	this.options = jQuery.fn.extend(
+		{
+			reload_data_timeout: 1800,
+			rectangle_of_confusion: G_DEFAULT_ICON.iconSize
+		}
+		, opts || {} );
+	this.options.rectangle_of_confusion = new google.maps.Size( this.options.rectangle_of_confusion.width, this.options.rectangle_of_confusion.height );
+	if (this.options.rectangle_of_confusion.width<16) this.options.rectangle_of_confusion.width=16;
+	if (this.options.rectangle_of_confusion.height<16) this.options.rectangle_of_confusion.height=16;
+}
+
+
+// returns the number of digits (between 0 and 6) to round a lat/lon so that it does not vary by more than factor*pow(-exp)
+getLatLonDigits = function(d, factor, exp)
+{
+	if (d<0) return getLatLonDigits(-d,factor,exp);
+	var digits = Math.ceil( exp - Math.log(d*factor)/Math.LN10 );
+	return digits<0 ? 0 : (digits>6 ? 6 : digits);
+}
+
+Math.roundN = function(d, digits) { var c = Math.pow(10,digits); return Math.round(d*c)/c; }
+
+
+PwgDataLoader.prototype =  {
+
+
+_urlMapData: null,
+_timerReloadData: null,
+_dataLoading: false,
+
+_previousLoadDataReq : {box: null, zoom:0, resultBounds:null},
+
+start: function(urlMapData)
+{
+	this._urlMapData = urlMapData;
+	google.maps.Event.bind( this._map, "movestart", this, this.clearTimerReloadData );
+	google.maps.Event.bind( this._map, "moveend", this, this._onMapMoveEnd );
+	this._loadData();
+},
+
+terminate: function()
+{
+	this.clearTimerReloadData();
+	this._map = null;
+},
+
+clearTimerReloadData : function()
+{
+	if (this._timerReloadData)
+	{
+		clearTimeout( this._timerReloadData );
+		this._timerReloadData = null;
+		return true;
+	}
+	return false;
+},
+
+_onMapMoveEnd: function()
+{
+	this.clearTimerReloadData();
+	this._timerReloadData = setTimeout(  pwgBind(this, this._onTimeoutLoadData), this.options.reload_data_timeout );
+},
+
+
+_onTimeoutLoadData: function ()
+{
+	if (this._dataLoading) return; // still in progress
+	this.clearTimerReloadData();
+	this._loadData();
+},
+
+_loadData: function()
+{
+	var bounds = this._map.getBounds();
+
+	var latRange = bounds.toSpan().lat();
+	var latPrec = latRange * this.options.rectangle_of_confusion.height / this._map.getSize().height;
+
+	var lonRange = bounds.toSpan().lng();
+	var lonPrec = ( lonRange>=0 ? lonRange : 360-lonRange )* this.options.rectangle_of_confusion.width / this._map.getSize().width;
+
+	if ( this._previousLoadDataReq.box!=null )
+	{ // not the first time
+		if ( this._previousLoadDataReq.box.containsBounds( bounds ) )
+		{
+			if ( this._previousLoadDataReq.resultBounds == null )
+				return; // no images here
+			if ( this._map.getZoom() <= this._previousLoadDataReq.zoom )
+				return;
+			else
+			{
+				if (
+					this._map.getZoom() == this._previousLoadDataReq.zoom + 1
+					&& this._map.getZoom() < this._map.getBoundsZoomLevel(this._previousLoadDataReq.resultBounds)
+					)
+				{
+					if (document.is_debug) google.maps.Log.write('no load: zoom crt: '+this._map.getZoom()+'; prev: '+this._previousLoadDataReq.zoom+'; target: '+this._map.getBoundsZoomLevel(this._previousLoadDataReq.resultBounds));
+					return;
+				}
+			}
+		}
+		else
+		{
+		}
+	}
+
+	var nd=0, sd=0, ed=0, wd=0;
+	if ( !bounds.isFullLat() )
+	{
+		nd = latRange*12/100;
+		sd = latRange*4/100;
+	}
+	if ( !bounds.isFullLng() )
+	{
+		ed = lonRange*9/100;
+		wd = lonRange*7/100;
+	}
+	var digits = Math.max( getLatLonDigits(latRange,4,2), getLatLonDigits(lonRange,4,2) );
+	var box = new google.maps.LatLngBounds( bounds.getSouthWest(), bounds.getNorthEast() );
+	box.extend( new google.maps.LatLng( Math.roundN(bounds.getSouthWest().lat()-sd,digits), Math.roundN( bounds.getSouthWest().lng()-wd,digits ) ) );
+	box.extend( new google.maps.LatLng( Math.roundN(bounds.getNorthEast().lat()+nd,digits), Math.roundN( bounds.getNorthEast().lng()+ed,digits) ) );
+
+	var url = this._urlMapData;
+	url += "&box=" + box.getSouthWest().toUrlValue(5) + "," + box.getNorthEast().toUrlValue(5);
+	url += "&lap=" +  Math.roundN( latPrec, getLatLonDigits(latPrec,1,1) ).toString();
+	url += "&lop=" +  Math.roundN( lonPrec, getLatLonDigits(lonPrec,1,1) ).toString();
+
+	if (document.is_debug) {
+		google.maps.Log.write("sd="+sd+" wd="+wd+" nd="+nd+" ed="+ed);
+		google.maps.Log.write( "bounds: " + this._map.getBounds().getSouthWest().toUrlValue() + " " + this._map.getBounds().getNorthEast().toUrlValue() +"; zoom: "+this._map.getZoom() +"; size: "+this._map.getSize().toString() +"; c: "+this._map.getCenter().toUrlValue() );
+		google.maps.Log.writeUrl( url );
+	}
+
+	this._previousLoadDataReq.box = box;
+	this._previousLoadDataReq.zoom = this._map.getZoom();
+	this._previousLoadDataReq.resultBounds = null;
+	this._dataLoading = true;
+
+	try {
+		google.maps.Event.trigger( this, "dataloading" );
+		jQuery.ajax( {
+			url: url,
+			success: pwgBind(this, this._onAjaxSuccess),
+			error: pwgBind(this, this._onAjaxError),
+			});
+	}
+	catch (e) {
+		this._dataLoading = false;
+		this._previousLoadDataReq.box=null;
+		google.maps.Event.trigger( this, "dataloadfailed", 600, e );
+	}
+},
+
+_onAjaxSuccess: function(data, textStatus, xhr)
+{
+	var resp;
+	try
+	{
+		eval('resp = ' + data);
+		if (resp.nb_items == undefined)
+			throw new Error( "DATA DECODING ERROR" );
+		this._previousLoadDataReq.resultBounds = resp.bounds;
+		if (document.is_debug && resp.debug) google.maps.Log.write( resp.debug );
+		google.maps.Event.trigger( this, "dataloaded", resp );
+	}
+	catch (e)	{
+		this._previousLoadDataReq.box=null;
+		google.maps.Event.trigger( this, "dataloadfailed", responseCode, e );
+		var s = e.message;
+		s += '\n' + data.substr(0,1000);
+		alert( s );
+	}
+	finally {
+		this._dataLoading = false;
+	}
+},
+
+_onAjaxError: function(xhr, textStatus, exc)
+{
+	try {
+		google.maps.Event.trigger( this, "dataloadfailed", textStatus + xhr.status, exc );
+	}
+	catch (e) {
+	}
+	finally {
+		this._dataLoading = false;
+	}
+},
+
+}
Index: /extensions/rv_gmaps/branches/2.1/template/earth_kml.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/earth_kml.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/earth_kml.tpl	(revision 8301)
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="{$CONTENT_ENCODING}"?>
+<kml xmlns="http://earth.google.com/kml/2.2">
+<Document>
+	<Style id="img_normal">
+		<IconStyle> 
+			<Icon><href>http://maps.google.com/mapfiles/kml/shapes/camera.png</href></Icon>
+			<scale>1</scale>
+		</IconStyle> 
+	</Style>
+	<Style id="img_highlight">
+		<IconStyle> 
+			<Icon><href>http://maps.google.com/mapfiles/kml/shapes/camera.png</href></Icon>
+			<scale>1</scale>
+		</IconStyle> 
+	</Style>
+	<StyleMap id="img">
+		<Pair>
+			<key>normal</key><styleUrl>#img_normal</styleUrl>
+		</Pair>
+		<Pair>
+			<key>highlight</key><styleUrl>#img_highlight</styleUrl>
+		</Pair>
+	</StyleMap>
+  <name><![CDATA[{$PAGE_TITLE}]]></name>
+  <description><![CDATA[{$NB_ITEMS_DESC|@default}<a href="{$U_INDEX}">{'Go to'|@translate} {$PAGE_TITLE}</a><br/>{$PAGE_COMMENT}
+]]></description>
+{if not empty($region)}
+<Region> 
+  <LatLonAltBox> 
+    <north>{$region.n}</north>
+    <south>{$region.s}</south>
+    <east>{$region.e}</east>
+    <west>{$region.w}</west>
+  </LatLonAltBox> 
+</Region> 
+{/if}
+
+{if not empty($categories)}
+{foreach from=$categories item=category}
+<NetworkLink>
+  <visibility>0</visibility>
+  <name><![CDATA[{$category.NAME}]]></name>
+  <description><![CDATA[{$category.COMMENT}
+	{if not empty($category.TN_SRC)}
+    <br/><img src="{$category.TN_SRC}" />
+	{/if}
+]]></description>
+  <Link>
+    <href>{$category.U_KML}</href>
+  </Link>   
+{if not empty($category.region)}
+  <Region>
+    <LatLonAltBox>
+      <north>{$category.region.n}</north>
+      <south>{$category.region.s}</south>
+      <east>{$category.region.e}</east>
+      <west>{$category.region.w}</west>
+    </LatLonAltBox>
+  </Region>
+  <TimeSpan>
+    <begin>{$category.region.min_date}</begin>
+    <end>{$category.region.max_date}</end>
+  </TimeSpan>
+{/if}
+</NetworkLink>
+{/foreach}
+{/if}
+
+{if not empty($images)}
+{foreach from=$images item=img}
+	<Placemark>
+		<visibility>1</visibility>
+		<open>1</open>
+		<name><![CDATA[{$img.TITLE}]]></name>
+		<Snippet>{$img.DESCRIPTION|@strip_tags:false|@truncate:80}</Snippet>
+		<description><![CDATA[
+{$img.DESCRIPTION}<br/>
+<a href="{$img.U_PAGE}"><img src="{$img.TN_SRC}"/></a><br/>
+]]></description>
+		<styleUrl>#img</styleUrl>
+		<Point>
+			<coordinates>{$img.LON},{$img.LAT},0</coordinates>
+		</Point>
+		{if not empty($img.date_creation)}
+		<TimeStamp>
+			<when>{$img.date_creation}</when>
+		</TimeStamp>
+		{/if}
+	</Placemark>
+{/foreach}
+{/if}
+</Document>
+</kml>
Index: /extensions/rv_gmaps/branches/2.1/template/map.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/map.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/map.tpl	(revision 8301)
@@ -0,0 +1,228 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset={$CONTENT_ENCODING}" />
+<meta name="robots" content="noindex,nofollow" />
+<title>{$GALLERY_TITLE}</title>
+<link rel="stylesheet" type="text/css" href="{$PLUGIN_ROOT_URL}/template/style.css?v={$RVM_PLUGIN_VERSION}" />
+<!--[if IE]>
+<style type="text/css">
+v\:* {ldelim}
+  behavior:url(#default#VML);
+}
+</style>
+<![endif]-->
+<!--[if lt IE 7]>
+<style type="text/css">
+	#map {ldelim} position:auto; height: 100%; }
+</style>
+<![endif]-->
+
+<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key={$GMAPS_API_KEY}&amp;hl={$lang_info.code}" type="text/javascript"></script>
+
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
+<script type="text/javascript">jQuery.noConflict();</script>
+<script src="{$PLUGIN_ROOT_URL}/template/nyroModal/jquery.nyroModal-1.6.2.js" type="text/javascript"></script>
+<link href="{$PLUGIN_ROOT_URL}/template/nyroModal/nyroModal.css" rel="stylesheet" type="text/css">
+
+<script src="{$PLUGIN_ROOT_URL}/template/data_loader.js?v={$RVM_PLUGIN_VERSION}" type="text/javascript"></script>
+<script src="{$PLUGIN_ROOT_URL}/template/data_handler.js?v={$RVM_PLUGIN_VERSION}" type="text/javascript"></script>
+<script src="{$PLUGIN_ROOT_URL}/template/page_linker.js?v={$RVM_PLUGIN_VERSION}" type="text/javascript"></script>
+
+<script src="{$ROOT_URL}themes/default/js/scripts.js" type="text/javascript"></script>
+
+<script type="text/javascript">{literal}
+//<![CDATA[
+var map;
+var geocoder;
+
+document.is_debug = false;
+if ( document.location.search.match(/[\?&]debug/) ) {
+	document.is_debug = true;
+	document._window = window;
+}
+  
+function load()
+{
+	if (!GBrowserIsCompatible())
+	return;
+
+	var mapElement = document.getElementById("map");
+	map = new google.maps.Map2( mapElement );
+
+	map.addMapType( G_PHYSICAL_MAP );
+	map.addControl(new google.maps.LargeMapControl3D());
+	map.addControl(new google.maps.HierarchicalMapTypeControl());
+	map.addControl(new google.maps.ScaleControl());
+
+	pwgPageLinker = new PageLinker(map, "aLinkToThisPage" );
+	if ( !map.isLoaded() )
+	{
+{/literal}
+		{if isset($initial_bounds)}
+		var bounds = new google.maps.LatLngBounds( new google.maps.LatLng({$initial_bounds.s},{$initial_bounds.w}), new google.maps.LatLng({$initial_bounds.n},{$initial_bounds.e}) );
+		map.setCenter( bounds.getCenter(), map.getBoundsZoomLevel( bounds ) );
+		{/if}
+{literal}
+		if ( !map.isLoaded() )
+			map.setCenter( new google.maps.LatLng(0,0), 2 );
+	}
+
+	try {
+		// the overview must be added after setting map center
+		var ovcontrol = new google.maps.OverviewMapControl(new google.maps.Size(165,165));
+		map.addControl(ovcontrol);
+	}
+	catch(e){ alert( e.message ); }
+
+	map.enableScrollWheelZoom();
+	map.enableDoubleClickZoom();
+
+	var pwgMarkerIcon = (function(){ {/literal}{$MAP_MARKER_ICON_JS}{literal} }).call(null);
+
+	map.pwgDataLoader = new PwgDataLoader(map, {rectangle_of_confusion: pwgMarkerIcon.iconSize} );
+	google.maps.Event.addListener(map.pwgDataLoader, "dataloading", function() {
+		var pre = '<img src="{/literal}{$PLUGIN_ROOT_URL}{literal}/icons/progress_s.gif" width="16" height="16" alt="~" /> ';
+		document.getElementById("dataLoadStatus").innerHTML = pre + Localization.get("Loading");
+		}
+	);
+  
+	google.maps.Event.addListener(map.pwgDataLoader, "dataloadfailed", function(responseCode) {
+		document.getElementById("dataLoadStatus").innerHTML = Localization.get("Failed") + " "+responseCode;
+		}
+		);
+
+	map.pwgDataHandler = new PwgDataHandler(map, {icon: pwgMarkerIcon, show_all_img_src: "{/literal}{$PLUGIN_ROOT_URL}{literal}/icons/pic_s.gif" } );
+	google.maps.Event.addListener(map.pwgDataLoader, "dataloaded", pwgBind(map.pwgDataHandler, map.pwgDataHandler.handle) );
+
+	map.pwgDataLoader.start( "{/literal}{$U_MAP_DATA}{literal}" );
+
+	if (document.is_debug)
+	{
+		google.maps.Event.addListener(map, "moveend", function() { google.maps.Log.write("movend c:"+map.getCenter().toUrlValue());} );
+		google.maps.Event.addListener(map, "maptypechanged", function() { google.maps.Log.write("maptypechanged");} );
+		google.maps.Event.addListener(map, "infowindowopen", function() { google.maps.Log.write("infowindowopen");} );
+		google.maps.Event.addListener(map, "infowindowclose", function() { google.maps.Log.write("infowindowclose");} );
+	}
+}
+
+function unload()
+{
+	if (map)
+	{
+		!map.pwgDataLoader || map.pwgDataLoader.terminate();
+		!map.pwgDataHandler || map.pwgDataHandler.terminate();
+	}
+	GUnload();
+}
+
+function searchLocation(q)
+{
+	if (!q.length) return false;
+	if (!geocoder)
+		geocoder = new google.maps.ClientGeocoder();
+	geocoder.getLocations(q, function(resp)
+	  {
+		if ( resp && resp.Status )
+		{
+		  document._geoResponse = resp;
+		  if (resp.Status.code==200)
+		  {
+			var zoom = 2;
+			switch (resp.Placemark[0].AddressDetails.Accuracy)
+			{
+			  case 1: zoom=5; break; //country
+			  case 2: zoom=7; break; //region
+			  case 3: zoom=8; break; //county
+			  case 4: zoom=12; break; //town
+			  case 5: zoom=13; break; //post code
+			  case 6: zoom=14; break; //street
+			  case 7: case 8: zoom=16; break; //intersection/exact
+			}
+			map.setCenter( new google.maps.LatLng( resp.Placemark[0].Point.coordinates[1], resp.Placemark[0].Point.coordinates[0] ), zoom);
+		  }
+		  else
+			alert("This address has not been found\nCode:"+resp.Status.code);
+		}
+	  });
+	return false;
+}
+
+
+var Localization =
+{
+  _strings: {
+{/literal}
+"go to %s": "{'go to %s'|@translate|@escape:javascript}",
+"Next": "{'Next'|@translate|@escape:javascript}",
+"Prev": "{'Prev'|@translate|@escape:javascript}",
+"out of %d": "{'out of %d'|@translate|@escape:javascript}",
+"Loading": "{'Loading'|@translate|@escape:javascript}",
+"Failed": "{'Failed'|@translate|@escape:javascript}",
+"Show all": "{'Show all'|@translate|@escape:javascript}",
+"show all pictures around this location": "{'show all pictures around this location'|@translate|@escape:javascript}",
+"displays %s on a map" : "{'displays %s on a map'|@translate|@escape:javascript}",
+"opens %s in Google Earth" : "{'opens %s in Google Earth'|@translate|@escape:javascript}",
+"%d images" : "{'%d images'|@translate|@escape:javascript}",
+{literal}
+dontMindTheComma: ""
+    },
+
+  get: function( str ) {
+		var lang_str = this._strings[str];
+		if (lang_str == undefined)
+		{
+			if (document.is_debug) google.maps.Log.write("Language string undefined '"+ str+"'");
+			return str;
+		}
+		return lang_str;
+	},
+
+  getQ: function( str ) {
+		return '"'+this.get(str)+'"';
+	},
+
+  fmt1: function () {
+		var str = arguments[0];
+		str = this.get(str);
+		str = str.replace( '%s', "%" ).replace( '%d', "%" ).replace('%', arguments[1]);
+		return str;
+		
+	}
+}
+{/literal}
+//]]>
+</script>
+</head>
+
+<body onload="load()" onunload="unload()">
+
+<div id="titlebar">
+  <div class="titlebar_links" >
+    <span id="dataLoadStatus"></span>
+    <a id="aKml" href="" type="application/vnd.google-earth.kml+xml" class="gmnoprint"><img src="http://maps.google.com/mapfiles/ms/view_as_kml.png" width="16" height="16" alt="kml" /> <span>KML</span></a>
+    <a id="aLinkToThisPage" href="" class="gmnoprint"><img src="http://maps.google.com/mapfiles/bar_icon_link.gif" alt="&lt;-&gt;" width="16" height="16" /> <span>{'Link to this page'|@translate}</span></a>
+    <a id="aBlowup" href="" onclick="return PwgDataHandler.blowupUrl(this.href);" class="gmnoprint" title="{'show all pictures around this location'|@translate}">
+			<img src="{$PLUGIN_ROOT_URL}/icons/pic_s.gif" alt="" title="{'show all pictures around this location'|@translate}" />
+			<span>{'Show all'|@translate}</span>
+		</a>
+    <span class="gmnoprint">
+			<form action="#" onsubmit="if (this.q.value!='' &amp;&amp; this.q.value!='{'Search a location...'|@translate|@escape:javascript}') searchLocation(this.q.value);return false;">
+				<input type="text" size="32" name="q"
+					value="{'Search a location...'|@translate}"
+					onfocus="if (value=='{'Search a location...'|@translate|@escape:javascript}') value='';"
+					onblur="if (value=='') value='{'Search a location...'|@translate|@escape:javascript}'" />
+				<input type="submit" value="{'Search'|@translate}"/>
+			</form>
+		</span>
+  </div>
+  <div class="titlebar_title">
+    <a href="{$U_HOME}" title="{'return to homepage'|@translate}" class="gmnoprint">{'Home'|@translate}</a>
+    <a href="{$U_HOME_MAP}" title="{'displays all images on a map'|@translate}"><img src="{$PLUGIN_ROOT_URL}/icons/map_sw.gif" width="32" height="17" alt="map"/></a>
+    {'Viewing'|@translate}: <a id="aPageUrl" href=""></a>
+  </div>
+</div>
+
+<div id="map"> </div>
+</body>
+</html>
Index: /extensions/rv_gmaps/branches/2.1/template/mapl.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/mapl.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/mapl.tpl	(revision 8301)
@@ -0,0 +1,63 @@
+{html_head}
+<style type="text/css">
+.fullTagCloud {ldelim}
+	text-align: justify;
+	padding: 0;
+	margin: 0.5em 1em 0.5em 1em;
+}
+.fullTagCloud LI {ldelim}
+	display: inline;white-space: nowrap;
+}
+</style>
+{/html_head}
+
+<div id="content" class="content" style="margin: 0;">
+	<div class="titrePage">
+		<ul class="categoryActions">
+			<li><a href="{$U_KML}" title="{$KML_LINK_TITLE}" rel="nofollow" type="application/vnd.google-earth.kml+xml"><img src="{$PLUGIN_ROOT_URL}/icons/earth_m.png" class="button" alt="earth"></a></li>
+			<li><a target="_top" href="{$U_HOME}" title="{'return to homepage'|@translate}"><img src="{$ROOT_URL}{$themeconf.icon_dir}/home.png" class="button" alt="{'Home'|@translate}"/></a></li>
+		</ul>
+		<h2>{$TITLE}</h2>
+	</div>
+
+{assign var='displays_x_on_a_map' value='displays %s on a map'|@translate }
+{if not empty($related_categories)}
+	<ul class="fullTagCloud">
+		<li>{'Categories'|@translate}:</li>
+		{foreach from=$related_categories item=cat}
+		<li>{strip}
+			<a target="_top" href="{$cat.URL}" class="{$cat.CLASS}" title="{$cat.TITLE}">{$cat.NAME}</a>
+			<a target="_top" href="{$cat.U_MAP}" title="{$pwg->sprintf($displays_x_on_a_map, $cat.NAME)}" ><img src="{$PLUGIN_ROOT_URL}/icons/map_s.png" alt="map" class="button" /></a>
+		{/strip}</li>&nbsp;
+		{/foreach}
+	</ul>
+{/if}
+
+{if not empty($related_tags)}
+	<ul class="fullTagCloud">
+		<li>{'Tags'|@translate}:</li>
+		{foreach from=$related_tags item=tag}
+		<li>{strip}
+			<a target="_top" href="{$tag.URL}" class="tagLevel{$tag.level}{$tag.radu_class|@default}" title="{$tag.TITLE}">{$tag.name}</a>
+			<a target="_top" href="{$tag.U_MAP}" title="{$pwg->sprintf($displays_x_on_a_map, $tag.name)}"><img src="{$PLUGIN_ROOT_URL}/icons/map_s.png" alt="map" class="button" /></a>
+		{/strip}</li>&nbsp;
+		{/foreach}
+	</ul>
+{/if}
+
+{if !empty($navbar) }{include file='navigation_bar.tpl'}{/if}
+
+{if not empty($thumbnails)}
+<ul class="thumbnails">
+	{foreach from=$thumbnails item=thumbnail}
+	<li><span class="wrap1"><span class="wrap2">
+			<a href="{$thumbnail.URL}" title="{$thumbnail.TN_TITLE}">
+				<img class="thumbnail" src="{$thumbnail.TN_SRC}" alt="{$thumbnail.TN_ALT}" />
+			</a>
+			</span></span>
+	</li>
+	{/foreach}
+</ul>
+{/if}
+
+</div>
Index: /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_orange.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_orange.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_orange.tpl	(revision 8301)
@@ -0,0 +1,6 @@
+var icon = new google.maps.Icon();
+icon.image = "{$PLUGIN_ROOT_URL}/template/markers/small_bullet_orange.png";
+icon.iconSize = new google.maps.Size(11, 11);
+icon.iconAnchor = new google.maps.Point(5, 5);
+icon.infoWindowAnchor = new google.maps.Point(5, 0);
+return icon;
Index: /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_red.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_red.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_red.tpl	(revision 8301)
@@ -0,0 +1,6 @@
+var icon = new google.maps.Icon();
+icon.image = "{$PLUGIN_ROOT_URL}/template/markers/small_bullet_red.png";
+icon.iconSize = new google.maps.Size(11, 11);
+icon.iconAnchor = new google.maps.Point(5, 5);
+icon.infoWindowAnchor = new google.maps.Point(5, 0);
+return icon;
Index: /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_yellow.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_yellow.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/markers/small_bullet_yellow.tpl	(revision 8301)
@@ -0,0 +1,6 @@
+var icon = new google.maps.Icon();
+icon.image = "{$PLUGIN_ROOT_URL}/template/markers/small_bullet_yellow.png";
+icon.iconSize = new google.maps.Size(11, 11);
+icon.iconAnchor = new google.maps.Point(5, 5);
+icon.infoWindowAnchor = new google.maps.Point(5, 0);
+return icon;
Index: /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_blue.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_blue.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_blue.tpl	(revision 8301)
@@ -0,0 +1,8 @@
+var icon = new google.maps.Icon();
+icon.image = "http://labs.google.com/ridefinder/images/mm_20_blue.png";
+icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
+icon.iconSize = new google.maps.Size(12, 20);
+icon.shadowSize = new google.maps.Size(22, 20);
+icon.iconAnchor = new google.maps.Point(6, 20);
+icon.infoWindowAnchor = new google.maps.Point(5, 1);
+return icon;
Index: /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_green.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_green.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_green.tpl	(revision 8301)
@@ -0,0 +1,8 @@
+var icon = new google.maps.Icon();
+icon.image = "http://labs.google.com/ridefinder/images/mm_20_green.png";
+icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
+icon.iconSize = new google.maps.Size(12, 20);
+icon.shadowSize = new google.maps.Size(22, 20);
+icon.iconAnchor = new google.maps.Point(6, 20);
+icon.infoWindowAnchor = new google.maps.Point(5, 1);
+return icon;
Index: /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_purple.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_purple.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_purple.tpl	(revision 8301)
@@ -0,0 +1,8 @@
+var icon = new google.maps.Icon();
+icon.image = "http://labs.google.com/ridefinder/images/mm_20_purple.png";
+icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
+icon.iconSize = new google.maps.Size(12, 20);
+icon.shadowSize = new google.maps.Size(22, 20);
+icon.iconAnchor = new google.maps.Point(6, 20);
+icon.infoWindowAnchor = new google.maps.Point(5, 1);
+return icon;
Index: /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_red.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_red.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/markers/small_dot_red.tpl	(revision 8301)
@@ -0,0 +1,8 @@
+var icon = new google.maps.Icon();
+icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
+icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
+icon.iconSize = new google.maps.Size(12, 20);
+icon.shadowSize = new google.maps.Size(22, 20);
+icon.iconAnchor = new google.maps.Point(6, 20);
+icon.infoWindowAnchor = new google.maps.Point(5, 1);
+return icon;
Index: /extensions/rv_gmaps/branches/2.1/template/nyroModal/jquery.nyroModal-1.6.2.js
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/nyroModal/jquery.nyroModal-1.6.2.js	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/nyroModal/jquery.nyroModal-1.6.2.js	(revision 8301)
@@ -0,0 +1,1707 @@
+/*
+ * nyroModal - jQuery Plugin
+ * http://nyromodal.nyrodev.com
+ *
+ * Copyright (c) 2010 Cedric Nirousset (nyrodev.com)
+ * Licensed under the MIT license
+ *
+ * $Date: 2010-02-23 (Tue, 23 Feb 2010) $
+ * $version: 1.6.2
+ */
+jQuery(function($) {
+
+	// -------------------------------------------------------
+	// Private Variables
+	// -------------------------------------------------------
+
+	var userAgent = navigator.userAgent.toLowerCase();
+	var browserVersion = (userAgent.match(/.+(?:rv|webkit|khtml|opera|msie)[\/: ]([\d.]+)/ ) || [0,'0'])[1];
+
+	var isIE6 = (/msie/.test(userAgent) && !/opera/.test(userAgent) && parseInt(browserVersion) < 7 && (!window.XMLHttpRequest || typeof(XMLHttpRequest) === 'function'));
+	var body = $('body');
+
+	var currentSettings;
+	var callingSettings;
+
+	var shouldResize = false;
+
+	var gallery = {};
+
+	// To know if the fix for the Issue 10 should be applied (or has been applied)
+	var fixFF = false;
+
+	// Used for retrieve the content from an hidden div
+	var contentElt;
+	var contentEltLast;
+
+	// Contains info about nyroModal state and all div references
+	var modal = {
+		started: false,
+		ready: false,
+		dataReady: false,
+		anim: false,
+		animContent: false,
+		loadingShown: false,
+		transition: false,
+		resizing: false,
+		closing: false,
+		error: false,
+		blocker: null,
+		blockerVars: null,
+		full: null,
+		bg: null,
+		loading: null,
+		tmp: null,
+		content: null,
+		wrapper: null,
+		contentWrapper: null,
+		scripts: new Array(),
+		scriptsShown: new Array()
+	};
+
+	// Indicate of the height or the width was resized, to reinit the currentsettings related to null
+	var resized = {
+		width: false,
+		height: false,
+		windowResizing: false
+	};
+
+	var initSettingsSize = {
+		width: null,
+		height: null,
+		windowResizing: true
+	};
+
+	var windowResizeTimeout;
+
+
+	// -------------------------------------------------------
+	// Public function
+	// -------------------------------------------------------
+
+	// jQuery extension function. A paramater object could be used to overwrite the default settings
+	$.fn.nyroModal = function(settings) {
+		if (!this)
+			return false;
+		return this.each(function() {
+			var me = $(this);
+			if (this.nodeName.toLowerCase() == 'form') {
+				me
+				.unbind('submit.nyroModal')
+				.bind('submit.nyroModal', function(e) {
+					if(e.isDefaultPrevented())
+						return false;
+					if (me.data('nyroModalprocessing'))
+						return true;
+					if (this.enctype == 'multipart/form-data') {
+						processModal($.extend(settings, {
+							from: this
+						}));
+						return true;
+					}
+					e.preventDefault();
+					processModal($.extend(settings, {
+						from: this
+					}));
+					return false;
+				});
+			} else {
+				me
+				.unbind('click.nyroModal')
+				.bind('click.nyroModal', function(e) {
+					if(e.isDefaultPrevented())
+						return false;
+					e.preventDefault();
+					processModal($.extend(settings, {
+						from: this
+					}));
+					return false;
+				});
+			}
+		});
+	};
+
+	// jQuery extension function to call manually the modal. A paramater object could be used to overwrite the default settings
+	$.fn.nyroModalManual = function(settings) {
+		if (!this.length)
+			processModal(settings);
+		return this.each(function(){
+			processModal($.extend(settings, {
+				from: this
+			}));
+		});
+	};
+
+	$.nyroModalManual = function(settings) {
+		processModal(settings);
+	};
+
+	// Update the current settings
+	// object settings
+	// string deep1 first key where overwrite the settings
+	// string deep2 second key where overwrite the settings
+	$.nyroModalSettings = function(settings, deep1, deep2) {
+		setCurrentSettings(settings, deep1, deep2);
+		if (!deep1 && modal.started) {
+			if (modal.bg && settings.bgColor)
+				currentSettings.updateBgColor(modal, currentSettings, function(){});
+
+			if (modal.contentWrapper && settings.title)
+				setTitle();
+
+			if (!modal.error && (settings.windowResizing || (!modal.resizing && (('width' in settings && settings.width == currentSettings.width) || ('height' in settings && settings.height == currentSettings.height))))) {
+				modal.resizing = true;
+				if (modal.contentWrapper)
+					calculateSize(true);
+				if (modal.contentWrapper && modal.contentWrapper.is(':visible') && !modal.animContent) {
+					if (fixFF)
+						modal.content.css({position: ''});
+					currentSettings.resize(modal, currentSettings, function() {
+						currentSettings.windowResizing = false;
+						modal.resizing = false;
+						if (fixFF)
+							modal.content.css({position: 'fixed'});
+						if ($.isFunction(currentSettings.endResize))
+							currentSettings.endResize(modal, currentSettings);
+					});
+				}
+			}
+		}
+	};
+
+	// Remove the modal function
+	$.nyroModalRemove = function() {
+		removeModal();
+	};
+
+	// Go to the next image for a gallery
+	// return false if nothing was done
+	$.nyroModalNext = function() {
+		var link = getGalleryLink(1);
+		if (link)
+			return link.nyroModalManual(getCurrentSettingsNew());
+		return false;
+	};
+
+	// Go to the previous image for a gallery
+	// return false if nothing was done
+	$.nyroModalPrev = function() {
+		var link = getGalleryLink(-1);
+		if (link)
+			return link.nyroModalManual(getCurrentSettingsNew());
+		return false;
+	};
+
+
+	// -------------------------------------------------------
+	// Default Settings
+	// -------------------------------------------------------
+
+	$.fn.nyroModal.settings = {
+		debug: false, // Show the debug in the background
+
+		blocker: false, // Element which will be blocked by the modal
+		
+		windowResize: true, // indicates if the modal should resize when the window is resized
+
+		modal: false, // Esc key or click backgrdound enabling or not
+
+		type: '', // nyroModal type (form, formData, iframe, image, etc...)
+		forceType: null, // Used to force the type
+		from: '', // Dom object where the call come from
+		hash: '', // Eventual hash in the url
+
+		processHandler: null, // Handler just before the real process
+
+		selIndicator: 'nyroModalSel', // Value added when a form or Ajax is sent with a filter content
+
+		formIndicator: 'nyroModal', // Value added when a form is sent
+
+		content: null, // Raw content if type content is used
+
+		bgColor: '#000000', // Background color
+
+		ajax: {}, // Ajax option (url, data, type, success will be overwritten for a form, url and success only for an ajax call)
+
+		swf: { // Swf player options if swf type is used.
+			wmode: 'transparent'
+		},
+
+		width: null, // default Width If null, will be calculate automatically
+		height: null, // default Height If null, will be calculate automatically
+
+		minWidth: 400, // Minimum width
+		minHeight: 300, // Minimum height
+
+		resizable: true, // Indicate if the content is resizable. Will be set to false for swf
+		autoSizable: true, // Indicate if the content is auto sizable. If not, the min size will be used
+
+		padding: 25, // padding for the max modal size
+
+		regexImg: '[^\.]\.(jpg|jpeg|png|tiff|gif|bmp)\s*$', // Regex to find images
+		addImageDivTitle: false, // Indicate if the div title should be inserted
+		defaultImgAlt: 'Image', // Default alt attribute for the images
+		setWidthImgTitle: true, // Set the width to the image title
+		ltr: true, // Left to Right by default. Put to false for Hebrew or Right to Left language
+
+		gallery: null, // Gallery name if provided
+		galleryLinks: '<a href="#" class="nyroModalPrev">Prev</a><a href="#"  class="nyroModalNext">Next</a>', // Use .nyroModalPrev and .nyroModalNext to set the navigation link
+		galleryCounts: galleryCounts, // Callback to show the gallery count
+		galleryLoop: false, // Indicate if the gallery should loop
+
+		zIndexStart: 100,
+
+		cssOpt: { // Default CSS option for the nyroModal Div. Some will be overwritten or updated when using IE6
+			bg: {
+				position: 'absolute',
+				overflow: 'hidden',
+				top: 0,
+				left: 0,
+				height: '100%',
+				width: '100%'
+			},
+			wrapper: {
+				position: 'absolute',
+				top: '50%',
+				left: '50%'
+			},
+			wrapper2: {
+			},
+			content: {
+			},
+			loading: {
+				position: 'absolute',
+				top: '50%',
+				left: '50%',
+				marginTop: '-50px',
+				marginLeft: '-50px'
+			}
+		},
+
+		wrap: { // Wrapper div used to style the modal regarding the content type
+			div: '<div class="wrapper"></div>',
+			ajax: '<div class="wrapper"></div>',
+			form: '<div class="wrapper"></div>',
+			formData: '<div class="wrapper"></div>',
+			image: '<div class="wrapperImg"></div>',
+			swf: '<div class="wrapperSwf"></div>',
+			iframe: '<div class="wrapperIframe"></div>',
+			iframeForm: '<div class="wrapperIframe"></div>',
+			manual: '<div class="wrapper"></div>'
+		},
+
+		closeButton: '<a href="#" class="nyroModalClose" id="closeBut" title="close">Close</a>', // Adding automaticly as the first child of #nyroModalWrapper
+
+		title: null, // Modal title
+		titleFromIframe: true, // When using iframe in the same domain, try to get the title from it
+
+		openSelector: '.nyroModal', // selector for open a new modal. will be used to parse automaticly at page loading
+		closeSelector: '.nyroModalClose', // selector to close the modal
+
+		contentLoading: '<a href="#" class="nyroModalClose">Cancel</a>', // Loading div content
+
+		errorClass: 'error', // CSS Error class added to the loading div in case of error
+		contentError: 'The requested content cannot be loaded.<br />Please try again later.<br /><a href="#" class="nyroModalClose">Close</a>', // Content placed in the loading div in case of error
+
+		handleError: null, // Callback in case of error
+
+		showBackground: showBackground, // Show background animation function
+		hideBackground: hideBackground, // Hide background animation function
+
+		endFillContent: null, // Will be called after filling and wraping the content, before parsing closeSelector and openSelector and showing the content
+		showContent: showContent, // Show content animation function
+		endShowContent: null, // Will be called once the content is shown
+		beforeHideContent: null, // Will be called just before the modal closing
+		hideContent: hideContent, // Hide content animation function
+
+		showTransition: showTransition, // Show the transition animation (a modal is already shown and a new one is requested)
+		hideTransition: hideTransition, // Hide the transition animation to show the content
+
+		showLoading: showLoading, // show loading animation function
+		hideLoading: hideLoading, // hide loading animation function
+
+		resize: resize, // Resize animation function
+		endResize: null, // Will be called one the content is resized
+
+		updateBgColor: updateBgColor, // Change background color animation function
+
+		endRemove: null // Will be called once the modal is totally gone
+	};
+
+	// -------------------------------------------------------
+	// Private function
+	// -------------------------------------------------------
+
+	// Main function
+	function processModal(settings) {
+		if (modal.loadingShown || modal.transition || modal.anim)
+			return;
+		debug('processModal');
+		modal.started = true;
+		callingSettings = $.extend(true, settings);
+		setDefaultCurrentSettings(settings);
+		if (!modal.full)
+			modal.blockerVars = modal.blocker = null;
+		modal.error = false;
+		modal.closing = false;
+		modal.dataReady = false;
+		modal.scripts = new Array();
+		modal.scriptsShown = new Array();
+
+		currentSettings.type = fileType();
+		if (currentSettings.forceType) {
+			if (!currentSettings.content)
+				currentSettings.from = true;
+			currentSettings.type = currentSettings.forceType;
+			currentSettings.forceType = null;
+		}
+
+		if ($.isFunction(currentSettings.processHandler))
+			currentSettings.processHandler(currentSettings);
+
+		var from = currentSettings.from;
+		var url = currentSettings.url;
+
+		initSettingsSize.width = currentSettings.width;
+		initSettingsSize.height = currentSettings.height;
+
+		if (currentSettings.type == 'swf') {
+			// Swf is transforming as a raw content
+			setCurrentSettings({overflow: 'visible'}, 'cssOpt', 'content');
+			currentSettings.content = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+currentSettings.width+'" height="'+currentSettings.height+'"><param name="movie" value="'+url+'"></param>';
+			var tmp = '';
+			$.each(currentSettings.swf, function(name, val) {
+				currentSettings.content+= '<param name="'+name+'" value="'+val+'"></param>';
+				tmp+= ' '+name+'="'+val+'"';
+			});
+			currentSettings.content+= '<embed src="'+url+'" type="application/x-shockwave-flash" width="'+currentSettings.width+'" height="'+currentSettings.height+'"'+tmp+'></embed></object>';
+		}
+
+		if (from) {
+			var jFrom = $(from).blur();
+			if (currentSettings.type == 'form') {
+				var data = $(from).serializeArray();
+				data.push({name: currentSettings.formIndicator, value: 1});
+				if (currentSettings.selector)
+					data.push({name: currentSettings.selIndicator, value: currentSettings.selector.substring(1)});
+				showModal();
+				$.ajax($.extend({}, currentSettings.ajax, {
+						url: url,
+						data: data,
+						type: jFrom.attr('method') ? jFrom.attr('method') : 'get',
+						success: ajaxLoaded,
+						error: loadingError
+					}));
+				debug('Form Ajax Load: '+jFrom.attr('action'));
+			} else if (currentSettings.type == 'formData') {
+				// Form with data. We're using a hidden iframe
+				initModal();
+				jFrom.attr('target', 'nyroModalIframe');
+				jFrom.attr('action', url);
+				jFrom.prepend('<input type="hidden" name="'+currentSettings.formIndicator+'" value="1" />');
+				if (currentSettings.selector)
+					jFrom.prepend('<input type="hidden" name="'+currentSettings.selIndicator+'" value="'+currentSettings.selector.substring(1)+'" />');
+				modal.tmp.html('<iframe frameborder="0" hspace="0" name="nyroModalIframe" src="javascript:\'\';"></iframe>');
+				$('iframe', modal.tmp)
+					.css({
+						width: currentSettings.width,
+						height: currentSettings.height
+					})
+					.error(loadingError)
+					.load(formDataLoaded);
+				debug('Form Data Load: '+jFrom.attr('action'));
+				showModal();
+				showContentOrLoading();
+			} else if (currentSettings.type == 'image') {
+				debug('Image Load: '+url);
+				var title = jFrom.attr('title') || currentSettings.defaultImgAlt;
+				initModal();
+				modal.tmp.html('<img id="nyroModalImg" />').find('img').attr('alt', title);
+				modal.tmp.css({lineHeight: 0});
+				$('img', modal.tmp)
+					.error(loadingError)
+					.load(function() {
+						debug('Image Loaded: '+this.src);
+						$(this).unbind('load');
+						var w = modal.tmp.width();
+						var h = modal.tmp.height();
+						modal.tmp.css({lineHeight: ''});
+						resized.width = w;
+						resized.height = h;
+						setCurrentSettings({
+							width: w,
+							height: h,
+							imgWidth: w,
+							imgHeight: h
+						});
+						initSettingsSize.width = w;
+						initSettingsSize.height = h;
+						setCurrentSettings({overflow: 'visible'}, 'cssOpt', 'content');
+						modal.dataReady = true;
+						if (modal.loadingShown || modal.transition)
+							showContentOrLoading();
+					})
+					.attr('src', url);
+				showModal();
+			} else if (currentSettings.type == 'iframeForm') {
+				initModal();
+				modal.tmp.html('<iframe frameborder="0" hspace="0" src="javascript:\'\';" name="nyroModalIframe" id="nyroModalIframe"></iframe>');
+				debug('Iframe Form Load: '+url);
+				$('iframe', modal.tmp).eq(0)
+					.css({
+						width: '100%',
+						height: $.support.boxModel? '99%' : '100%'
+					})
+					.load(iframeLoaded);
+				modal.dataReady = true;
+				showModal();
+			} else if (currentSettings.type == 'iframe') {
+				initModal();
+				modal.tmp.html('<iframe frameborder="0" hspace="0" src="javascript:\'\';" name="nyroModalIframe" id="nyroModalIframe"></iframe>');
+				debug('Iframe Load: '+url);
+				$('iframe', modal.tmp).eq(0)
+					.css({
+						width: '100%',
+						height: $.support.boxModel? '99%' : '100%'
+					})
+					.load(iframeLoaded);
+				modal.dataReady = true;
+				showModal();
+			} else if (currentSettings.type) {
+				// Could be every other kind of type or a dom selector
+				debug('Content: '+currentSettings.type);
+				initModal();
+				modal.tmp.html(currentSettings.content);
+				var w = modal.tmp.width();
+				var h = modal.tmp.height();
+				var div = $(currentSettings.type);
+				if (div.length) {
+					setCurrentSettings({type: 'div'});
+					w = div.width();
+					h = div.height();
+					if (contentElt)
+						contentEltLast = contentElt;
+					contentElt = div;
+					modal.tmp.append(div.contents());
+				}
+				initSettingsSize.width = w;
+				initSettingsSize.height = h;
+				setCurrentSettings({
+					width: w,
+					height: h
+				});
+				if (modal.tmp.html())
+					modal.dataReady = true;
+				else
+					loadingError();
+				if (!modal.ready)
+					showModal();
+				else
+					endHideContent();
+			} else {
+				debug('Ajax Load: '+url);
+				setCurrentSettings({type: 'ajax'});
+				var data = currentSettings.ajax.data || {};
+				if (currentSettings.selector) {
+					if (typeof data == "string") {
+						data+= '&'+currentSettings.selIndicator+'='+currentSettings.selector.substring(1);
+					} else {
+						data[currentSettings.selIndicator] = currentSettings.selector.substring(1);
+					}
+				}
+				showModal();
+				$.ajax($.extend(true, currentSettings.ajax, {
+					url: url,
+					success: ajaxLoaded,
+					error: loadingError,
+					data: data
+				}));
+			}
+		} else if (currentSettings.content) {
+			// Raw content not from a DOM element
+			debug('Content: '+currentSettings.type);
+			setCurrentSettings({type: 'manual'});
+			initModal();
+			modal.tmp.html($('<div/>').html(currentSettings.content).contents());
+			if (modal.tmp.html())
+				modal.dataReady = true;
+			else
+				loadingError();
+			showModal();
+		} else {
+			// What should we show here? nothing happen
+		}
+	}
+
+	// Update the current settings
+	// object settings
+	// string deep1 first key where overwrite the settings
+	// string deep2 second key where overwrite the settings
+	function setDefaultCurrentSettings(settings) {
+		debug('setDefaultCurrentSettings');
+		currentSettings = $.extend(true, {}, $.fn.nyroModal.settings, settings);
+		setMargin();
+	}
+
+	function setCurrentSettings(settings, deep1, deep2) {
+		if (modal.started) {
+			if (deep1 && deep2) {
+				$.extend(true, currentSettings[deep1][deep2], settings);
+			} else if (deep1) {
+				$.extend(true, currentSettings[deep1], settings);
+			} else {
+				if (modal.animContent) {
+					if ('width' in settings) {
+						if (!modal.resizing) {
+							settings.setWidth = settings.width;
+							shouldResize = true;
+						}
+						delete settings['width'];
+					}
+					if ('height' in settings) {
+						if (!modal.resizing) {
+							settings.setHeight = settings.height;
+							shouldResize = true;
+						}
+						delete settings['height'];
+					}
+				}
+				$.extend(true, currentSettings, settings);
+			}
+		} else {
+			if (deep1 && deep2) {
+				$.extend(true, $.fn.nyroModal.settings[deep1][deep2], settings);
+			} else if (deep1) {
+				$.extend(true, $.fn.nyroModal.settings[deep1], settings);
+			} else {
+				$.extend(true, $.fn.nyroModal.settings, settings);
+			}
+		}
+	}
+
+	// Set the margin for postionning the element. Useful for IE6
+	function setMarginScroll() {
+		if (isIE6 && !modal.blocker) {
+			if (document.documentElement) {
+				currentSettings.marginScrollLeft = document.documentElement.scrollLeft;
+				currentSettings.marginScrollTop = document.documentElement.scrollTop;
+			} else {
+				currentSettings.marginScrollLeft = document.body.scrollLeft;
+				currentSettings.marginScrollTop = document.body.scrollTop;
+			}
+		} else {
+			currentSettings.marginScrollLeft = 0;
+			currentSettings.marginScrollTop = 0;
+		}
+	}
+
+	// Set the margin for the content
+	function setMargin() {
+		setMarginScroll();
+		currentSettings.marginLeft = -(currentSettings.width+currentSettings.borderW)/2;
+		currentSettings.marginTop = -(currentSettings.height+currentSettings.borderH)/2;
+		if (!modal.blocker) {
+			currentSettings.marginLeft+= currentSettings.marginScrollLeft;
+			currentSettings.marginTop+= currentSettings.marginScrollTop;
+		}
+	}
+
+	// Set the margin for the current loading
+	function setMarginLoading() {
+		setMarginScroll();
+		var outer = getOuter(modal.loading);
+		currentSettings.marginTopLoading = -(modal.loading.height() + outer.h.border + outer.h.padding)/2;
+		currentSettings.marginLeftLoading = -(modal.loading.width() + outer.w.border + outer.w.padding)/2;
+		if (!modal.blocker) {
+			currentSettings.marginLeftLoading+= currentSettings.marginScrollLeft;
+			currentSettings.marginTopLoading+= currentSettings.marginScrollTop;
+		}
+	}
+
+	// Set the modal Title
+	function setTitle() {
+		var title = $('h1#nyroModalTitle', modal.contentWrapper);
+		if (title.length)
+			title.text(currentSettings.title);
+		else
+			modal.contentWrapper.prepend('<h1 id="nyroModalTitle">'+currentSettings.title+'</h1>');
+	}
+
+	// Init the nyroModal div by settings the CSS elements and hide needed elements
+	function initModal() {
+		debug('initModal');
+		if (!modal.full) {
+			if (currentSettings.debug)
+				setCurrentSettings({color: 'white'}, 'cssOpt', 'bg');
+
+			var full = {
+				zIndex: currentSettings.zIndexStart,
+				position: 'fixed',
+				top: 0,
+				left: 0,
+				width: '100%',
+				height: '100%'
+			};
+
+			var contain = body;
+			var iframeHideIE = '';
+			if (currentSettings.blocker) {
+				modal.blocker = contain = $(currentSettings.blocker);
+				var pos = modal.blocker.offset();
+				var w = modal.blocker.outerWidth();
+				var h = modal.blocker.outerHeight();
+				if (isIE6) {
+					setCurrentSettings({
+						height: '100%',
+						width: '100%',
+						top: 0,
+						left: 0
+					}, 'cssOpt', 'bg');
+				}
+				modal.blockerVars = {
+					top: pos.top,
+					left: pos.left,
+					width: w,
+					height: h
+				};
+				var plusTop = (/msie/.test(userAgent) ?0:getCurCSS(body.get(0), 'borderTopWidth'));
+				var plusLeft = (/msie/.test(userAgent) ?0:getCurCSS(body.get(0), 'borderLeftWidth'));
+				full = {
+					position: 'absolute',
+					top: pos.top + plusTop,
+					left: pos.left + plusLeft,
+					width: w,
+					height: h
+				};
+			} else if (isIE6) {
+				body.css({
+					marginLeft: 0,
+					marginRight: 0
+				});
+				var w = body.width();
+				var h = $(window).height()+'px';
+				if ($(window).height() >= body.outerHeight()) {
+					h = body.outerHeight()+'px';
+				} else
+					w+= 20;
+				w += 'px';
+				body.css({
+					width: w,
+					height: h,
+					position: 'static',
+					overflow: 'hidden'
+				});
+				$('html').css({overflow: 'hidden'});
+				setCurrentSettings({
+					cssOpt: {
+						bg: {
+							position: 'absolute',
+							zIndex: currentSettings.zIndexStart+1,
+							height: '110%',
+							width: '110%',
+							top: currentSettings.marginScrollTop+'px',
+							left: currentSettings.marginScrollLeft+'px'
+						},
+						wrapper: { zIndex: currentSettings.zIndexStart+2 },
+						loading: { zIndex: currentSettings.zIndexStart+3 }
+					}
+				});
+
+				iframeHideIE = $('<iframe id="nyroModalIframeHideIe" src="javascript:\'\';"></iframe>')
+								.css($.extend({},
+									currentSettings.cssOpt.bg, {
+										opacity: 0,
+										zIndex: 50,
+										border: 'none'
+									}));
+			}
+
+			contain.append($('<div id="nyroModalFull"><div id="nyroModalBg"></div><div id="nyroModalWrapper"><div id="nyroModalContent"></div></div><div id="nyrModalTmp"></div><div id="nyroModalLoading"></div></div>').hide());
+
+			modal.full = $('#nyroModalFull')
+				.css(full)
+				.show();
+			modal.bg = $('#nyroModalBg')
+				.css($.extend({
+						backgroundColor: currentSettings.bgColor
+					}, currentSettings.cssOpt.bg))
+				.before(iframeHideIE);
+			modal.bg.bind('click.nyroModal', clickBg);
+			modal.loading = $('#nyroModalLoading')
+				.css(currentSettings.cssOpt.loading)
+				.hide();
+			modal.contentWrapper = $('#nyroModalWrapper')
+				.css(currentSettings.cssOpt.wrapper)
+				.hide();
+			modal.content = $('#nyroModalContent');
+			modal.tmp = $('#nyrModalTmp').hide();
+
+			// To stop the mousewheel if the the plugin is available
+			if ($.isFunction($.fn.mousewheel)) {
+				modal.content.mousewheel(function(e, d) {
+					var elt = modal.content.get(0);
+					if ((d > 0 && elt.scrollTop == 0) ||
+							(d < 0 && elt.scrollHeight - elt.scrollTop == elt.clientHeight)) {
+						e.preventDefault();
+						e.stopPropagation();
+					}
+				});
+			}
+
+			$(document).bind('keydown.nyroModal', keyHandler);
+			modal.content.css({width: 'auto', height: 'auto'});
+			modal.contentWrapper.css({width: 'auto', height: 'auto'});
+
+			if (!currentSettings.blocker && currentSettings.windowResize) {
+				$(window).bind('resize.nyroModal', function() {
+					window.clearTimeout(windowResizeTimeout);
+					windowResizeTimeout = window.setTimeout(windowResizeHandler, 200);
+				});
+			}
+		}
+	}
+
+	function windowResizeHandler() {
+		$.nyroModalSettings(initSettingsSize);
+	}
+
+	// Show the modal (ie: the background and then the loading if needed or the content directly)
+	function showModal() {
+		debug('showModal');
+		if (!modal.ready) {
+			initModal();
+			modal.anim = true;
+			currentSettings.showBackground(modal, currentSettings, endBackground);
+		} else {
+			modal.anim = true;
+			modal.transition = true;
+			currentSettings.showTransition(modal, currentSettings, function(){endHideContent();modal.anim=false;showContentOrLoading();});
+		}
+	}
+
+	// Called when user click on background
+	function clickBg(e) {
+		if (!currentSettings.modal)
+			removeModal();
+	}
+	
+	// Used for the escape key or the arrow in the gallery type
+	function keyHandler(e) {
+		if (e.keyCode == 27) {
+			if (!currentSettings.modal)
+				removeModal();
+		} else if (currentSettings.gallery && modal.ready && modal.dataReady && !modal.anim && !modal.transition) {
+			if (e.keyCode == 39 || e.keyCode == 40) {
+				e.preventDefault();
+				$.nyroModalNext();
+				return false;
+			} else if (e.keyCode == 37 || e.keyCode == 38) {
+				e.preventDefault();
+				$.nyroModalPrev();
+				return false;
+			}
+		}
+	}
+
+	// Determine the filetype regarding the link DOM element
+	function fileType() {
+		var from = currentSettings.from;
+
+		var url;
+
+		if (from && from.nodeName) {
+			var jFrom = $(from);
+
+			url = jFrom.attr(from.nodeName.toLowerCase() == 'form' ? 'action' : 'href');
+			if (!url)
+				url = location.href.substring(window.location.host.length+7);
+			currentSettings.url = url;
+
+			if (jFrom.attr('rev') == 'modal')
+				currentSettings.modal = true;
+
+			currentSettings.title = jFrom.attr('title');
+
+			if (from && from.rel && from.rel.toLowerCase() != 'nofollow') {
+				var indexSpace = from.rel.indexOf(' ');
+				currentSettings.gallery = indexSpace > 0 ? from.rel.substr(0, indexSpace) : from.rel;
+			}
+
+			var imgType = imageType(url, from);
+			if (imgType)
+				return imgType;
+
+			if (isSwf(url))
+				return 'swf';
+
+			var iframe = false;
+			if (from.target && from.target.toLowerCase() == '_blank' || (from.hostname && from.hostname.replace(/:\d*$/,'') != window.location.hostname.replace(/:\d*$/,''))) {
+				iframe = true;
+			}
+			if (from.nodeName.toLowerCase() == 'form') {
+				if (iframe)
+					return 'iframeForm';
+				setCurrentSettings(extractUrlSel(url));
+				if (jFrom.attr('enctype') == 'multipart/form-data')
+					return 'formData';
+				return 'form';
+			}
+			if (iframe)
+				return 'iframe';
+		} else {
+			url = currentSettings.url;
+			if (!currentSettings.content)
+				currentSettings.from = true;
+
+			if (!url)
+				return null;
+
+			if (isSwf(url))
+				return 'swf';
+
+			var reg1 = new RegExp("^http://|https://", "g");
+			if (url.match(reg1))
+				return 'iframe';
+		}
+
+		var imgType = imageType(url, from);
+		if (imgType)
+			return imgType;
+
+		var tmp = extractUrlSel(url);
+		setCurrentSettings(tmp);
+
+		if (!tmp.url)
+			return tmp.selector;
+	}
+
+	function imageType(url, from) {
+		var image = new RegExp(currentSettings.regexImg, 'i');
+		if (image.test(url)) {
+			return 'image';
+		}
+	}
+
+	function isSwf(url) {
+		var swf = new RegExp('[^\.]\.(swf)\s*$', 'i');
+		return swf.test(url);
+	}
+
+	function extractUrlSel(url) {
+		var ret = {
+			url: null,
+			selector: null
+		};
+
+		if (url) {
+			var hash = getHash(url);
+			var hashLoc = getHash(window.location.href);
+			var curLoc = window.location.href.substring(0, window.location.href.length - hashLoc.length);
+			var req = url.substring(0, url.length - hash.length);
+
+			if (req == curLoc || req == $('base').attr('href')) {
+				ret.selector = hash;
+			} else {
+				ret.url = req;
+				ret.selector = hash;
+			}
+		}
+		return ret;
+	}
+
+	// Called when the content cannot be loaded or tiemout reached
+	function loadingError() {
+		debug('loadingError');
+
+		modal.error = true;
+
+		if (!modal.ready)
+			return;
+
+		if ($.isFunction(currentSettings.handleError))
+			currentSettings.handleError(modal, currentSettings);
+
+		modal.loading
+			.addClass(currentSettings.errorClass)
+			.html(currentSettings.contentError);
+		$(currentSettings.closeSelector, modal.loading)
+			.unbind('click.nyroModal')
+			.bind('click.nyroModal', removeModal);
+		setMarginLoading();
+		modal.loading
+			.css({
+				marginTop: currentSettings.marginTopLoading+'px',
+				marginLeft: currentSettings.marginLeftLoading+'px'
+			});
+	}
+
+	// Put the content from modal.tmp to modal.content
+	function fillContent() {
+		debug('fillContent');
+		if (!modal.tmp.html())
+			return;
+
+		modal.content.html(modal.tmp.contents());
+		modal.tmp.empty();
+		wrapContent();
+
+		if (currentSettings.type == 'iframeForm') {
+			$(currentSettings.from)
+				.attr('target', 'nyroModalIframe')
+				.data('nyroModalprocessing', 1)
+				.submit()
+				.attr('target', '_blank')
+				.removeData('nyroModalprocessing');
+		}
+
+		if (!currentSettings.modal)
+			modal.wrapper.prepend(currentSettings.closeButton);
+
+		if ($.isFunction(currentSettings.endFillContent))
+			currentSettings.endFillContent(modal, currentSettings);
+
+		modal.content.append(modal.scripts);
+
+		$(currentSettings.closeSelector, modal.contentWrapper)
+			.unbind('click.nyroModal')
+			.bind('click.nyroModal', removeModal);
+		$(currentSettings.openSelector, modal.contentWrapper).nyroModal(getCurrentSettingsNew());
+	}
+
+	// Get the current settings to be used in new links
+	function getCurrentSettingsNew() {
+		return callingSettings;
+		var currentSettingsNew = $.extend(true, {}, currentSettings);
+		if (resized.width)
+			currentSettingsNew.width = null;
+		else
+			currentSettingsNew.width = initSettingsSize.width;
+		if (resized.height)
+			currentSettingsNew.height = null;
+		else
+			currentSettingsNew.height = initSettingsSize.height;
+		currentSettingsNew.cssOpt.content.overflow = 'auto';
+		return currentSettingsNew;
+	}
+
+	// Wrap the content and update the modal size if needed
+	function wrapContent() {
+		debug('wrapContent');
+
+		var wrap = $(currentSettings.wrap[currentSettings.type]);
+		modal.content.append(wrap.children().remove());
+		modal.contentWrapper.wrapInner(wrap);
+
+		if (currentSettings.gallery) {
+			// Set the action for the next and prev button (or remove them)
+			modal.content.append(currentSettings.galleryLinks);
+
+			gallery.links = $('[rel="'+currentSettings.gallery+'"], [rel^="'+currentSettings.gallery+' "]');
+			gallery.index = gallery.links.index(currentSettings.from);
+
+			if (currentSettings.galleryCounts && $.isFunction(currentSettings.galleryCounts))
+				currentSettings.galleryCounts(gallery.index + 1, gallery.links.length, modal, currentSettings);
+
+			var currentSettingsNew = getCurrentSettingsNew();
+
+			var linkPrev = getGalleryLink(-1);
+			if (linkPrev) {
+				var prev = $('.nyroModalPrev', modal.contentWrapper)
+					.attr('href', linkPrev.attr('href'))
+					.click(function(e) {
+						e.preventDefault();
+						$.nyroModalPrev();
+						return false;
+					});
+				if (isIE6 && currentSettings.type == 'swf') {
+					prev.before($('<iframe id="nyroModalIframeHideIeGalleryPrev" src="javascript:\'\';"></iframe>').css({
+											position: prev.css('position'),
+											top: prev.css('top'),
+											left: prev.css('left'),
+											width: prev.width(),
+											height: prev.height(),
+											opacity: 0,
+											border: 'none'
+										}));
+				}
+			} else {
+				$('.nyroModalPrev', modal.contentWrapper).remove();
+			}
+			var linkNext = getGalleryLink(1);
+			if (linkNext) {
+				var next = $('.nyroModalNext', modal.contentWrapper)
+					.attr('href', linkNext.attr('href'))
+					.click(function(e) {
+						e.preventDefault();
+						$.nyroModalNext();
+						return false;
+					});
+				if (isIE6 && currentSettings.type == 'swf') {
+					next.before($('<iframe id="nyroModalIframeHideIeGalleryNext" src="javascript:\'\';"></iframe>')
+									.css($.extend({}, {
+											position: next.css('position'),
+											top: next.css('top'),
+											left: next.css('left'),
+											width: next.width(),
+											height: next.height(),
+											opacity: 0,
+											border: 'none'
+										})));
+				}
+			} else {
+				$('.nyroModalNext', modal.contentWrapper).remove();
+			}
+		}
+
+		calculateSize();
+	}
+
+	function getGalleryLink(dir) {
+		if (currentSettings.gallery) {
+			if (!currentSettings.ltr)
+				dir *= -1;
+			var index = gallery.index + dir;
+			if (index >= 0 && index < gallery.links.length)
+				return gallery.links.eq(index);
+			else if (currentSettings.galleryLoop) {
+				if (index < 0)
+					return gallery.links.eq(gallery.links.length-1);
+				else
+					return gallery.links.eq(0);
+			}
+		}
+		return false;
+	}
+
+	// Calculate the size for the contentWrapper
+	function calculateSize(resizing) {
+		debug('calculateSize');
+
+		modal.wrapper = modal.contentWrapper.children('div:first');
+
+		resized.width = false;
+		resized.height = false;
+		if (false && !currentSettings.windowResizing) {
+			initSettingsSize.width = currentSettings.width;
+			initSettingsSize.height = currentSettings.height;
+		}
+
+		if (currentSettings.autoSizable && (!currentSettings.width || !currentSettings.height)) {
+			modal.contentWrapper
+				.css({
+					opacity: 0,
+					width: 'auto',
+					height: 'auto'
+				})
+				.show();
+			var tmp = {
+				width: 'auto',
+				height: 'auto'
+			};
+			if (currentSettings.width) {
+				tmp.width = currentSettings.width;
+			} else if (currentSettings.type == 'iframe') {
+				tmp.width = currentSettings.minWidth;
+			}
+
+			if (currentSettings.height) {
+				tmp.height = currentSettings.height;
+			} else if (currentSettings.type == 'iframe') {
+				tmp.height = currentSettings.minHeight;
+			}
+
+			modal.content.css(tmp);
+			if (!currentSettings.width) {
+				currentSettings.width = modal.content.outerWidth(true);
+				resized.width = true;
+			}
+			if (!currentSettings.height) {
+				currentSettings.height = modal.content.outerHeight(true);
+				resized.height = true;
+			}
+			modal.contentWrapper.css({opacity: 1});
+			if (!resizing)
+				modal.contentWrapper.hide();
+		}
+
+		if (currentSettings.type != 'image' && currentSettings.type != 'swf') {
+			currentSettings.width = Math.max(currentSettings.width, currentSettings.minWidth);
+			currentSettings.height = Math.max(currentSettings.height, currentSettings.minHeight);
+		}
+
+		var outerWrapper = getOuter(modal.contentWrapper);
+		var outerWrapper2 = getOuter(modal.wrapper);
+		var outerContent = getOuter(modal.content);
+
+		var tmp = {
+			content: {
+				width: currentSettings.width,
+				height: currentSettings.height
+			},
+			wrapper2: {
+				width: currentSettings.width + outerContent.w.total,
+				height: currentSettings.height + outerContent.h.total
+			},
+			wrapper: {
+				width: currentSettings.width + outerContent.w.total + outerWrapper2.w.total,
+				height: currentSettings.height + outerContent.h.total + outerWrapper2.h.total
+			}
+		};
+
+		if (currentSettings.resizable) {
+			var maxHeight = modal.blockerVars? modal.blockerVars.height : $(window).height()
+								- outerWrapper.h.border
+								- (tmp.wrapper.height - currentSettings.height);
+			var maxWidth = modal.blockerVars? modal.blockerVars.width : $(window).width()
+								- outerWrapper.w.border
+								- (tmp.wrapper.width - currentSettings.width);
+			maxHeight-= currentSettings.padding*2;
+			maxWidth-= currentSettings.padding*2;
+
+			if (tmp.content.height > maxHeight || tmp.content.width > maxWidth) {
+				// We're gonna resize the modal as it will goes outside the view port
+				if (currentSettings.type == 'image' || currentSettings.type == 'swf') {
+					// An image is resized proportionnaly
+					var useW = currentSettings.imgWidth?currentSettings.imgWidth : currentSettings.width;
+					var useH = currentSettings.imgHeight?currentSettings.imgHeight : currentSettings.height;
+					var diffW = tmp.content.width - useW;
+					var diffH = tmp.content.height - useH;
+						if (diffH < 0) diffH = 0;
+						if (diffW < 0) diffW = 0;
+					var calcH = maxHeight - diffH;
+					var calcW = maxWidth - diffW;
+					var ratio = Math.min(calcH/useH, calcW/useW);
+					calcW = Math.floor(useW*ratio);
+					calcH = Math.floor(useH*ratio);
+					tmp.content.height = calcH + diffH;
+					tmp.content.width = calcW + diffW;
+				} else {
+					// For an HTML content, we simply decrease the size
+					tmp.content.height = Math.min(tmp.content.height, maxHeight);
+					tmp.content.width = Math.min(tmp.content.width, maxWidth);
+				}
+				tmp.wrapper2 = {
+						width: tmp.content.width + outerContent.w.total,
+						height: tmp.content.height + outerContent.h.total
+					};
+				tmp.wrapper = {
+						width: tmp.content.width + outerContent.w.total + outerWrapper2.w.total,
+						height: tmp.content.height + outerContent.h.total + outerWrapper2.h.total
+					};
+			}
+		}
+
+		if (currentSettings.type == 'swf') {
+			$('object, embed', modal.content)
+				.attr('width', tmp.content.width)
+				.attr('height', tmp.content.height);
+		} else if (currentSettings.type == 'image') {
+			$('img', modal.content).css({
+				width: tmp.content.width,
+				height: tmp.content.height
+			});
+		}
+
+		modal.content.css($.extend({}, tmp.content, currentSettings.cssOpt.content));
+		modal.wrapper.css($.extend({}, tmp.wrapper2, currentSettings.cssOpt.wrapper2));
+
+		if (!resizing)
+			modal.contentWrapper.css($.extend({}, tmp.wrapper, currentSettings.cssOpt.wrapper));
+
+		if (currentSettings.type == 'image' && currentSettings.addImageDivTitle) {
+			// Adding the title for the image
+			$('img', modal.content).removeAttr('alt');
+			var divTitle = $('div', modal.content);
+			if (currentSettings.title != currentSettings.defaultImgAlt && currentSettings.title) {
+				if (divTitle.length == 0) {
+					divTitle = $('<div>'+currentSettings.title+'</div>');
+					modal.content.append(divTitle);
+				}
+				if (currentSettings.setWidthImgTitle) {
+					var outerDivTitle = getOuter(divTitle);
+					divTitle.css({width: (tmp.content.width + outerContent.w.padding - outerDivTitle.w.total)+'px'});
+				}
+			} else if (divTitle.length = 0) {
+				divTitle.remove();
+			}
+		}
+
+		if (currentSettings.title)
+			setTitle();
+
+		tmp.wrapper.borderW = outerWrapper.w.border;
+		tmp.wrapper.borderH = outerWrapper.h.border;
+
+		setCurrentSettings(tmp.wrapper);
+		setMargin();
+	}
+
+	function removeModal(e) {
+		debug('removeModal');
+		if (e)
+			e.preventDefault();
+		if (modal.full && modal.ready) {
+			$(document).unbind('keydown.nyroModal');
+			if (!currentSettings.blocker)
+				$(window).unbind('resize.nyroModal');
+			modal.ready = false;
+			modal.anim = true;
+			modal.closing = true;
+			if (modal.loadingShown || modal.transition) {
+				currentSettings.hideLoading(modal, currentSettings, function() {
+						modal.loading.hide();
+						modal.loadingShown = false;
+						modal.transition = false;
+						currentSettings.hideBackground(modal, currentSettings, endRemove);
+					});
+			} else {
+				if (fixFF)
+					modal.content.css({position: ''}); // Fix Issue #10, remove the attribute
+				modal.wrapper.css({overflow: 'hidden'}); // Used to fix a visual issue when hiding
+				modal.content.css({overflow: 'hidden'}); // Used to fix a visual issue when hiding
+				$('iframe', modal.content).hide(); // Fix issue 359
+				if ($.isFunction(currentSettings.beforeHideContent)) {
+					currentSettings.beforeHideContent(modal, currentSettings, function() {
+						currentSettings.hideContent(modal, currentSettings, function() {
+							endHideContent();
+							currentSettings.hideBackground(modal, currentSettings, endRemove);
+						});
+					});
+				} else {
+					currentSettings.hideContent(modal, currentSettings, function() {
+							endHideContent();
+							currentSettings.hideBackground(modal, currentSettings, endRemove);
+						});
+				}
+			}
+		}
+		if (e)
+			return false;
+	}
+
+	function showContentOrLoading() {
+		debug('showContentOrLoading');
+		if (modal.ready && !modal.anim) {
+			if (modal.dataReady) {
+				if (modal.tmp.html()) {
+					modal.anim = true;
+					if (modal.transition) {
+						fillContent();
+						modal.animContent = true;
+						currentSettings.hideTransition(modal, currentSettings, function() {
+							modal.loading.hide();
+							modal.transition = false;
+							modal.loadingShown = false;
+							endShowContent();
+						});
+					} else {
+						currentSettings.hideLoading(modal, currentSettings, function() {
+								modal.loading.hide();
+								modal.loadingShown = false;
+								fillContent();
+								setMarginLoading();
+								setMargin();
+								modal.animContent = true;
+								currentSettings.showContent(modal, currentSettings, endShowContent);
+							});
+					}
+				}
+			} else if (!modal.loadingShown && !modal.transition) {
+				modal.anim = true;
+				modal.loadingShown = true;
+				if (modal.error)
+					loadingError();
+				else
+					modal.loading.html(currentSettings.contentLoading);
+				$(currentSettings.closeSelector, modal.loading)
+					.unbind('click.nyroModal')
+					.bind('click.nyroModal', removeModal);
+				setMarginLoading();
+				currentSettings.showLoading(modal, currentSettings, function(){modal.anim=false;showContentOrLoading();});
+			}
+		}
+	}
+	
+	// -------------------------------------------------------
+	// Private Data Loaded callback
+	// -------------------------------------------------------
+
+	function ajaxLoaded(data) {
+		debug('AjaxLoaded: '+this.url);
+		
+		if (currentSettings.selector) {
+			var tmp = {};
+			var i = 0;
+			// Looking for script to store them
+			data = data
+				.replace(/\r\n/gi,'nyroModalLN')
+				.replace(/<script(.|\s)*?\/script>/gi, function(x) {
+						tmp[i] = x;
+						return '<pre style="display: none" class=nyroModalScript rel="'+(i++)+'"></pre>';
+					});
+			data = $('<div>'+data+'</div>').find(currentSettings.selector).html()
+				.replace(/<pre style="display: none;?" class="?nyroModalScript"? rel="(.?)"><\/pre>/gi, function(x, y, z) {
+					return tmp[y];
+				})
+				.replace(/nyroModalLN/gi,"\r\n");
+		}
+		modal.tmp.html(filterScripts(data));
+		if (modal.tmp.html()) {
+			modal.dataReady = true;
+			showContentOrLoading();
+		} else
+			loadingError();
+	}
+
+	function formDataLoaded() {
+		debug('formDataLoaded');
+		var jFrom = $(currentSettings.from);
+		jFrom.attr('action', jFrom.attr('action')+currentSettings.selector);
+		jFrom.attr('target', '');
+		$('input[name='+currentSettings.formIndicator+']', currentSettings.from).remove();
+		var iframe = modal.tmp.children('iframe');
+		var iframeContent = iframe.unbind('load').contents().find(currentSettings.selector || 'body').not('script[src]');
+		iframe.attr('src', 'about:blank'); // Used to stop the loading in FF
+		modal.tmp.html(iframeContent.html());
+		if (modal.tmp.html()) {
+			modal.dataReady = true;
+			showContentOrLoading();
+		} else
+			loadingError();
+	}
+	
+	function iframeLoaded() {
+		if ((window.location.hostname && currentSettings.url.indexOf(window.location.hostname) > -1)
+				||	currentSettings.url.indexOf('http://')) {
+			var iframe = $('iframe', modal.full).contents();
+			var tmp = {};
+			if (currentSettings.titleFromIframe) {
+				tmp.title = iframe.find('title').text();
+				if (!tmp.title) {
+					// for IE
+					try {
+						tmp.title = iframe.find('title').html();
+					} catch(err) {}
+				}
+			}
+			var body = iframe.find('body');
+			if (!currentSettings.height && body.height())
+				tmp.height = body.height();
+			if (!currentSettings.width && body.width())
+				tmp.width = body.width();
+			$.extend(initSettingsSize, tmp);
+			$.nyroModalSettings(tmp);
+		}
+	}
+
+	function galleryCounts(nb, total, elts, settings) {
+		if (total > 1)
+			settings.title+= (settings.title?' - ':'') +nb+'/'+total;
+	}
+
+
+	// -------------------------------------------------------
+	// Private Animation callback
+	// -------------------------------------------------------
+
+	function endHideContent() {
+		debug('endHideContent');
+		modal.anim = false;
+		if (contentEltLast) {
+			contentEltLast.append(modal.content.contents());
+			contentEltLast = null;
+		} else if (contentElt) {
+			contentElt.append(modal.content.contents());
+			contentElt= null;
+		}
+		modal.content.empty();
+
+		gallery = {};
+
+		modal.contentWrapper.hide().children().remove().empty().attr('style', '').hide();
+
+		if (modal.closing || modal.transition)
+			modal.contentWrapper.hide();
+
+		modal.contentWrapper
+			.css(currentSettings.cssOpt.wrapper)
+			.append(modal.content);
+		showContentOrLoading();
+	}
+
+	function endRemove() {
+		debug('endRemove');
+		$(document).unbind('keydown', keyHandler);
+		modal.anim = false;
+		modal.full.remove();
+		modal.full = null;
+		if (isIE6) {
+			body.css({height: '', width: '', position: '', overflow: '', marginLeft: '', marginRight: ''});
+			$('html').css({overflow: ''});
+		}
+		if ($.isFunction(currentSettings.endRemove))
+			currentSettings.endRemove(modal, currentSettings);
+	}
+
+	function endBackground() {
+		debug('endBackground');
+		modal.ready = true;
+		modal.anim = false;
+		showContentOrLoading();
+	}
+
+	function endShowContent() {
+		debug('endShowContent');
+		modal.anim = false;
+		modal.animContent = false;
+		modal.contentWrapper.css({opacity: ''}); // for the close button in IE
+		fixFF = /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent) && parseFloat(browserVersion) < 1.9 && currentSettings.type != 'image';
+
+		if (fixFF)
+			modal.content.css({position: 'fixed'}); // Fix Issue #10
+		modal.content.append(modal.scriptsShown);
+
+		if(currentSettings.type == 'iframe')
+			modal.content.find('iframe').attr('src', currentSettings.url);
+
+		if ($.isFunction(currentSettings.endShowContent))
+			currentSettings.endShowContent(modal, currentSettings);
+
+		if (shouldResize) {
+			shouldResize = false;
+			$.nyroModalSettings({width: currentSettings.setWidth, height: currentSettings.setHeight});
+			delete currentSettings['setWidth'];
+			delete currentSettings['setHeight'];
+		}
+		if (resized.width)
+			setCurrentSettings({width: null});
+		if (resized.height)
+			setCurrentSettings({height: null});
+	}
+
+
+	// -------------------------------------------------------
+	// Utilities
+	// -------------------------------------------------------
+
+	// Get the selector from an url (as string)
+	function getHash(url) {
+		if (typeof url == 'string') {
+			var hashPos = url.indexOf('#');
+			if (hashPos > -1)
+				return url.substring(hashPos);
+		}
+		return '';
+	}
+
+	// Filter an html content to remove the script[src]
+	function filterScripts(data) {
+		// Removing the body, head and html tag
+		if (typeof data == 'string')
+			data = data.replace(/<\/?(html|head|body)([^>]*)>/gi, '');
+		var tmp = new Array();
+		$.each($.clean({0:data}, this.ownerDocument), function() {
+			if ($.nodeName(this, "script")) {
+				if (!this.src || $(this).attr('rel') == 'forceLoad') {
+					if ($(this).attr('rev') == 'shown')
+						modal.scriptsShown.push(this);
+					else
+						modal.scripts.push(this);
+				}
+			} else
+				tmp.push(this);
+		});
+		return tmp;
+	}
+
+	// Get the vertical and horizontal margin, padding and border dimension
+	function getOuter(elm) {
+		elm = elm.get(0);
+		var ret = {
+			h: {
+				margin: getCurCSS(elm, 'marginTop') + getCurCSS(elm, 'marginBottom'),
+				border: getCurCSS(elm, 'borderTopWidth') + getCurCSS(elm, 'borderBottomWidth'),
+				padding: getCurCSS(elm, 'paddingTop') + getCurCSS(elm, 'paddingBottom')
+			},
+			w: {
+				margin: getCurCSS(elm, 'marginLeft') + getCurCSS(elm, 'marginRight'),
+				border: getCurCSS(elm, 'borderLeftWidth') + getCurCSS(elm, 'borderRightWidth'),
+				padding: getCurCSS(elm, 'paddingLeft') + getCurCSS(elm, 'paddingRight')
+			}
+		};
+
+		ret.h.outer = ret.h.margin + ret.h.border;
+		ret.w.outer = ret.w.margin + ret.w.border;
+
+		ret.h.inner = ret.h.padding + ret.h.border;
+		ret.w.inner = ret.w.padding + ret.w.border;
+
+		ret.h.total = ret.h.outer + ret.h.padding;
+		ret.w.total = ret.w.outer + ret.w.padding;
+
+		return ret;
+	}
+
+	function getCurCSS(elm, name) {
+		var ret = parseInt($.curCSS(elm, name, true));
+		if (isNaN(ret))
+			ret = 0;
+		return ret;
+	}
+
+	// Proxy Debug function
+	function debug(msg) {
+		if ($.fn.nyroModal.settings.debug || currentSettings && currentSettings.debug)
+			nyroModalDebug(msg, modal, currentSettings || {});
+	}
+
+	// -------------------------------------------------------
+	// Default animation function
+	// -------------------------------------------------------
+
+	function showBackground(elts, settings, callback) {
+		elts.bg.css({opacity:0}).fadeTo(500, 0.75, callback);
+	}
+
+	function hideBackground(elts, settings, callback) {
+		elts.bg.fadeOut(300, callback);
+	}
+
+	function showLoading(elts, settings, callback) {
+		elts.loading
+			.css({
+				marginTop: settings.marginTopLoading+'px',
+				marginLeft: settings.marginLeftLoading+'px',
+				opacity: 0
+			})
+			.show()
+			.animate({
+				opacity: 1
+			}, {complete: callback, duration: 400});
+	}
+
+	function hideLoading(elts, settings, callback) {
+		callback();
+	}
+
+	function showContent(elts, settings, callback) {
+		elts.loading
+			.css({
+				marginTop: settings.marginTopLoading+'px',
+				marginLeft: settings.marginLeftLoading+'px'
+			})
+			.show()
+			.animate({
+				width: settings.width+'px',
+				height: settings.height+'px',
+				marginTop: settings.marginTop+'px',
+				marginLeft: settings.marginLeft+'px'
+			}, {duration: 350, complete: function() {
+				elts.contentWrapper
+					.css({
+						width: settings.width+'px',
+						height: settings.height+'px',
+						marginTop: settings.marginTop+'px',
+						marginLeft: settings.marginLeft+'px'
+					})
+					.show();
+					elts.loading.fadeOut(200, callback);
+				}
+			});
+	}
+
+	function hideContent(elts, settings, callback) {
+		elts.contentWrapper
+			.animate({
+				height: '50px',
+				width: '50px',
+				marginTop: (-(25+settings.borderH)/2 + settings.marginScrollTop)+'px',
+				marginLeft: (-(25+settings.borderW)/2 + settings.marginScrollLeft)+'px'
+			}, {duration: 350, complete: function() {
+				elts.contentWrapper.hide();
+				callback();
+			}});
+	}
+
+	function showTransition(elts, settings, callback) {
+		// Put the loading with the same dimensions of the current content
+		elts.loading
+			.css({
+				marginTop: elts.contentWrapper.css('marginTop'),
+				marginLeft: elts.contentWrapper.css('marginLeft'),
+				height: elts.contentWrapper.css('height'),
+				width: elts.contentWrapper.css('width'),
+				opacity: 0
+			})
+			.show()
+			.fadeTo(400, 1, function() {
+					elts.contentWrapper.hide();
+					callback();
+				});
+	}
+
+	function hideTransition(elts, settings, callback) {
+		// Place the content wrapper underneath the the loading with the right dimensions
+		elts.contentWrapper
+			.hide()
+			.css({
+				width: settings.width+'px',
+				height: settings.height+'px',
+				marginLeft: settings.marginLeft+'px',
+				marginTop: settings.marginTop+'px',
+				opacity: 1
+			});
+		elts.loading
+			.animate({
+				width: settings.width+'px',
+				height: settings.height+'px',
+				marginLeft: settings.marginLeft+'px',
+				marginTop: settings.marginTop+'px'
+			}, {complete: function() {
+					elts.contentWrapper.show();
+					elts.loading.fadeOut(400, function() {
+						elts.loading.hide();
+						callback();
+					});
+				}, duration: 350});
+	}
+
+	function resize(elts, settings, callback) {
+		elts.contentWrapper
+			.animate({
+				width: settings.width+'px',
+				height: settings.height+'px',
+				marginLeft: settings.marginLeft+'px',
+				marginTop: settings.marginTop+'px'
+			}, {complete: callback, duration: 400});
+	}
+
+	function updateBgColor(elts, settings, callback) {
+		if (!$.fx.step.backgroundColor) {
+			elts.bg.css({backgroundColor: settings.bgColor});
+			callback();
+		} else
+			elts.bg
+				.animate({
+					backgroundColor: settings.bgColor
+				}, {complete: callback, duration: 400});
+	}
+
+	// -------------------------------------------------------
+	// Default initialization
+	// -------------------------------------------------------
+
+	$($.fn.nyroModal.settings.openSelector).nyroModal();
+
+});
+
+// Default debug function, to be overwritten if needed
+//      Be aware that the settings parameter could be empty
+var tmpDebug = '';
+function nyroModalDebug(msg, elts, settings) {
+	if (elts.full && elts.bg) {
+		elts.bg.prepend(msg+'<br />'+tmpDebug);
+		tmpDebug = '';
+	} else
+		tmpDebug+= msg+'<br />';
+}
Index: /extensions/rv_gmaps/branches/2.1/template/nyroModal/jquery.nyroModal-1.6.2.min.js
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/nyroModal/jquery.nyroModal-1.6.2.min.js	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/nyroModal/jquery.nyroModal-1.6.2.min.js	(revision 8301)
@@ -0,0 +1,11 @@
+/*
+ * nyroModal - jQuery Plugin
+ * http://nyromodal.nyrodev.com
+ *
+ * Copyright (c) 2010 Cedric Nirousset (nyrodev.com)
+ * Licensed under the MIT license
+ *
+ * $Date: 2010-02-23 (Tue, 23 Feb 2010) $
+ * $version: 1.6.2
+ */
+jQuery(function($){var userAgent=navigator.userAgent.toLowerCase();var browserVersion=(userAgent.match(/.+(?:rv|webkit|khtml|opera|msie)[\/: ]([\d.]+)/)||[0,'0'])[1];var isIE6=(/msie/.test(userAgent)&&!/opera/.test(userAgent)&&parseInt(browserVersion)<7&&(!window.XMLHttpRequest||typeof(XMLHttpRequest)==='function'));var body=$('body');var currentSettings;var callingSettings;var shouldResize=false;var gallery={};var fixFF=false;var contentElt;var contentEltLast;var modal={started:false,ready:false,dataReady:false,anim:false,animContent:false,loadingShown:false,transition:false,resizing:false,closing:false,error:false,blocker:null,blockerVars:null,full:null,bg:null,loading:null,tmp:null,content:null,wrapper:null,contentWrapper:null,scripts:new Array(),scriptsShown:new Array()};var resized={width:false,height:false,windowResizing:false};var initSettingsSize={width:null,height:null,windowResizing:true};var windowResizeTimeout;$.fn.nyroModal=function(settings){if(!this)return false;return this.each(function(){var me=$(this);if(this.nodeName.toLowerCase()=='form'){me.unbind('submit.nyroModal').bind('submit.nyroModal',function(e){if(e.isDefaultPrevented())return false;if(me.data('nyroModalprocessing'))return true;if(this.enctype=='multipart/form-data'){processModal($.extend(settings,{from:this}));return true}e.preventDefault();processModal($.extend(settings,{from:this}));return false})}else{me.unbind('click.nyroModal').bind('click.nyroModal',function(e){if(e.isDefaultPrevented())return false;e.preventDefault();processModal($.extend(settings,{from:this}));return false})}})};$.fn.nyroModalManual=function(settings){if(!this.length)processModal(settings);return this.each(function(){processModal($.extend(settings,{from:this}))})};$.nyroModalManual=function(settings){processModal(settings)};$.nyroModalSettings=function(settings,deep1,deep2){setCurrentSettings(settings,deep1,deep2);if(!deep1&&modal.started){if(modal.bg&&settings.bgColor)currentSettings.updateBgColor(modal,currentSettings,function(){});if(modal.contentWrapper&&settings.title)setTitle();if(!modal.error&&(settings.windowResizing||(!modal.resizing&&(('width'in settings&&settings.width==currentSettings.width)||('height'in settings&&settings.height==currentSettings.height))))){modal.resizing=true;if(modal.contentWrapper)calculateSize(true);if(modal.contentWrapper&&modal.contentWrapper.is(':visible')&&!modal.animContent){if(fixFF)modal.content.css({position:''});currentSettings.resize(modal,currentSettings,function(){currentSettings.windowResizing=false;modal.resizing=false;if(fixFF)modal.content.css({position:'fixed'});if($.isFunction(currentSettings.endResize))currentSettings.endResize(modal,currentSettings)})}}}};$.nyroModalRemove=function(){removeModal()};$.nyroModalNext=function(){var link=getGalleryLink(1);if(link)return link.nyroModalManual(getCurrentSettingsNew());return false};$.nyroModalPrev=function(){var link=getGalleryLink(-1);if(link)return link.nyroModalManual(getCurrentSettingsNew());return false};$.fn.nyroModal.settings={debug:false,blocker:false,windowResize:true,modal:false,type:'',forceType:null,from:'',hash:'',processHandler:null,selIndicator:'nyroModalSel',formIndicator:'nyroModal',content:null,bgColor:'#000000',ajax:{},swf:{wmode:'transparent'},width:null,height:null,minWidth:400,minHeight:300,resizable:true,autoSizable:true,padding:25,regexImg:'[^\.]\.(jpg|jpeg|png|tiff|gif|bmp)\s*$',addImageDivTitle:false,defaultImgAlt:'Image',setWidthImgTitle:true,ltr:true,gallery:null,galleryLinks:'<a href="#" class="nyroModalPrev">Prev</a><a href="#"  class="nyroModalNext">Next</a>',galleryCounts:galleryCounts,galleryLoop:false,zIndexStart:100,cssOpt:{bg:{position:'absolute',overflow:'hidden',top:0,left:0,height:'100%',width:'100%'},wrapper:{position:'absolute',top:'50%',left:'50%'},wrapper2:{},content:{},loading:{position:'absolute',top:'50%',left:'50%',marginTop:'-50px',marginLeft:'-50px'}},wrap:{div:'<div class="wrapper"></div>',ajax:'<div class="wrapper"></div>',form:'<div class="wrapper"></div>',formData:'<div class="wrapper"></div>',image:'<div class="wrapperImg"></div>',swf:'<div class="wrapperSwf"></div>',iframe:'<div class="wrapperIframe"></div>',iframeForm:'<div class="wrapperIframe"></div>',manual:'<div class="wrapper"></div>'},closeButton:'<a href="#" class="nyroModalClose" id="closeBut" title="close">Close</a>',title:null,titleFromIframe:true,openSelector:'.nyroModal',closeSelector:'.nyroModalClose',contentLoading:'<a href="#" class="nyroModalClose">Cancel</a>',errorClass:'error',contentError:'The requested content cannot be loaded.<br />Please try again later.<br /><a href="#" class="nyroModalClose">Close</a>',handleError:null,showBackground:showBackground,hideBackground:hideBackground,endFillContent:null,showContent:showContent,endShowContent:null,beforeHideContent:null,hideContent:hideContent,showTransition:showTransition,hideTransition:hideTransition,showLoading:showLoading,hideLoading:hideLoading,resize:resize,endResize:null,updateBgColor:updateBgColor,endRemove:null};function processModal(settings){if(modal.loadingShown||modal.transition||modal.anim)return;debug('processModal');modal.started=true;callingSettings=$.extend(true,settings);setDefaultCurrentSettings(settings);if(!modal.full)modal.blockerVars=modal.blocker=null;modal.error=false;modal.closing=false;modal.dataReady=false;modal.scripts=new Array();modal.scriptsShown=new Array();currentSettings.type=fileType();if(currentSettings.forceType){if(!currentSettings.content)currentSettings.from=true;currentSettings.type=currentSettings.forceType;currentSettings.forceType=null}if($.isFunction(currentSettings.processHandler))currentSettings.processHandler(currentSettings);var from=currentSettings.from;var url=currentSettings.url;initSettingsSize.width=currentSettings.width;initSettingsSize.height=currentSettings.height;if(currentSettings.type=='swf'){setCurrentSettings({overflow:'visible'},'cssOpt','content');currentSettings.content='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+currentSettings.width+'" height="'+currentSettings.height+'"><param name="movie" value="'+url+'"></param>';var tmp='';$.each(currentSettings.swf,function(name,val){currentSettings.content+='<param name="'+name+'" value="'+val+'"></param>';tmp+=' '+name+'="'+val+'"'});currentSettings.content+='<embed src="'+url+'" type="application/x-shockwave-flash" width="'+currentSettings.width+'" height="'+currentSettings.height+'"'+tmp+'></embed></object>'}if(from){var jFrom=$(from).blur();if(currentSettings.type=='form'){var data=$(from).serializeArray();data.push({name:currentSettings.formIndicator,value:1});if(currentSettings.selector)data.push({name:currentSettings.selIndicator,value:currentSettings.selector.substring(1)});showModal();$.ajax($.extend({},currentSettings.ajax,{url:url,data:data,type:jFrom.attr('method')?jFrom.attr('method'):'get',success:ajaxLoaded,error:loadingError}));debug('Form Ajax Load: '+jFrom.attr('action'))}else if(currentSettings.type=='formData'){initModal();jFrom.attr('target','nyroModalIframe');jFrom.attr('action',url);jFrom.prepend('<input type="hidden" name="'+currentSettings.formIndicator+'" value="1" />');if(currentSettings.selector)jFrom.prepend('<input type="hidden" name="'+currentSettings.selIndicator+'" value="'+currentSettings.selector.substring(1)+'" />');modal.tmp.html('<iframe frameborder="0" hspace="0" name="nyroModalIframe" src="javascript:\'\';"></iframe>');$('iframe',modal.tmp).css({width:currentSettings.width,height:currentSettings.height}).error(loadingError).load(formDataLoaded);debug('Form Data Load: '+jFrom.attr('action'));showModal();showContentOrLoading()}else if(currentSettings.type=='image'){debug('Image Load: '+url);var title=jFrom.attr('title')||currentSettings.defaultImgAlt;initModal();modal.tmp.html('<img id="nyroModalImg" />').find('img').attr('alt',title);modal.tmp.css({lineHeight:0});$('img',modal.tmp).error(loadingError).load(function(){debug('Image Loaded: '+this.src);$(this).unbind('load');var w=modal.tmp.width();var h=modal.tmp.height();modal.tmp.css({lineHeight:''});resized.width=w;resized.height=h;setCurrentSettings({width:w,height:h,imgWidth:w,imgHeight:h});initSettingsSize.width=w;initSettingsSize.height=h;setCurrentSettings({overflow:'visible'},'cssOpt','content');modal.dataReady=true;if(modal.loadingShown||modal.transition)showContentOrLoading()}).attr('src',url);showModal()}else if(currentSettings.type=='iframeForm'){initModal();modal.tmp.html('<iframe frameborder="0" hspace="0" src="javascript:\'\';" name="nyroModalIframe" id="nyroModalIframe"></iframe>');debug('Iframe Form Load: '+url);$('iframe',modal.tmp).eq(0).css({width:'100%',height:$.support.boxModel?'99%':'100%'}).load(iframeLoaded);modal.dataReady=true;showModal()}else if(currentSettings.type=='iframe'){initModal();modal.tmp.html('<iframe frameborder="0" hspace="0" src="javascript:\'\';" name="nyroModalIframe" id="nyroModalIframe"></iframe>');debug('Iframe Load: '+url);$('iframe',modal.tmp).eq(0).css({width:'100%',height:$.support.boxModel?'99%':'100%'}).load(iframeLoaded);modal.dataReady=true;showModal()}else if(currentSettings.type){debug('Content: '+currentSettings.type);initModal();modal.tmp.html(currentSettings.content);var w=modal.tmp.width();var h=modal.tmp.height();var div=$(currentSettings.type);if(div.length){setCurrentSettings({type:'div'});w=div.width();h=div.height();if(contentElt)contentEltLast=contentElt;contentElt=div;modal.tmp.append(div.contents())}initSettingsSize.width=w;initSettingsSize.height=h;setCurrentSettings({width:w,height:h});if(modal.tmp.html())modal.dataReady=true;else loadingError();if(!modal.ready)showModal();else endHideContent()}else{debug('Ajax Load: '+url);setCurrentSettings({type:'ajax'});var data=currentSettings.ajax.data||{};if(currentSettings.selector){if(typeof data=="string"){data+='&'+currentSettings.selIndicator+'='+currentSettings.selector.substring(1)}else{data[currentSettings.selIndicator]=currentSettings.selector.substring(1)}}showModal();$.ajax($.extend(true,currentSettings.ajax,{url:url,success:ajaxLoaded,error:loadingError,data:data}))}}else if(currentSettings.content){debug('Content: '+currentSettings.type);setCurrentSettings({type:'manual'});initModal();modal.tmp.html($('<div/>').html(currentSettings.content).contents());if(modal.tmp.html())modal.dataReady=true;else loadingError();showModal()}else{}}function setDefaultCurrentSettings(settings){debug('setDefaultCurrentSettings');currentSettings=$.extend(true,{},$.fn.nyroModal.settings,settings);setMargin()}function setCurrentSettings(settings,deep1,deep2){if(modal.started){if(deep1&&deep2){$.extend(true,currentSettings[deep1][deep2],settings)}else if(deep1){$.extend(true,currentSettings[deep1],settings)}else{if(modal.animContent){if('width'in settings){if(!modal.resizing){settings.setWidth=settings.width;shouldResize=true}delete settings['width']}if('height'in settings){if(!modal.resizing){settings.setHeight=settings.height;shouldResize=true}delete settings['height']}}$.extend(true,currentSettings,settings)}}else{if(deep1&&deep2){$.extend(true,$.fn.nyroModal.settings[deep1][deep2],settings)}else if(deep1){$.extend(true,$.fn.nyroModal.settings[deep1],settings)}else{$.extend(true,$.fn.nyroModal.settings,settings)}}}function setMarginScroll(){if(isIE6&&!modal.blocker){if(document.documentElement){currentSettings.marginScrollLeft=document.documentElement.scrollLeft;currentSettings.marginScrollTop=document.documentElement.scrollTop}else{currentSettings.marginScrollLeft=document.body.scrollLeft;currentSettings.marginScrollTop=document.body.scrollTop}}else{currentSettings.marginScrollLeft=0;currentSettings.marginScrollTop=0}}function setMargin(){setMarginScroll();currentSettings.marginLeft=-(currentSettings.width+currentSettings.borderW)/2;currentSettings.marginTop=-(currentSettings.height+currentSettings.borderH)/2;if(!modal.blocker){currentSettings.marginLeft+=currentSettings.marginScrollLeft;currentSettings.marginTop+=currentSettings.marginScrollTop}}function setMarginLoading(){setMarginScroll();var outer=getOuter(modal.loading);currentSettings.marginTopLoading=-(modal.loading.height()+outer.h.border+outer.h.padding)/2;currentSettings.marginLeftLoading=-(modal.loading.width()+outer.w.border+outer.w.padding)/2;if(!modal.blocker){currentSettings.marginLeftLoading+=currentSettings.marginScrollLeft;currentSettings.marginTopLoading+=currentSettings.marginScrollTop}}function setTitle(){var title=$('h1#nyroModalTitle',modal.contentWrapper);if(title.length)title.text(currentSettings.title);else modal.contentWrapper.prepend('<h1 id="nyroModalTitle">'+currentSettings.title+'</h1>')}function initModal(){debug('initModal');if(!modal.full){if(currentSettings.debug)setCurrentSettings({color:'white'},'cssOpt','bg');var full={zIndex:currentSettings.zIndexStart,position:'fixed',top:0,left:0,width:'100%',height:'100%'};var contain=body;var iframeHideIE='';if(currentSettings.blocker){modal.blocker=contain=$(currentSettings.blocker);var pos=modal.blocker.offset();var w=modal.blocker.outerWidth();var h=modal.blocker.outerHeight();if(isIE6){setCurrentSettings({height:'100%',width:'100%',top:0,left:0},'cssOpt','bg')}modal.blockerVars={top:pos.top,left:pos.left,width:w,height:h};var plusTop=(/msie/.test(userAgent)?0:getCurCSS(body.get(0),'borderTopWidth'));var plusLeft=(/msie/.test(userAgent)?0:getCurCSS(body.get(0),'borderLeftWidth'));full={position:'absolute',top:pos.top+plusTop,left:pos.left+plusLeft,width:w,height:h}}else if(isIE6){body.css({marginLeft:0,marginRight:0});var w=body.width();var h=$(window).height()+'px';if($(window).height()>=body.outerHeight()){h=body.outerHeight()+'px'}else w+=20;w+='px';body.css({width:w,height:h,position:'static',overflow:'hidden'});$('html').css({overflow:'hidden'});setCurrentSettings({cssOpt:{bg:{position:'absolute',zIndex:currentSettings.zIndexStart+1,height:'110%',width:'110%',top:currentSettings.marginScrollTop+'px',left:currentSettings.marginScrollLeft+'px'},wrapper:{zIndex:currentSettings.zIndexStart+2},loading:{zIndex:currentSettings.zIndexStart+3}}});iframeHideIE=$('<iframe id="nyroModalIframeHideIe" src="javascript:\'\';"></iframe>').css($.extend({},currentSettings.cssOpt.bg,{opacity:0,zIndex:50,border:'none'}))}contain.append($('<div id="nyroModalFull"><div id="nyroModalBg"></div><div id="nyroModalWrapper"><div id="nyroModalContent"></div></div><div id="nyrModalTmp"></div><div id="nyroModalLoading"></div></div>').hide());modal.full=$('#nyroModalFull').css(full).show();modal.bg=$('#nyroModalBg').css($.extend({backgroundColor:currentSettings.bgColor},currentSettings.cssOpt.bg)).before(iframeHideIE);modal.bg.bind('click.nyroModal',clickBg);modal.loading=$('#nyroModalLoading').css(currentSettings.cssOpt.loading).hide();modal.contentWrapper=$('#nyroModalWrapper').css(currentSettings.cssOpt.wrapper).hide();modal.content=$('#nyroModalContent');modal.tmp=$('#nyrModalTmp').hide();if($.isFunction($.fn.mousewheel)){modal.content.mousewheel(function(e,d){var elt=modal.content.get(0);if((d>0&&elt.scrollTop==0)||(d<0&&elt.scrollHeight-elt.scrollTop==elt.clientHeight)){e.preventDefault();e.stopPropagation()}})}$(document).bind('keydown.nyroModal',keyHandler);modal.content.css({width:'auto',height:'auto'});modal.contentWrapper.css({width:'auto',height:'auto'});if(!currentSettings.blocker&&currentSettings.windowResize){$(window).bind('resize.nyroModal',function(){window.clearTimeout(windowResizeTimeout);windowResizeTimeout=window.setTimeout(windowResizeHandler,200)})}}}function windowResizeHandler(){$.nyroModalSettings(initSettingsSize)}function showModal(){debug('showModal');if(!modal.ready){initModal();modal.anim=true;currentSettings.showBackground(modal,currentSettings,endBackground)}else{modal.anim=true;modal.transition=true;currentSettings.showTransition(modal,currentSettings,function(){endHideContent();modal.anim=false;showContentOrLoading()})}}function clickBg(e){if(!currentSettings.modal)removeModal()}function keyHandler(e){if(e.keyCode==27){if(!currentSettings.modal)removeModal()}else if(currentSettings.gallery&&modal.ready&&modal.dataReady&&!modal.anim&&!modal.transition){if(e.keyCode==39||e.keyCode==40){e.preventDefault();$.nyroModalNext();return false}else if(e.keyCode==37||e.keyCode==38){e.preventDefault();$.nyroModalPrev();return false}}}function fileType(){var from=currentSettings.from;var url;if(from&&from.nodeName){var jFrom=$(from);url=jFrom.attr(from.nodeName.toLowerCase()=='form'?'action':'href');if(!url)url=location.href.substring(window.location.host.length+7);currentSettings.url=url;if(jFrom.attr('rev')=='modal')currentSettings.modal=true;currentSettings.title=jFrom.attr('title');if(from&&from.rel&&from.rel.toLowerCase()!='nofollow'){var indexSpace=from.rel.indexOf(' ');currentSettings.gallery=indexSpace>0?from.rel.substr(0,indexSpace):from.rel}var imgType=imageType(url,from);if(imgType)return imgType;if(isSwf(url))return'swf';var iframe=false;if(from.target&&from.target.toLowerCase()=='_blank'||(from.hostname&&from.hostname.replace(/:\d*$/,'')!=window.location.hostname.replace(/:\d*$/,''))){iframe=true}if(from.nodeName.toLowerCase()=='form'){if(iframe)return'iframeForm';setCurrentSettings(extractUrlSel(url));if(jFrom.attr('enctype')=='multipart/form-data')return'formData';return'form'}if(iframe)return'iframe'}else{url=currentSettings.url;if(!currentSettings.content)currentSettings.from=true;if(!url)return null;if(isSwf(url))return'swf';var reg1=new RegExp("^http://|https://","g");if(url.match(reg1))return'iframe'}var imgType=imageType(url,from);if(imgType)return imgType;var tmp=extractUrlSel(url);setCurrentSettings(tmp);if(!tmp.url)return tmp.selector}function imageType(url,from){var image=new RegExp(currentSettings.regexImg,'i');if(image.test(url)){return'image'}}function isSwf(url){var swf=new RegExp('[^\.]\.(swf)\s*$','i');return swf.test(url)}function extractUrlSel(url){var ret={url:null,selector:null};if(url){var hash=getHash(url);var hashLoc=getHash(window.location.href);var curLoc=window.location.href.substring(0,window.location.href.length-hashLoc.length);var req=url.substring(0,url.length-hash.length);if(req==curLoc||req==$('base').attr('href')){ret.selector=hash}else{ret.url=req;ret.selector=hash}}return ret}function loadingError(){debug('loadingError');modal.error=true;if(!modal.ready)return;if($.isFunction(currentSettings.handleError))currentSettings.handleError(modal,currentSettings);modal.loading.addClass(currentSettings.errorClass).html(currentSettings.contentError);$(currentSettings.closeSelector,modal.loading).unbind('click.nyroModal').bind('click.nyroModal',removeModal);setMarginLoading();modal.loading.css({marginTop:currentSettings.marginTopLoading+'px',marginLeft:currentSettings.marginLeftLoading+'px'})}function fillContent(){debug('fillContent');if(!modal.tmp.html())return;modal.content.html(modal.tmp.contents());modal.tmp.empty();wrapContent();if(currentSettings.type=='iframeForm'){$(currentSettings.from).attr('target','nyroModalIframe').data('nyroModalprocessing',1).submit().attr('target','_blank').removeData('nyroModalprocessing')}if(!currentSettings.modal)modal.wrapper.prepend(currentSettings.closeButton);if($.isFunction(currentSettings.endFillContent))currentSettings.endFillContent(modal,currentSettings);modal.content.append(modal.scripts);$(currentSettings.closeSelector,modal.contentWrapper).unbind('click.nyroModal').bind('click.nyroModal',removeModal);$(currentSettings.openSelector,modal.contentWrapper).nyroModal(getCurrentSettingsNew())}function getCurrentSettingsNew(){return callingSettings;var currentSettingsNew=$.extend(true,{},currentSettings);if(resized.width)currentSettingsNew.width=null;else currentSettingsNew.width=initSettingsSize.width;if(resized.height)currentSettingsNew.height=null;else currentSettingsNew.height=initSettingsSize.height;currentSettingsNew.cssOpt.content.overflow='auto';return currentSettingsNew}function wrapContent(){debug('wrapContent');var wrap=$(currentSettings.wrap[currentSettings.type]);modal.content.append(wrap.children().remove());modal.contentWrapper.wrapInner(wrap);if(currentSettings.gallery){modal.content.append(currentSettings.galleryLinks);gallery.links=$('[rel="'+currentSettings.gallery+'"], [rel^="'+currentSettings.gallery+' "]');gallery.index=gallery.links.index(currentSettings.from);if(currentSettings.galleryCounts&&$.isFunction(currentSettings.galleryCounts))currentSettings.galleryCounts(gallery.index+1,gallery.links.length,modal,currentSettings);var currentSettingsNew=getCurrentSettingsNew();var linkPrev=getGalleryLink(-1);if(linkPrev){var prev=$('.nyroModalPrev',modal.contentWrapper).attr('href',linkPrev.attr('href')).click(function(e){e.preventDefault();$.nyroModalPrev();return false});if(isIE6&&currentSettings.type=='swf'){prev.before($('<iframe id="nyroModalIframeHideIeGalleryPrev" src="javascript:\'\';"></iframe>').css({position:prev.css('position'),top:prev.css('top'),left:prev.css('left'),width:prev.width(),height:prev.height(),opacity:0,border:'none'}))}}else{$('.nyroModalPrev',modal.contentWrapper).remove()}var linkNext=getGalleryLink(1);if(linkNext){var next=$('.nyroModalNext',modal.contentWrapper).attr('href',linkNext.attr('href')).click(function(e){e.preventDefault();$.nyroModalNext();return false});if(isIE6&&currentSettings.type=='swf'){next.before($('<iframe id="nyroModalIframeHideIeGalleryNext" src="javascript:\'\';"></iframe>').css($.extend({},{position:next.css('position'),top:next.css('top'),left:next.css('left'),width:next.width(),height:next.height(),opacity:0,border:'none'})))}}else{$('.nyroModalNext',modal.contentWrapper).remove()}}calculateSize()}function getGalleryLink(dir){if(currentSettings.gallery){if(!currentSettings.ltr)dir*=-1;var index=gallery.index+dir;if(index>=0&&index<gallery.links.length)return gallery.links.eq(index);else if(currentSettings.galleryLoop){if(index<0)return gallery.links.eq(gallery.links.length-1);else return gallery.links.eq(0)}}return false}function calculateSize(resizing){debug('calculateSize');modal.wrapper=modal.contentWrapper.children('div:first');resized.width=false;resized.height=false;if(false&&!currentSettings.windowResizing){initSettingsSize.width=currentSettings.width;initSettingsSize.height=currentSettings.height}if(currentSettings.autoSizable&&(!currentSettings.width||!currentSettings.height)){modal.contentWrapper.css({opacity:0,width:'auto',height:'auto'}).show();var tmp={width:'auto',height:'auto'};if(currentSettings.width){tmp.width=currentSettings.width}else if(currentSettings.type=='iframe'){tmp.width=currentSettings.minWidth}if(currentSettings.height){tmp.height=currentSettings.height}else if(currentSettings.type=='iframe'){tmp.height=currentSettings.minHeight}modal.content.css(tmp);if(!currentSettings.width){currentSettings.width=modal.content.outerWidth(true);resized.width=true}if(!currentSettings.height){currentSettings.height=modal.content.outerHeight(true);resized.height=true}modal.contentWrapper.css({opacity:1});if(!resizing)modal.contentWrapper.hide()}if(currentSettings.type!='image'&&currentSettings.type!='swf'){currentSettings.width=Math.max(currentSettings.width,currentSettings.minWidth);currentSettings.height=Math.max(currentSettings.height,currentSettings.minHeight)}var outerWrapper=getOuter(modal.contentWrapper);var outerWrapper2=getOuter(modal.wrapper);var outerContent=getOuter(modal.content);var tmp={content:{width:currentSettings.width,height:currentSettings.height},wrapper2:{width:currentSettings.width+outerContent.w.total,height:currentSettings.height+outerContent.h.total},wrapper:{width:currentSettings.width+outerContent.w.total+outerWrapper2.w.total,height:currentSettings.height+outerContent.h.total+outerWrapper2.h.total}};if(currentSettings.resizable){var maxHeight=modal.blockerVars?modal.blockerVars.height:$(window).height()-outerWrapper.h.border-(tmp.wrapper.height-currentSettings.height);var maxWidth=modal.blockerVars?modal.blockerVars.width:$(window).width()-outerWrapper.w.border-(tmp.wrapper.width-currentSettings.width);maxHeight-=currentSettings.padding*2;maxWidth-=currentSettings.padding*2;if(tmp.content.height>maxHeight||tmp.content.width>maxWidth){if(currentSettings.type=='image'||currentSettings.type=='swf'){var useW=currentSettings.imgWidth?currentSettings.imgWidth:currentSettings.width;var useH=currentSettings.imgHeight?currentSettings.imgHeight:currentSettings.height;var diffW=tmp.content.width-useW;var diffH=tmp.content.height-useH;if(diffH<0)diffH=0;if(diffW<0)diffW=0;var calcH=maxHeight-diffH;var calcW=maxWidth-diffW;var ratio=Math.min(calcH/useH,calcW/useW);calcW=Math.floor(useW*ratio);calcH=Math.floor(useH*ratio);tmp.content.height=calcH+diffH;tmp.content.width=calcW+diffW}else{tmp.content.height=Math.min(tmp.content.height,maxHeight);tmp.content.width=Math.min(tmp.content.width,maxWidth)}tmp.wrapper2={width:tmp.content.width+outerContent.w.total,height:tmp.content.height+outerContent.h.total};tmp.wrapper={width:tmp.content.width+outerContent.w.total+outerWrapper2.w.total,height:tmp.content.height+outerContent.h.total+outerWrapper2.h.total}}}if(currentSettings.type=='swf'){$('object, embed',modal.content).attr('width',tmp.content.width).attr('height',tmp.content.height)}else if(currentSettings.type=='image'){$('img',modal.content).css({width:tmp.content.width,height:tmp.content.height})}modal.content.css($.extend({},tmp.content,currentSettings.cssOpt.content));modal.wrapper.css($.extend({},tmp.wrapper2,currentSettings.cssOpt.wrapper2));if(!resizing)modal.contentWrapper.css($.extend({},tmp.wrapper,currentSettings.cssOpt.wrapper));if(currentSettings.type=='image'&&currentSettings.addImageDivTitle){$('img',modal.content).removeAttr('alt');var divTitle=$('div',modal.content);if(currentSettings.title!=currentSettings.defaultImgAlt&&currentSettings.title){if(divTitle.length==0){divTitle=$('<div>'+currentSettings.title+'</div>');modal.content.append(divTitle)}if(currentSettings.setWidthImgTitle){var outerDivTitle=getOuter(divTitle);divTitle.css({width:(tmp.content.width+outerContent.w.padding-outerDivTitle.w.total)+'px'})}}else if(divTitle.length=0){divTitle.remove()}}if(currentSettings.title)setTitle();tmp.wrapper.borderW=outerWrapper.w.border;tmp.wrapper.borderH=outerWrapper.h.border;setCurrentSettings(tmp.wrapper);setMargin()}function removeModal(e){debug('removeModal');if(e)e.preventDefault();if(modal.full&&modal.ready){$(document).unbind('keydown.nyroModal');if(!currentSettings.blocker)$(window).unbind('resize.nyroModal');modal.ready=false;modal.anim=true;modal.closing=true;if(modal.loadingShown||modal.transition){currentSettings.hideLoading(modal,currentSettings,function(){modal.loading.hide();modal.loadingShown=false;modal.transition=false;currentSettings.hideBackground(modal,currentSettings,endRemove)})}else{if(fixFF)modal.content.css({position:''});modal.wrapper.css({overflow:'hidden'});modal.content.css({overflow:'hidden'});$('iframe',modal.content).hide();if($.isFunction(currentSettings.beforeHideContent)){currentSettings.beforeHideContent(modal,currentSettings,function(){currentSettings.hideContent(modal,currentSettings,function(){endHideContent();currentSettings.hideBackground(modal,currentSettings,endRemove)})})}else{currentSettings.hideContent(modal,currentSettings,function(){endHideContent();currentSettings.hideBackground(modal,currentSettings,endRemove)})}}}if(e)return false}function showContentOrLoading(){debug('showContentOrLoading');if(modal.ready&&!modal.anim){if(modal.dataReady){if(modal.tmp.html()){modal.anim=true;if(modal.transition){fillContent();modal.animContent=true;currentSettings.hideTransition(modal,currentSettings,function(){modal.loading.hide();modal.transition=false;modal.loadingShown=false;endShowContent()})}else{currentSettings.hideLoading(modal,currentSettings,function(){modal.loading.hide();modal.loadingShown=false;fillContent();setMarginLoading();setMargin();modal.animContent=true;currentSettings.showContent(modal,currentSettings,endShowContent)})}}}else if(!modal.loadingShown&&!modal.transition){modal.anim=true;modal.loadingShown=true;if(modal.error)loadingError();else modal.loading.html(currentSettings.contentLoading);$(currentSettings.closeSelector,modal.loading).unbind('click.nyroModal').bind('click.nyroModal',removeModal);setMarginLoading();currentSettings.showLoading(modal,currentSettings,function(){modal.anim=false;showContentOrLoading()})}}}function ajaxLoaded(data){debug('AjaxLoaded: '+this.url);if(currentSettings.selector){var tmp={};var i=0;data=data.replace(/\r\n/gi,'nyroModalLN').replace(/<script(.|\s)*?\/script>/gi,function(x){tmp[i]=x;return'<pre style="display: none" class=nyroModalScript rel="'+(i++)+'"></pre>'});data=$('<div>'+data+'</div>').find(currentSettings.selector).html().replace(/<pre style="display: none;?" class="?nyroModalScript"? rel="(.?)"><\/pre>/gi,function(x,y,z){return tmp[y]}).replace(/nyroModalLN/gi,"\r\n")}modal.tmp.html(filterScripts(data));if(modal.tmp.html()){modal.dataReady=true;showContentOrLoading()}else loadingError()}function formDataLoaded(){debug('formDataLoaded');var jFrom=$(currentSettings.from);jFrom.attr('action',jFrom.attr('action')+currentSettings.selector);jFrom.attr('target','');$('input[name='+currentSettings.formIndicator+']',currentSettings.from).remove();var iframe=modal.tmp.children('iframe');var iframeContent=iframe.unbind('load').contents().find(currentSettings.selector||'body').not('script[src]');iframe.attr('src','about:blank');modal.tmp.html(iframeContent.html());if(modal.tmp.html()){modal.dataReady=true;showContentOrLoading()}else loadingError()}function iframeLoaded(){if((window.location.hostname&&currentSettings.url.indexOf(window.location.hostname)>-1)||currentSettings.url.indexOf('http://')){var iframe=$('iframe',modal.full).contents();var tmp={};if(currentSettings.titleFromIframe){tmp.title=iframe.find('title').text();if(!tmp.title){try{tmp.title=iframe.find('title').html()}catch(err){}}}var body=iframe.find('body');if(!currentSettings.height&&body.height())tmp.height=body.height();if(!currentSettings.width&&body.width())tmp.width=body.width();$.extend(initSettingsSize,tmp);$.nyroModalSettings(tmp)}}function galleryCounts(nb,total,elts,settings){if(total>1)settings.title+=(settings.title?' - ':'')+nb+'/'+total}function endHideContent(){debug('endHideContent');modal.anim=false;if(contentEltLast){contentEltLast.append(modal.content.contents());contentEltLast=null}else if(contentElt){contentElt.append(modal.content.contents());contentElt=null}modal.content.empty();gallery={};modal.contentWrapper.hide().children().remove().empty().attr('style','').hide();if(modal.closing||modal.transition)modal.contentWrapper.hide();modal.contentWrapper.css(currentSettings.cssOpt.wrapper).append(modal.content);showContentOrLoading()}function endRemove(){debug('endRemove');$(document).unbind('keydown',keyHandler);modal.anim=false;modal.full.remove();modal.full=null;if(isIE6){body.css({height:'',width:'',position:'',overflow:'',marginLeft:'',marginRight:''});$('html').css({overflow:''})}if($.isFunction(currentSettings.endRemove))currentSettings.endRemove(modal,currentSettings)}function endBackground(){debug('endBackground');modal.ready=true;modal.anim=false;showContentOrLoading()}function endShowContent(){debug('endShowContent');modal.anim=false;modal.animContent=false;modal.contentWrapper.css({opacity:''});fixFF=/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)&&parseFloat(browserVersion)<1.9&&currentSettings.type!='image';if(fixFF)modal.content.css({position:'fixed'});modal.content.append(modal.scriptsShown);if(currentSettings.type=='iframe')modal.content.find('iframe').attr('src',currentSettings.url);if($.isFunction(currentSettings.endShowContent))currentSettings.endShowContent(modal,currentSettings);if(shouldResize){shouldResize=false;$.nyroModalSettings({width:currentSettings.setWidth,height:currentSettings.setHeight});delete currentSettings['setWidth'];delete currentSettings['setHeight']}if(resized.width)setCurrentSettings({width:null});if(resized.height)setCurrentSettings({height:null})}function getHash(url){if(typeof url=='string'){var hashPos=url.indexOf('#');if(hashPos>-1)return url.substring(hashPos)}return''}function filterScripts(data){if(typeof data=='string')data=data.replace(/<\/?(html|head|body)([^>]*)>/gi,'');var tmp=new Array();$.each($.clean({0:data},this.ownerDocument),function(){if($.nodeName(this,"script")){if(!this.src||$(this).attr('rel')=='forceLoad'){if($(this).attr('rev')=='shown')modal.scriptsShown.push(this);else modal.scripts.push(this)}}else tmp.push(this)});return tmp}function getOuter(elm){elm=elm.get(0);var ret={h:{margin:getCurCSS(elm,'marginTop')+getCurCSS(elm,'marginBottom'),border:getCurCSS(elm,'borderTopWidth')+getCurCSS(elm,'borderBottomWidth'),padding:getCurCSS(elm,'paddingTop')+getCurCSS(elm,'paddingBottom')},w:{margin:getCurCSS(elm,'marginLeft')+getCurCSS(elm,'marginRight'),border:getCurCSS(elm,'borderLeftWidth')+getCurCSS(elm,'borderRightWidth'),padding:getCurCSS(elm,'paddingLeft')+getCurCSS(elm,'paddingRight')}};ret.h.outer=ret.h.margin+ret.h.border;ret.w.outer=ret.w.margin+ret.w.border;ret.h.inner=ret.h.padding+ret.h.border;ret.w.inner=ret.w.padding+ret.w.border;ret.h.total=ret.h.outer+ret.h.padding;ret.w.total=ret.w.outer+ret.w.padding;return ret}function getCurCSS(elm,name){var ret=parseInt($.curCSS(elm,name,true));if(isNaN(ret))ret=0;return ret}function debug(msg){if($.fn.nyroModal.settings.debug||currentSettings&&currentSettings.debug)nyroModalDebug(msg,modal,currentSettings||{})}function showBackground(elts,settings,callback){elts.bg.css({opacity:0}).fadeTo(500,0.75,callback)}function hideBackground(elts,settings,callback){elts.bg.fadeOut(300,callback)}function showLoading(elts,settings,callback){elts.loading.css({marginTop:settings.marginTopLoading+'px',marginLeft:settings.marginLeftLoading+'px',opacity:0}).show().animate({opacity:1},{complete:callback,duration:400})}function hideLoading(elts,settings,callback){callback()}function showContent(elts,settings,callback){elts.loading.css({marginTop:settings.marginTopLoading+'px',marginLeft:settings.marginLeftLoading+'px'}).show().animate({width:settings.width+'px',height:settings.height+'px',marginTop:settings.marginTop+'px',marginLeft:settings.marginLeft+'px'},{duration:350,complete:function(){elts.contentWrapper.css({width:settings.width+'px',height:settings.height+'px',marginTop:settings.marginTop+'px',marginLeft:settings.marginLeft+'px'}).show();elts.loading.fadeOut(200,callback)}})}function hideContent(elts,settings,callback){elts.contentWrapper.animate({height:'50px',width:'50px',marginTop:(-(25+settings.borderH)/2+settings.marginScrollTop)+'px',marginLeft:(-(25+settings.borderW)/2+settings.marginScrollLeft)+'px'},{duration:350,complete:function(){elts.contentWrapper.hide();callback()}})}function showTransition(elts,settings,callback){elts.loading.css({marginTop:elts.contentWrapper.css('marginTop'),marginLeft:elts.contentWrapper.css('marginLeft'),height:elts.contentWrapper.css('height'),width:elts.contentWrapper.css('width'),opacity:0}).show().fadeTo(400,1,function(){elts.contentWrapper.hide();callback()})}function hideTransition(elts,settings,callback){elts.contentWrapper.hide().css({width:settings.width+'px',height:settings.height+'px',marginLeft:settings.marginLeft+'px',marginTop:settings.marginTop+'px',opacity:1});elts.loading.animate({width:settings.width+'px',height:settings.height+'px',marginLeft:settings.marginLeft+'px',marginTop:settings.marginTop+'px'},{complete:function(){elts.contentWrapper.show();elts.loading.fadeOut(400,function(){elts.loading.hide();callback()})},duration:350})}function resize(elts,settings,callback){elts.contentWrapper.animate({width:settings.width+'px',height:settings.height+'px',marginLeft:settings.marginLeft+'px',marginTop:settings.marginTop+'px'},{complete:callback,duration:400})}function updateBgColor(elts,settings,callback){if(!$.fx.step.backgroundColor){elts.bg.css({backgroundColor:settings.bgColor});callback()}else elts.bg.animate({backgroundColor:settings.bgColor},{complete:callback,duration:400})}$($.fn.nyroModal.settings.openSelector).nyroModal()});var tmpDebug='';function nyroModalDebug(msg,elts,settings){if(elts.full&&elts.bg){elts.bg.prepend(msg+'<br />'+tmpDebug);tmpDebug=''}else tmpDebug+=msg+'<br />'}
Index: /extensions/rv_gmaps/branches/2.1/template/nyroModal/nyroModal.css
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/nyroModal/nyroModal.css	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/nyroModal/nyroModal.css	(revision 8301)
@@ -0,0 +1,105 @@
+div#nyroModalFull {
+	font-size: 12px;
+	color: #777;
+}
+div#nyroModalLoading {
+	border: 4px solid #777;
+	width: 150px;
+	height: 150px;
+	text-indent: -9999em;
+	background: #fff url(ajaxLoader.gif) no-repeat;
+	background-position: center;
+}
+div#nyroModalLoading.error {
+	border: 4px solid #f66;
+	line-height: 20px;
+	padding: 20px;
+	width: 300px;
+	height: 100px;
+	text-indent: 0;
+	background: #fff;
+}
+div#nyroModalWrapper {
+	background: #fff;
+	border: 4px solid #777;
+}
+a#closeBut {
+	position: absolute;
+	display: block;
+	top: -13px;
+	right: -13px;
+	width: 12px;
+	height: 12px;
+	text-indent: -9999em;
+	background: url(close.gif) no-repeat;
+	outline: 0;
+}
+h1#nyroModalTitle {
+	margin: 0;
+	padding: 0;
+	position: absolute;
+	top: -22px;
+	left: 5px;
+	font-size: 12px;
+	color: #ddd;
+}
+div#nyroModalContent {
+	overflow: auto;
+}
+div.wrapper div#nyroModalContent {
+	padding: 5px;
+}
+div.wrapperImg div#nyroModalContent {
+	position: relative;
+	overflow: hidden;
+	text-align: center;
+}
+div.wrapperImg img {
+	vertical-align: baseline;
+}
+div.wrapperImg div#nyroModalContent div {
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	background: black;
+	padding: 10px;
+	margin: 10px;
+	border: 1px white dotted;
+	overflow: hidden;
+	opacity: 0.2;
+	filter: alpha(opacity=20);
+}
+div.wrapperImg div#nyroModalContent div:hover {
+	opacity: 0.5;
+	filter: alpha(opacity=50);
+	cursor: help;
+}
+a.nyroModalPrev, a.nyroModalNext {
+	z-index: 105;
+	outline: none;
+	position: absolute;
+	top: 0;
+	height: 100%;
+	width: 40%;
+	cursor: pointer;
+	text-indent: -9999em;
+	background: left 20% no-repeat;
+	background-image: url(data:image/gif;base64,AAAA); /* Trick IE6 */
+}
+div.wrapperSwf a.nyroModalPrev, div.wrapperSwf a.nyroModalNext, div.wrapper a.nyroModalPrev, div.wrapper a.nyroModalNext {
+	height: 60%;
+	width: 20%;
+}
+a.nyroModalPrev {
+	left: 0;
+}
+a.nyroModalPrev:hover {
+	background-image: url(prev.gif);
+}
+a.nyroModalNext {
+	right: 0;
+	background-position: right 20%;
+}
+a.nyroModalNext:hover {
+	background-image: url(next.gif);
+}
Index: /extensions/rv_gmaps/branches/2.1/template/page_linker.js
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/page_linker.js	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/page_linker.js	(revision 8301)
@@ -0,0 +1,88 @@
+function PageLinker(map, aElementId)
+{
+  this._map = map;
+  this._elementId = aElementId;
+
+  PageLinker.url2Map( map );
+  
+  google.maps.Event.bind( this._map, "maptypechanged", this, this._regenerateUrl );
+  google.maps.Event.bind( this._map, "moveend", this, this._regenerateUrl );
+  if ( this._map.isLoaded() )
+    this._regenerateUrl();
+}
+
+PageLinker.getQueryVars = function()
+{
+  var vars = {};
+  var qString = unescape( top.location.search.substring(1) );
+  if (qString.length==0)
+    return vars;
+  var pairs = qString.split(/\&/);
+  for (var i=0; i<pairs.length; i++ )
+  {
+    var nameVal = pairs[i].split(/\=/);
+    vars[nameVal[0]] = nameVal[1];
+  }
+  return vars;
+};
+
+PageLinker.map2Url = function( map )
+{
+  var vars = PageLinker.getQueryVars();
+  vars['ll'] = map.getCenter().toUrlValue(5);
+  vars['z'] = map.getZoom();
+  if ( map.getCurrentMapType()===G_NORMAL_MAP )
+    { if (vars['t']) vars['t']=null; }
+  else
+    vars['t']=map.getCurrentMapType().getUrlArg();
+
+  var url = document.location.protocol+'//'+document.location.hostname+document.location.pathname;
+  var bFirst = true;
+  for (var key in vars)
+  {
+    url += bFirst ? "?" : "&";
+    bFirst = false;
+    url += key;
+    if (vars[key]!=null)
+      url += "="+vars[key];
+  }
+  return url;
+};
+
+PageLinker.url2Map = function( map )
+{
+  var vars = PageLinker.getQueryVars();
+  if ( !( (vars['z'] && vars['ll']) || vars['t'] ) )
+    return;
+
+  var mapType = G_NORMAL_MAP;
+  if  (vars['t'])
+  for (var i=0; i<map.getMapTypes().length; i++)
+    if ( map.getMapTypes()[i].getUrlArg()==vars['t'] )
+    {
+      mapType = map.getMapTypes()[i];break;
+    }
+  
+  if (vars['z'] && vars['ll'])
+  {
+    var zoom = parseFloat(vars['z']);
+    var ll = vars['ll'].split( "," );
+    if (ll.length==2)
+    {
+      var center = new google.maps.LatLng( ll[0], ll[1] );
+      map.setCenter( center, zoom, mapType );
+    }
+  }
+}
+
+
+PageLinker.prototype = {
+
+_regenerateUrl: function()
+{
+  var elt = document.getElementById( this._elementId );
+  if (!elt) return;
+  elt.href = PageLinker.map2Url(this._map);
+}
+
+}
Index: /extensions/rv_gmaps/branches/2.1/template/picture_map_content.tpl
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/picture_map_content.tpl	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/picture_map_content.tpl	(revision 8301)
@@ -0,0 +1,76 @@
+{html_head}
+<script src="http://maps.google.com/maps/api/js?sensor=false&amp;hl={$lang_info.code}" type="text/javascript"></script>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
+<script src="{$PLUGIN_ROOT_URL}/template/nyroModal/jquery.nyroModal-1.6.2.js" type="text/javascript"></script>
+<link href="{$PLUGIN_ROOT_URL}/template/nyroModal/nyroModal.css" rel="stylesheet" type="text/css">
+
+<style type="text/css">{literal}
+#mapPicture {
+	position:absolute;
+	width: 310px;
+}
+
+#map {
+	position:relative;
+	left: 320px;
+	margin-right: 320px;
+	height: 512px;
+	min-height: 512px;
+}
+
+#thumbPrev, #thumbNext {display:none;}
+{/literal}</style>
+{/html_head}
+
+<div id="mapPicture">
+<a href="{$U_NO_MAP}" title="{'return to normal view mode'|@translate}" rel="nofollow"><img src="{$TN_SRC}" alt="thumb"/></a>
+<br/>
+<a href="{$U_BLOWUP}" onclick="return blowupUrl(this.href);">{'More pictures near this location'|@translate}</a>
+<br/>
+{$COMMENT_IMG}
+<br/>
+</div>
+
+<div id="map"></div>
+
+<div style="clear:both"></div>
+<script type="text/javascript">{literal}
+//<![CDATA[
+function onLoad()
+{
+	var mapElement = document.getElementById("map");
+	var mapOpts = {
+{/literal}{if isset($coordinates)}
+		center: new google.maps.LatLng( {$coordinates.LAT}, {$coordinates.LON} ),
+		zoom : 12,
+{else}
+		center: new google.maps.LatLng(0,0),
+		zoom : 1,
+{/if}{literal}
+		mapTypeId: google.maps.MapTypeId.ROADMAP
+	};
+	
+	var map = new google.maps.Map( mapElement, mapOpts );
+
+{/literal}{if isset($coordinates)}
+	var marker = new google.maps.Marker( {ldelim}
+		position: map.getCenter(),
+		map: map
+		});
+{/if}{literal}
+}
+
+function blowupUrl(theUrl)
+{
+	jQuery.fx.off = true;
+	jQuery.nyroModalManual( {
+		url: theUrl,
+		forceType: 'iframe',
+		width: 1920
+	});
+	return false;
+}
+
+jQuery(document).ready( onLoad );
+//]]>
+{/literal}</script>
Index: /extensions/rv_gmaps/branches/2.1/template/style.css
===================================================================
--- /extensions/rv_gmaps/branches/2.1/template/style.css	(revision 8301)
+++ /extensions/rv_gmaps/branches/2.1/template/style.css	(revision 8301)
@@ -0,0 +1,147 @@
+
+HTML, BODY {
+	height: 100%;
+	max-height: 100%;
+	margin: 0;
+	padding: 0;
+	border: 0;
+}
+
+HTML {
+/* hide overflow:hidden from IE5/Mac */
+	overflow: hidden; /*get rid of scroll bars in IE */
+	/* */
+}
+
+BODY {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 12px;
+}
+
+
+#titlebar {
+	width: 100%;
+	height: 18px;
+	overflow: hidden;
+}
+
+
+#map {
+	overflow: auto;
+	position: absolute;
+	left: 0; width: 100%;
+	top: 18px; bottom: 0;
+}
+
+
+
+
+#titlebar .titlebar_links { float:right; }
+
+#titlebar .titlebar_title {
+  margin-left: 5px;
+  margin-right: 5px;
+}
+
+#titlebar .titlebar_title A {
+  font-size: 14px;
+  font-weight: bold;
+}
+
+#titlebar FORM {
+  display:inline;
+  margin:0;
+}
+
+#titlebar FORM INPUT {
+  border: 1px solid gray;
+  font-size:80%;
+}
+
+#titlebar FORM INPUT {
+  color: #404040;
+  background-color: #dddddd;
+}
+
+#titlebar FORM INPUT:focus {
+  color: black;
+  background-color: #ffffff;
+}
+
+#titlebar .titlebar_links A {
+  border: none;
+  text-decoration: none;
+}
+
+#titlebar .titlebar_links A SPAN {
+  text-decoration: underline;
+}
+
+#titlebar IMG {
+  border: none;
+  vertical-align: bottom;
+}
+
+
+#titlebar #dataLoadStatus {
+	min-width: 150px;
+	width: 150px;
+	margin-right: 10px;
+	margin-left: 5px;
+	font-weight: bold;
+}
+
+
+/* Info Window Structure is
+DIV.gmiw_header
+  SPAN#pwgImageCounters
+  A#gotoPrevImage
+  A#gotoNextImage
+  A#pwgImageBlowup
+DIV#pwgImageDetail
+  DIV.gmiw_imageTitle
+  DIV.gmiw_imageContent
+    DIV.gmiw_imageWrap
+      A IMG
+    DIV.gmiw_imageComment
+*/
+
+.gmiw_header A {
+	margin-left: 5px;
+	border: none;
+	text-decoration: none;
+}
+
+.gmiw_header IMG { vertical-align: bottom; }
+
+.gmiw_header A SPAN { text-decoration: underline; }
+
+.gmiw_header A#pwgImageBlowup {
+	margin-left: 15px;
+	font-weight: bold;
+}
+
+.gmiw_imageTitle {
+	font-size: 14px;
+	font-weight: bold;
+}
+
+.gmiw_imageContent {
+	min-width: 325px;
+	width: 325px;
+	min-height: 168px;
+	height: 168px;
+	overflow-y: auto;
+}
+
+.gmiw_imageWrap {
+	margin: 0 5px -3px 0; /* - for bottom something wrong with Geko and Opera ignored by IE6*/
+	float:left;
+	display:inline;
+}
+
+.gmiw_imageWrap A IMG { border-width: 1px; }
+
+.gmiw_imageComment {  display:inline; }
+
+
