]> git.openstreetmap.org Git - rails.git/commitdiff
Merge branch 'notes'
authorTom Hughes <tom@compton.nu>
Tue, 23 Apr 2013 21:40:21 +0000 (22:40 +0100)
committerTom Hughes <tom@compton.nu>
Tue, 23 Apr 2013 21:40:21 +0000 (22:40 +0100)
Conflicts:
Vendorfile

84 files changed:
Gemfile
Gemfile.lock
Vendorfile
app/assets/images/closed_note_marker.png [new file with mode: 0644]
app/assets/images/new_note_marker.png [new file with mode: 0644]
app/assets/images/open_note_marker.png [new file with mode: 0644]
app/assets/javascripts/application.js
app/assets/javascripts/browse.js
app/assets/javascripts/index.js
app/assets/javascripts/index/notes.js.erb [new file with mode: 0644]
app/assets/javascripts/oauth.js [new file with mode: 0644]
app/assets/javascripts/osm.js.erb
app/assets/javascripts/templates/notes/new.jst.ejs [new file with mode: 0644]
app/assets/javascripts/templates/notes/show.jst.ejs [new file with mode: 0644]
app/assets/stylesheets/common.css.scss
app/controllers/application_controller.rb
app/controllers/browse_controller.rb
app/controllers/notes_controller.rb [new file with mode: 0644]
app/controllers/site_controller.rb
app/helpers/application_helper.rb
app/helpers/geocoder_helper.rb
app/helpers/note_helper.rb [new file with mode: 0644]
app/models/client_application.rb
app/models/note.rb [new file with mode: 0644]
app/models/note_comment.rb [new file with mode: 0644]
app/models/notifier.rb
app/models/user.rb
app/views/browse/_map.html.erb
app/views/browse/note.html.erb [new file with mode: 0644]
app/views/diary_entry/_location.html.erb
app/views/layouts/_head.html.erb
app/views/notes/_description.html.erb [new file with mode: 0644]
app/views/notes/_note.gpx.builder [new file with mode: 0644]
app/views/notes/_note.json.jsonify [new file with mode: 0644]
app/views/notes/_note.rss.builder [new file with mode: 0644]
app/views/notes/_note.xml.builder [new file with mode: 0644]
app/views/notes/_notes_paging_nav.html.erb [new file with mode: 0644]
app/views/notes/_user.html.erb [new file with mode: 0644]
app/views/notes/feed.rss.builder [new file with mode: 0644]
app/views/notes/index.gpx.builder [new file with mode: 0644]
app/views/notes/index.json.jsonify [new file with mode: 0644]
app/views/notes/index.rss.builder [new file with mode: 0644]
app/views/notes/index.xml.builder [new file with mode: 0644]
app/views/notes/mine.html.erb [new file with mode: 0644]
app/views/notes/show.gpx.builder [new file with mode: 0644]
app/views/notes/show.json.jsonify [new file with mode: 0644]
app/views/notes/show.rss.builder [new file with mode: 0644]
app/views/notes/show.xml.builder [new file with mode: 0644]
app/views/notifier/note_comment_notification.html.erb [new file with mode: 0644]
app/views/notifier/note_comment_notification.text.erb [new file with mode: 0644]
app/views/site/index.html.erb
app/views/user/view.html.erb
config/example.application.yml
config/i18n-js.yml
config/initializers/action_view.rb [new file with mode: 0644]
config/initializers/mime_types.rb
config/locales/de.yml
config/locales/en.yml
config/openlayers.cfg
config/routes.rb
db/migrate/053_add_map_bug_tables.rb [new file with mode: 0644]
db/migrate/054_refactor_map_bug_tables.rb [new file with mode: 0644]
db/migrate/055_change_map_bug_comment_type.rb [new file with mode: 0644]
db/migrate/056_add_date_closed.rb [new file with mode: 0644]
db/migrate/057_add_map_bug_comment_event.rb [new file with mode: 0644]
db/migrate/20110508145337_cleanup_bug_tables.rb [new file with mode: 0644]
db/migrate/20110521142405_rename_bugs_to_notes.rb [new file with mode: 0644]
db/migrate/20121119165817_drop_nearby_place_from_notes.rb [new file with mode: 0644]
db/migrate/20121202155309_remove_author_name_from_note_comment.rb [new file with mode: 0644]
db/migrate/20121203124841_change_note_address_to_inet.rb [new file with mode: 0644]
db/migrate/20130328184137_add_write_notes_permission.rb [new file with mode: 0644]
db/structure.sql
lib/bounding_box.rb
lib/geo_record.rb
lib/migrate.rb
lib/nominatim.rb [new file with mode: 0644]
lib/osm.rb
test/fixtures/note_comments.yml [new file with mode: 0644]
test/fixtures/notes.yml [new file with mode: 0644]
test/functional/browse_controller_test.rb
test/functional/notes_controller_test.rb [new file with mode: 0644]
vendor/assets/ohauth/ohauth.js [new file with mode: 0644]
vendor/assets/ohauth/sha.js [new file with mode: 0644]
vendor/assets/openlayers/OpenLayers.js

diff --git a/Gemfile b/Gemfile
index 787a0864008fe0710c41e3307d5b85298309210c..f841dc19ae8be8016ed03f75558ffc0066f637ab 100644 (file)
--- a/Gemfile
+++ b/Gemfile
@@ -29,6 +29,7 @@ gem 'paperclip', '~> 2.0'
 gem 'deadlock_retry', '>= 1.2.0'
 gem 'i18n-js', '>= 3.0.0.rc2'
 gem 'rack-cors'
+gem 'jsonify-rails'
 
 # We need ruby-openid 2.2.0 or later for ruby 1.9 support
 gem 'ruby-openid', '>= 2.2.0'
index c9bd6607c5bc80748ab2dbf05d244bed31731889..5a7a2bba86ab61d43fe6418bb55db3b9ecf6c375 100644 (file)
@@ -67,6 +67,11 @@ GEM
       railties (>= 3.0, < 5.0)
       thor (>= 0.14, < 2.0)
     json (1.7.7)
+    jsonify (0.3.1)
+      multi_json (~> 1.0)
+    jsonify-rails (0.3.2)
+      actionpack
+      jsonify (< 0.4.0)
     jwt (0.1.8)
       multi_json (>= 1.5)
     libv8 (3.3.10.4)
@@ -183,6 +188,7 @@ DEPENDENCIES
   i18n-js (>= 3.0.0.rc2)
   iconv (= 0.1)
   jquery-rails
+  jsonify-rails
   libxml-ruby (>= 2.0.5)
   memcached (>= 1.4.1)
   minitest
index 43dd73fadaa995a4d90b59175fda04a18b9b2d7d..a56751196a8228cfc0c52a56dee1b2f2ddf7edf4 100644 (file)
@@ -29,6 +29,13 @@ folder 'vendor/assets' do
   folder 'jquery' do
     from 'git://github.com/jevin/Autogrow-Textarea.git' do
       file 'jquery.autogrowtextarea.js', 'jquery.autogrowtextarea.js'
+    end  
+  end
+
+  folder 'ohauth' do
+    from 'git://github.com/tmcw/ohauth.git' do
+      file 'ohauth.js'
+      file 'sha.js'
     end
   end
 end
diff --git a/app/assets/images/closed_note_marker.png b/app/assets/images/closed_note_marker.png
new file mode 100644 (file)
index 0000000..bf6d6bb
Binary files /dev/null and b/app/assets/images/closed_note_marker.png differ
diff --git a/app/assets/images/new_note_marker.png b/app/assets/images/new_note_marker.png
new file mode 100644 (file)
index 0000000..671cf42
Binary files /dev/null and b/app/assets/images/new_note_marker.png differ
diff --git a/app/assets/images/open_note_marker.png b/app/assets/images/open_note_marker.png
new file mode 100644 (file)
index 0000000..a580316
Binary files /dev/null and b/app/assets/images/open_note_marker.png differ
index 8d6c13503095b9d3282446ade0e19637116a9b4a..284ec77e618576c66f54984e5948c95c7ee1c8b7 100644 (file)
@@ -10,6 +10,7 @@
 //= require leaflet.pan
 //= require leaflet.zoom
 //= require i18n/translations
+//= require oauth
 //= require osm
 //= require piwik
 //= require map
index c3d67e57e215be0c7017ddc65fdb0114863f95d1..7149b3481a3ab2e4890c5ac7bf8bd293284a9e6a 100644 (file)
@@ -43,7 +43,27 @@ $(document).ready(function () {
     });
 
     var centre = bbox.getCenter();
-    updatelinks(centre.lng, centre.lat, 16, null, params.minlon, params.minlat, params.maxlon, params.maxlat);
+    updatelinks(centre.lon, centre.lat, 16, null, params.minlon, params.minlat, params.maxlon, params.maxlat);
+  } else if (params.type == "note") {
+    var object = {type: params.type, id: params.id};
+
+    map.setView([params.lat, params.lon], 16);
+
+    L.marker([params.lat, params.lon], { icon: getUserIcon() }).addTo(map);
+
+    var bbox = map.getBounds();
+
+    $("#loading").hide();
+    $("#browse_map .geolink").show();
+
+    $("a[data-editor=remote]").click(function () {
+      return remoteEditHandler(bbox);
+    });
+
+    updatelinks(params.lon, params.lat, 16, null, 
+                bbox.getWestLng(), bbox.getSouthLat(),
+                bbox.getEastLng(), bbox.getNorthLat(),
+                object);
   } else {
     $("#object_larger_map").hide();
     $("#object_edit").hide();
index e96ffbf02cffa713776da79b0b3864e45e38863b..7c80b01081395726d6c57f3e602a42b7ac4f0bbc 100644 (file)
@@ -2,6 +2,7 @@
 //= require index/browse
 //= require index/export
 //= require index/key
+//= require index/notes
 
 $(document).ready(function () {
   var permalinks = $("#permalink").detach().html();
diff --git a/app/assets/javascripts/index/notes.js.erb b/app/assets/javascripts/index/notes.js.erb
new file mode 100644 (file)
index 0000000..0728907
--- /dev/null
@@ -0,0 +1,281 @@
+//= require templates/notes/show
+//= require templates/notes/new
+
+$(document).ready(function () {
+  var params = OSM.mapParams();
+
+  var noteIcons = {
+    "new": L.icon({
+      iconUrl: "<%= image_path 'new_note_marker.png' %>",
+      iconSize: [22, 22],
+      iconAnchor: [11, 11]
+    }),
+    "open": L.icon({
+      iconUrl: "<%= image_path 'open_note_marker.png' %>",
+      iconSize: [22, 22],
+      iconAnchor: [11, 11]
+    }),
+    "closed": L.icon({
+      iconUrl: "<%= image_path 'closed_note_marker.png' %>",
+      iconSize: [22, 22],
+      iconAnchor: [11, 11]
+    })
+  };
+
+  var noteLayer = new L.LayerGroup();
+  var notes = {};
+  var newNote;
+
+  map.on("layeradd", function (e) {
+    if (e.layer == noteLayer) {
+      loadNotes();
+      map.on("moveend", loadNotes);
+    }
+  });
+
+  map.on("layerremove", function (e) {
+    if (e.layer == noteLayer) {
+      map.off("moveend", loadNotes);
+      noteLayer.clearLayers();
+      notes = {};
+    }
+  });
+
+  map.on("popupopen", function (e) {
+    $(e.popup._container).find(".comment").focus();
+  });
+
+  map.on("popupclose", function (e) {
+    if (newNote && e.popup == newNote._popup) {
+      $(newNote).oneTime(10, "removenote", function () {
+        map.removeLayer(newNote);
+        newNote = null;
+      });
+    }
+  });
+
+  if (OSM.STATUS != 'api_offline' && OSM.STATUS != 'database_offline') {
+    map.layersControl.addOverlay(noteLayer, I18n.t("browse.start_rjs.notes_layer_name"));
+
+    if (params.notes) map.addLayer(noteLayer);
+
+    if (params.note) {
+      $.ajax({
+        url: "/api/" + OSM.API_VERSION + "/notes/" + params.note + ".json",
+        success: function (feature) {
+          var marker = updateMarker(notes[feature.properties.id], feature);
+
+          notes[feature.properties.id] = marker;
+
+          map.addLayer(noteLayer);
+          marker.openPopup();
+        }
+      });
+    }
+  }
+
+  function updateMarker(marker, feature) {
+    if (marker)
+    {
+      marker.setIcon(noteIcons[feature.properties.status]);
+      marker._popup.setContent(createPopupContent(marker, feature.properties));
+    }
+    else
+    {
+      marker = L.marker(feature.geometry.coordinates.reverse(), {
+        icon: noteIcons[feature.properties.status],
+        opacity: 0.7
+      });
+
+      marker.addTo(noteLayer).bindPopup(
+        createPopupContent(marker, feature.properties),
+        popupOptions()
+      );
+    }
+
+    return marker;
+  }
+
+  var noteLoader;
+
+  function loadNotes() {
+    var bounds = map.getBounds();
+    var size = bounds.getSize();
+
+    if (size <= OSM.MAX_NOTE_REQUEST_AREA) {
+      var url = "/api/" + OSM.API_VERSION + "/notes.json?bbox=" + bounds.toBBOX();
+
+      if (noteLoader) noteLoader.abort();
+
+      noteLoader = $.ajax({
+        url: url,
+        success: function (json) {
+          var oldNotes = notes;
+
+          notes = {};
+
+          json.features.forEach(function (feature) {
+            var marker = oldNotes[feature.properties.id];
+
+            delete oldNotes[feature.properties.id];
+
+            notes[feature.properties.id] = updateMarker(marker, feature);
+          });
+
+          for (id in oldNotes) {
+            noteLayer.removeLayer(oldNotes[id]);
+          }
+
+          noteLoader = null;
+        }
+      });
+    }
+  };
+
+  function popupOptions() {
+    var mapSize = map.getSize();
+
+    return {
+      minWidth: 320,
+      maxWidth: mapSize.y * 1 / 3,
+      maxHeight: mapSize.y * 2 / 3,
+      offset: new L.Point(0, -3),
+      autoPanPadding: new L.Point(60, 40)
+    };
+  }
+
+  function createPopupContent(marker, properties) {
+    var content = $(JST["templates/notes/show"]({ note: properties }));
+
+    content.find("textarea").on("input", function (e) {
+      var form = e.target.form;
+
+      if ($(e.target).val() == "") {
+        $(form.close).val(I18n.t("javascripts.notes.show.resolve"));
+        $(form.comment).prop("disabled", true);
+      } else {
+        $(form.close).val(I18n.t("javascripts.notes.show.comment_and_resolve"));
+        $(form.comment).prop("disabled", false);
+      }
+    });
+
+    content.find("input[type=submit]").on("click", function (e) {
+      e.preventDefault();
+      var data = $(e.target).data();
+      updateNote(marker, e.target.form, data.method, data.url);
+    });
+
+    return content[0];
+  }
+
+  function createNote(marker, form, url) {
+    var location = marker.getLatLng();
+
+    $(form).find("input[type=submit]").prop("disabled", true);
+
+    $.ajax({
+      url: url,
+      type: "POST",
+      oauth: true,
+      data: {
+        lat: location.lat,
+        lon: location.lng,
+        text: $(form.text).val()
+      },
+      success: function (feature) {
+        notes[feature.properties.id] = updateMarker(marker, feature);
+        newNote = null;
+
+        $("#createnoteanchor").removeClass("disabled").addClass("geolink");
+      }
+    });
+  }
+
+  function updateNote(marker, form, method, url) {
+    $(form).find("input[type=submit]").prop("disabled", true);
+
+    $.ajax({
+      url: url,
+      type: method,
+      oauth: true,
+      data: {
+        text: $(form.text).val()
+      },
+      success: function (feature) {
+        if (feature.properties.status == "hidden") {
+          noteLayer.removeLayer(marker);
+
+          delete notes[feature.properties.id];
+        } else {
+          var popupContent = createPopupContent(marker, feature.properties);
+
+          marker.setIcon(noteIcons[feature.properties.status]);
+          marker._popup.setContent(popupContent);
+        }
+      }
+    });
+  }
+
+  $("#createnoteanchor").click(function (e) {
+    e.preventDefault();
+
+    if ($(e.target).hasClass("disabled")) return;
+
+    $(e.target).removeClass("geolink").addClass("disabled");
+
+    map.addLayer(noteLayer);
+
+    var mapSize = map.getSize();
+    var markerPosition;
+
+    if (mapSize.y > 800)
+    {
+      markerPosition = [mapSize.x / 2, mapSize.y / 2];
+    }
+    else if (mapSize.y > 400)
+    {
+      markerPosition = [mapSize.x / 2, 400];
+    }
+    else
+    {
+      markerPosition = [mapSize.x / 2, mapSize.y];
+    }
+
+    newNote = L.marker(map.containerPointToLatLng(markerPosition), {
+      icon: noteIcons["new"],
+      opacity: 0.7,
+      draggable: true
+    });
+
+    var popupContent = $(JST["templates/notes/new"]({ create_url: $(e.target).attr("href") }));
+
+    popupContent.find("textarea").on("input", function (e) {
+      var form = e.target.form;
+
+      if ($(e.target).val() == "") {
+        $(form.add).prop("disabled", true);
+      } else {
+        $(form.add).prop("disabled", false);
+      }
+    });
+
+    popupContent.find("input[type=submit]").on("click", function (e) {
+      e.preventDefault();
+      createNote(newNote, e.target.form, $(e.target).data("url"));
+    });
+
+    newNote.addTo(noteLayer).bindPopup(popupContent[0], popupOptions()).openPopup();
+
+    newNote.on("remove", function (e) {
+      $("#createnoteanchor").removeClass("disabled").addClass("geolink");
+    });
+
+    newNote.on("dragstart", function (e) {
+      $(newNote).stopTime("removenote");
+    });
+
+    newNote.on("dragend", function (e) {
+      e.target.openPopup();
+    });
+  });
+});
diff --git a/app/assets/javascripts/oauth.js b/app/assets/javascripts/oauth.js
new file mode 100644 (file)
index 0000000..40f685c
--- /dev/null
@@ -0,0 +1,25 @@
+//= require sha
+//= require ohauth
+
+$.ajaxPrefilter(function(options, jqxhr) {
+  if (options.oauth && OSM.oauth_token) {
+    var ohauth = window.ohauth;
+    var url = options.url.replace(/\?$/, "");
+    var params = {
+      oauth_consumer_key: OSM.oauth_consumer_key,
+      oauth_token: OSM.oauth_token,
+      oauth_signature_method: "HMAC-SHA1",
+      oauth_timestamp: ohauth.timestamp(),
+      oauth_nonce: ohauth.nonce()
+    };
+
+    params.oauth_signature = ohauth.signature(
+      OSM.oauth_consumer_secret,
+      OSM.oauth_token_secret,
+      ohauth.baseString(options.type, url, $.extend({}, params, jqxhr.data))
+    );
+
+    options.headers = options.headers || {};
+    options.headers.Authorization = "OAuth " + ohauth.authHeader(params);
+  }
+});
index f3c1c3607a834ddb8b5e6879e677ee63f3d46880..81c1e315217711a2c5d23631c4b8b0802dc2fb1d 100644 (file)
@@ -1,13 +1,14 @@
 OSM = {
 <% if defined?(PIWIK_LOCATION) and defined?(PIWIK_SITE) %>
-  PIWIK_LOCATION:   <%= PIWIK_LOCATION.to_json %>,
-  PIWIK_SITE:       <%= PIWIK_SITE.to_json %>,
+  PIWIK_LOCATION:        <%= PIWIK_LOCATION.to_json %>,
+  PIWIK_SITE:            <%= PIWIK_SITE.to_json %>,
 <% end %>
 
-  MAX_REQUEST_AREA: <%= MAX_REQUEST_AREA.to_json %>,
-  SERVER_URL:       <%= SERVER_URL.to_json %>,
-  API_VERSION:      <%= API_VERSION.to_json %>,
-  STATUS:           <%= STATUS.to_json %>,
+  MAX_REQUEST_AREA:      <%= MAX_REQUEST_AREA.to_json %>,
+  SERVER_URL:            <%= SERVER_URL.to_json %>,
+  API_VERSION:           <%= API_VERSION.to_json %>,
+  STATUS:                <%= STATUS.to_json %>,
+  MAX_NOTE_REQUEST_AREA: <%= MAX_NOTE_REQUEST_AREA.to_json %>,
 
   apiUrl: function (object) {
     var url = "/api/" + OSM.API_VERSION + "/" + object.type + "/" + object.id;
@@ -110,6 +111,12 @@ OSM = {
       mapParams.lat = (mapParams.minlat + mapParams.maxlat) / 2;
     }
 
+    mapParams.notes = params.notes == "yes";
+
+    if (params.note) {
+      mapParams.note = parseInt(params.note);
+    }
+
     var scale = parseFloat(params.scale);
     if (scale > 0) {
       mapParams.zoom = Math.log(360.0 / (scale * 512.0)) / Math.log(2.0);
diff --git a/app/assets/javascripts/templates/notes/new.jst.ejs b/app/assets/javascripts/templates/notes/new.jst.ejs
new file mode 100644 (file)
index 0000000..2f12227
--- /dev/null
@@ -0,0 +1,12 @@
+<div class="note">
+  <p><%- I18n.t('javascripts.notes.new.intro') %></p>
+  <form action="#">
+    <input type="hidden" name="lon">
+    <input type="hidden" name="lat">
+    <textarea class="comment" name="text" cols="40" rows="10"></textarea>
+    <br/>
+    <div class="buttons">
+      <input type="submit" name="add" value="<%- I18n.t('javascripts.notes.new.add') %>" data-url="<%- create_url %>" disabled="1">
+    </div>
+  </form>
+</div>
diff --git a/app/assets/javascripts/templates/notes/show.jst.ejs b/app/assets/javascripts/templates/notes/show.jst.ejs
new file mode 100644 (file)
index 0000000..04cb6df
--- /dev/null
@@ -0,0 +1,34 @@
+<div class="note">
+  <h2><a href="/?note=<%- note.id %>"><%- I18n.t('javascripts.notes.show.title', { id: note.id }) %></a></h2>
+  <% if (note.comments.some(function (comment) { return !comment.user })) { %>
+  <small class="warning"><%- I18n.t('javascripts.notes.show.anonymous_warning') %></small>
+  <% } %>
+  <% note.comments.forEach(function (comment) { %>
+  <div>
+    <small class="deemphasize">
+      <% if (comment.user) { %>
+        <%= I18n.t('javascripts.notes.show.' + comment.action + '_by', {
+           user: comment.user, user_url: comment.user_url,
+           time: I18n.l("time.formats.long", comment.date)
+        }) %>
+      <% } else { %>
+        <%- I18n.t('javascripts.notes.show.' + comment.action + '_by_anonymous', {
+           time: I18n.l("time.formats.long", comment.date)
+        }) %>
+      <% } %>
+    </small>
+    <div class="comment_body"><%= comment.html %></div>
+  </div>
+  <% }) %>
+  <% if (note.status == "open") { %>
+  <form action="#">
+    <textarea class="comment" name="text" cols="40" rows="5"></textarea>
+    <br/>
+    <div class="buttons">
+      <input type="submit" name="hide" value="<%- I18n.t('javascripts.notes.show.hide') %>" class="hide_unless_moderator" data-method="DELETE" data-url="<%- note.url %>">
+      <input type="submit" name="close" value="<%- I18n.t('javascripts.notes.show.resolve') %>" class="hide_unless_logged_in" data-method="POST" data-url="<%- note.close_url %>">
+      <input type="submit" name="comment" value="<%- I18n.t('javascripts.notes.show.comment') %>" data-method="POST" data-url="<%- note.comment_url %>" disabled="1">
+    </div>
+  </form>
+  <% } %>
+</div>
index 62e333db36d8828c6dd56a897410792f6ecf85b4..d20e4b4c4067431727da123c8a10cc6ab4168d49 100644 (file)
@@ -511,6 +511,7 @@ table {
 #greeting {
   float: right;
   padding-top: 3px;
+  margin-right: 5px;
 }
 
 .greeting-bar-unread {
@@ -537,6 +538,12 @@ table {
   background:#fff;
 }
 
+.leaflet-control-attribution a.disabled {
+  color: #99c9dc;
+  cursor: default;
+  text-decoration: none;
+}
+
 .site-index .leaflet-top,
 .site-export .leaflet-top {
   top: 10px !important;
@@ -550,6 +557,12 @@ table {
   left: 10px !important;
 }
 
+.leaflet-popup-scrolled {
+  padding-right: 20px;
+  border-bottom: 0px !important;
+  border-top: 0px !important;
+}
+
 /* Rules for edit menu */
 
 .menuicon {
@@ -922,12 +935,20 @@ ul.results-list li { border-bottom: 1px solid #ccc; }
   &:first-child {
     margin-top: 0;
   }
+  &.warning {
+    color: #ff7070;
+    font-weight: bold;
+  }
   h4, p {
     margin-bottom: 5px;
   }
   p, ul, .bbox {
     margin-left: 33.3333%;
   }
+  ul p {
+    margin-left: 0;
+    margin-bottom: 0;
+  }
   h4 {
     width: 33.3333%;
     float: left;
@@ -1488,6 +1509,9 @@ ul.secondary-actions {
       border-left: 0;
       padding-left: 0;
     }
+    &:last-child {
+      margin-right: 0px;
+    }
   }
 }
 
@@ -1677,3 +1701,53 @@ a.button.submit {
     }
   }
 }
+
+/* Rules for the user notes list */
+
+.note_list {
+  tr.creator {
+    background-color: #eeeeee;
+  }
+
+  td {
+    padding: 3px;
+  }
+
+  p {
+    margin-bottom: 0px;
+  }
+}
+
+/* Rules for the notes interface */
+
+.note {
+  h2 {
+    margin-bottom: 10px;
+  }
+
+  .warning {
+    display: block;
+    background-color: #ff7070;
+    padding: 4px 6px;
+    margin-bottom: 10px;
+  }
+
+  .comment_body {
+    margin-top: 4px;
+    margin-bottom: 4px;
+
+    p {
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+  }
+
+  .comment {
+    width: 100%;
+  }
+
+  .buttons {
+    margin-top: 5px;
+    text-align: right;
+  }
+}
index e5a2b354037dd85fa9864729ddf9059584df2c10..067fc6a511f5856404ef601084d536f21f0be843 100644 (file)
@@ -55,6 +55,10 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  def require_oauth
+    @oauth = @user.access_token(OAUTH_KEY) if @user and defined? OAUTH_KEY
+  end
+
   ##
   # requires the user to be logged in by the token or HTTP methods, or have an 
   # OAuth token with the right capability. this method is a bit of a pain to call 
@@ -112,6 +116,9 @@ class ApplicationController < ActionController::Base
   def require_allow_write_gpx
     require_capability(:allow_write_gpx)
   end
+  def require_allow_write_notes
+    require_capability(:allow_write_notes)
+  end
 
   ##
   # require that the user is a moderator, or fill out a helpful error message
index e5557280e6ee7f4824a2c8144fbfefebe1c28c6a..5526aacca05df6de55bb8c7087662dcaea829db2 100644 (file)
@@ -76,4 +76,13 @@ class BrowseController < ApplicationController
   rescue ActiveRecord::RecordNotFound
     render :action => "not_found", :status => :not_found
   end
+
+  def note
+    @type = "note"
+    @note = Note.find(params[:id])
+    @next = Note.find(:first, :order => "id ASC", :conditions => [ "status != 'hidden' AND id > :id", { :id => @note.id }] )
+    @prev = Note.find(:first, :order => "id DESC", :conditions => [ "status != 'hidden' AND id < :id", { :id => @note.id }] )
+  rescue ActiveRecord::RecordNotFound
+    render :action => "not_found", :status => :not_found
+  end
 end
diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb
new file mode 100644 (file)
index 0000000..36236ef
--- /dev/null
@@ -0,0 +1,328 @@
+class NotesController < ApplicationController
+
+  layout 'site', :only => [:mine]
+
+  before_filter :check_api_readable
+  before_filter :authorize_web, :only => [:mine]
+  before_filter :setup_user_auth, :only => [:create, :comment]
+  before_filter :authorize, :only => [:close, :destroy]
+  before_filter :require_moderator, :only => [:destroy]
+  before_filter :check_api_writable, :only => [:create, :comment, :close, :destroy]
+  before_filter :require_allow_write_notes, :only => [:create, :comment, :close, :destroy]
+  before_filter :set_locale, :only => [:mine]
+  after_filter :compress_output
+  around_filter :api_call_handle_error, :api_call_timeout
+
+  ##
+  # Return a list of notes in a given area
+  def index
+    # Figure out the bbox - we prefer a bbox argument but also
+    # support the old, deprecated, method with four arguments
+    if params[:bbox]
+      bbox = BoundingBox.from_bbox_params(params)
+    else
+      raise OSM::APIBadUserInput.new("No l was given") unless params[:l]
+      raise OSM::APIBadUserInput.new("No r was given") unless params[:r]
+      raise OSM::APIBadUserInput.new("No b was given") unless params[:b]
+      raise OSM::APIBadUserInput.new("No t was given") unless params[:t]
+
+      bbox = BoundingBox.from_lrbt_params(params)
+    end
+
+    # Get any conditions that need to be applied
+    notes = closed_condition(Note.scoped)
+
+    # Check that the boundaries are valid
+    bbox.check_boundaries
+
+    # Check the the bounding box is not too big
+    bbox.check_size(MAX_NOTE_REQUEST_AREA)
+
+    # Find the notes we want to return
+    @notes = notes.bbox(bbox).order("updated_at DESC").limit(result_limit).preload(:comments)
+
+    # Render the result
+    respond_to do |format|
+      format.rss
+      format.xml
+      format.json
+      format.gpx
+    end
+  end
+
+  ##
+  # Create a new note
+  def create
+    # Check the arguments are sane
+    raise OSM::APIBadUserInput.new("No lat was given") unless params[:lat]
+    raise OSM::APIBadUserInput.new("No lon was given") unless params[:lon]
+    raise OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
+
+    # Extract the arguments
+    lon = params[:lon].to_f
+    lat = params[:lat].to_f
+    comment = params[:text]
+
+    # Include in a transaction to ensure that there is always a note_comment for every note
+    Note.transaction do
+      # Create the note
+      @note = Note.create(:lat => lat, :lon => lon)
+      raise OSM::APIBadUserInput.new("The note is outside this world") unless @note.in_world?
+
+      # Save the note
+      @note.save!
+
+      # Add a comment to the note
+      add_comment(@note, comment, "opened")
+    end
+
+    # Return a copy of the new note
+    respond_to do |format|
+      format.xml { render :action => :show }
+      format.json { render :action => :show }
+    end
+  end
+
+  ##
+  # Add a comment to an existing note
+  def comment
+    # Check the arguments are sane
+    raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+    raise OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
+
+    # Extract the arguments
+    id = params[:id].to_i
+    comment = params[:text]
+
+    # Find the note and check it is valid
+    @note = Note.find(id)
+    raise OSM::APINotFoundError unless @note
+    raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
+    raise OSM::APINoteAlreadyClosedError.new(@note) if @note.closed?
+
+    # Add a comment to the note
+    Note.transaction do
+      add_comment(@note, comment, "commented")
+    end
+
+    # Return a copy of the updated note
+    respond_to do |format|
+      format.xml { render :action => :show }
+      format.json { render :action => :show }
+    end
+  end
+
+  ##
+  # Close a note
+  def close
+    # Check the arguments are sane
+    raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+
+    # Extract the arguments
+    id = params[:id].to_i
+    comment = params[:text]
+
+    # Find the note and check it is valid
+    @note = Note.find_by_id(id)
+    raise OSM::APINotFoundError unless @note
+    raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
+    raise OSM::APINoteAlreadyClosedError.new(@note) if @note.closed?
+
+    # Close the note and add a comment
+    Note.transaction do
+      @note.close
+
+      add_comment(@note, comment, "closed")
+    end
+
+    # Return a copy of the updated note
+    respond_to do |format|
+      format.xml { render :action => :show }
+      format.json { render :action => :show }
+    end
+  end 
+
+  ##
+  # Get a feed of recent notes and comments
+  def feed
+    # Get any conditions that need to be applied
+    notes = closed_condition(Note.scoped)
+
+    # Process any bbox
+    if params[:bbox]
+      bbox = BoundingBox.from_bbox_params(params)
+
+      bbox.check_boundaries
+      bbox.check_size(MAX_NOTE_REQUEST_AREA)
+
+      notes = notes.bbox(bbox)
+    end
+
+    # Find the comments we want to return
+    @comments = NoteComment.where(:note_id => notes).order("created_at DESC").limit(result_limit).preload(:note)
+
+    # Render the result
+    respond_to do |format|
+      format.rss
+    end
+  end
+
+  ##
+  # Read a note
+  def show
+    # Check the arguments are sane
+    raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+
+    # Find the note and check it is valid
+    @note = Note.find(params[:id])
+    raise OSM::APINotFoundError unless @note
+    raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
+
+    # Render the result
+    respond_to do |format|
+      format.xml
+      format.rss
+      format.json
+      format.gpx
+    end
+  end
+
+  ##
+  # Delete (hide) a note
+  def destroy
+    # Check the arguments are sane
+    raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+
+    # Extract the arguments
+    id = params[:id].to_i
+    comment = params[:text]
+
+    # Find the note and check it is valid
+    @note = Note.find(id)
+    raise OSM::APINotFoundError unless @note
+    raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
+
+    # Mark the note as hidden
+    Note.transaction do
+      @note.status = "hidden"
+      @note.save
+
+      add_comment(@note, comment, "hidden")
+    end
+
+    # Return a copy of the updated note
+    respond_to do |format|
+      format.xml { render :action => :show }
+      format.json { render :action => :show }
+    end
+  end
+
+  ##
+  # Return a list of notes matching a given string
+  def search
+    # Check the arguments are sane
+    raise OSM::APIBadUserInput.new("No query string was given") unless params[:q]
+
+    # Get any conditions that need to be applied
+    @notes = closed_condition(Note.scoped)
+    @notes = @notes.joins(:comments).where("note_comments.body ~ ?", params[:q])
+
+    # Find the notes we want to return
+    @notes = @notes.order("updated_at DESC").limit(result_limit).preload(:comments)
+
+    # Render the result
+    respond_to do |format|
+      format.rss { render :action => :index }
+      format.xml { render :action => :index }
+      format.json { render :action => :index }
+      format.gpx { render :action => :index }
+    end
+  end
+
+  ##
+  # Display a list of notes by a specified user
+  def mine
+    if params[:display_name] 
+      if @this_user = User.active.find_by_display_name(params[:display_name])
+        @title =  t 'note.mine.title', :user => @this_user.display_name 
+        @heading =  t 'note.mine.heading', :user => @this_user.display_name 
+        @description = t 'note.mine.subheading', :user => render_to_string(:partial => "user", :object => @this_user)
+        @page = (params[:page] || 1).to_i 
+        @page_size = 10
+        @notes = @this_user.notes.order("updated_at DESC, id").uniq.offset((@page - 1) * @page_size).limit(@page_size).preload(:comments => :author)
+      else
+        @title = t 'user.no_such_user.title' 
+        @not_found_user = params[:display_name] 
+
+        render :template => 'user/no_such_user', :status => :not_found 
+      end 
+    end
+  end
+
+private 
+  #------------------------------------------------------------ 
+  # utility functions below. 
+  #------------------------------------------------------------   
+  ##
+  # Render an OK response
+  def render_ok
+    if params[:format] == "js"
+      render :text => "osbResponse();", :content_type => "text/javascript" 
+    else
+      render :text => "ok " + @note.id.to_s + "\n", :content_type => "text/plain" if @note
+      render :text => "ok\n", :content_type => "text/plain" unless @note
+    end
+  end
+
+  ##
+  # Get the maximum number of results to return
+  def result_limit
+    if params[:limit] and params[:limit].to_i > 0 and params[:limit].to_i < 10000
+      params[:limit].to_i
+    else
+      100
+    end
+  end
+
+  ##
+  # Generate a condition to choose which bugs we want based
+  # on their status and the user's request parameters
+  def closed_condition(notes)
+    if params[:closed]
+      closed_since = params[:closed].to_i
+    else
+      closed_since = 7
+    end
+       
+    if closed_since < 0
+      notes = notes.where("status != 'hidden'")
+    elsif closed_since > 0
+      notes = notes.where("(status = 'open' OR (status = 'closed' AND closed_at > '#{Time.now - closed_since.days}'))")
+    else
+      notes = notes.where("status = 'open'")
+    end
+
+    return notes
+  end
+
+  ##
+  # Add a comment to a note
+  def add_comment(note, text, event)
+    attributes = { :visible => true, :event => event, :body => text }
+
+    if @user  
+      attributes[:author_id] = @user.id
+    else  
+      attributes[:author_ip] = request.remote_ip
+    end
+
+    comment = note.comments.create(attributes, :without_protection => true)
+
+    note.comments.map { |c| c.author }.uniq.each do |user|
+      if user and user != @user
+        Notifier.note_comment_notification(comment, user).deliver
+      end
+    end
+  end
+end
index 606143f4f9ceaaa48fe79c40a1d6def05216f0a9..1ea3f7cb0ac6f8fb4adb34d044a2841f2d9656d0 100644 (file)
@@ -5,6 +5,7 @@ class SiteController < ApplicationController
   before_filter :authorize_web
   before_filter :set_locale
   before_filter :require_user, :only => [:edit]
+  before_filter :require_oauth, :only => [:index]
 
   def index
     unless STATUS == :database_readonly or STATUS == :database_offline
index 49608c4a0d42a9df70e3f2c6b7bbac4bb05d38b3..b91710b9c6f3dfa86df5cfc82532b00294adf1f7 100644 (file)
@@ -26,6 +26,7 @@ module ApplicationHelper
     css << ".hide_if_user_#{@user.id} { display: none !important }" if @user;
     css << ".show_if_user_#{@user.id} { display: inline !important }" if @user;
     css << ".hide_unless_administrator { display: none !important }" unless @user and @user.administrator?;
+    css << ".hide_unless_moderator { display: none !important }" unless @user and @user.moderator?;
 
     return content_tag(:style, css, :type => "text/css")
   end
@@ -95,4 +96,8 @@ module ApplicationHelper
       I18n.t("html.dir")
     end
   end
+
+  def friendly_date(date)
+    content_tag(:span, time_ago_in_words(date), :title => l(date, :format => :friendly))
+  end
 end
index f5519ddc3fcd5cc0eca4d9d8ebc3638141d7eea3..8f662bde73d304e7944b3c1195dca1b2cf407db1 100644 (file)
@@ -22,22 +22,6 @@ module GeocoderHelper
   end
 
   def describe_location(lat, lon, zoom = nil, language = nil)
-    zoom = zoom || 14
-    language = language || request.user_preferred_languages.join(',')
-    url = "http://nominatim.openstreetmap.org/reverse?lat=#{lat}&lon=#{lon}&zoom=#{zoom}&accept-language=#{language}"
-
-    begin
-      response = OSM::Timer.timeout(4) do
-        REXML::Document.new(Net::HTTP.get(URI.parse(url)))
-      end
-    rescue Exception
-      response = nil
-    end
-
-    if response and result = response.get_text("reversegeocode/result")
-      result.to_s
-    else
-      "#{number_with_precision(lat, :precision => 3)}, #{number_with_precision(lon, :precision => 3)}"
-    end
+    Nominatim.describe_location(lat, lon, zoom, language)
   end
 end
diff --git a/app/helpers/note_helper.rb b/app/helpers/note_helper.rb
new file mode 100644 (file)
index 0000000..f2bff86
--- /dev/null
@@ -0,0 +1,17 @@
+module NoteHelper
+  def note_event(at, by)
+    if by.nil?
+      I18n.t("browse.note.at_html", :when => friendly_date(at)).html_safe
+    else
+      I18n.t("browse.note.at_by_html", :when => friendly_date(at), :user => note_author(by)).html_safe
+    end
+  end
+
+  def note_author(author, link_options = {})
+    if author.nil?
+      ""
+    else
+      link_to h(author.display_name), link_options.merge({:controller => "user", :action => "view", :display_name => author.display_name})
+    end
+  end
+end
index 9a074fb30b21ed0421026a963f46fe6247a3d2ab..0619e75a3695696ee3c04ed5ee3fee61cb88a5a8 100644 (file)
@@ -16,7 +16,8 @@ class ClientApplication < ActiveRecord::Base
   attr_accessible :name, :url, :support_url, :callback_url,
                   :allow_read_prefs, :allow_write_prefs,
                   :allow_write_diary, :allow_write_api,
-                  :allow_read_gpx, :allow_write_gpx
+                  :allow_read_gpx, :allow_write_gpx,
+                  :allow_write_notes
 
   before_validation :generate_keys, :on => :create
 
@@ -87,7 +88,8 @@ protected
   # have to say up-front what permissions they want and when users sign up they
   # can agree or not agree to each of them.
   PERMISSIONS = [:allow_read_prefs, :allow_write_prefs, :allow_write_diary,
-                 :allow_write_api, :allow_read_gpx, :allow_write_gpx ]
+                 :allow_write_api, :allow_read_gpx, :allow_write_gpx,
+                 :allow_write_notes]
 
   def generate_keys
     self.key = OAuth::Helper.generate_key(40)[0,40]
diff --git a/app/models/note.rb b/app/models/note.rb
new file mode 100644 (file)
index 0000000..bb56c5c
--- /dev/null
@@ -0,0 +1,76 @@
+class Note < ActiveRecord::Base
+  include GeoRecord
+
+  has_many :comments, :class_name => "NoteComment",
+                      :foreign_key => :note_id,
+                      :order => :created_at,
+                      :conditions => { :visible => true }
+
+  validates_presence_of :id, :on => :update
+  validates_uniqueness_of :id
+  validates_numericality_of :latitude, :only_integer => true
+  validates_numericality_of :longitude, :only_integer => true
+  validates_presence_of :closed_at if :status == "closed"
+  validates_inclusion_of :status, :in => ["open", "closed", "hidden"]
+  validate :validate_position
+
+  attr_accessible :lat, :lon
+
+  after_initialize :set_defaults
+
+  # Sanity check the latitude and longitude and add an error if it's broken
+  def validate_position
+    errors.add(:base, "Note is not in the world") unless in_world?
+  end
+
+  # Close a note
+  def close
+    self.status = "closed"
+    self.closed_at = Time.now.getutc
+    self.save
+  end
+
+  # Return a flattened version of the comments for a note
+  def flatten_comment(separator_char, upto_timestamp = :nil)
+    resp = ""
+    comment_no = 1
+    self.comments.each do |comment|
+      next if upto_timestamp != :nil and comment.created_at > upto_timestamp
+      resp += (comment_no == 1 ? "" : separator_char)
+      resp += comment.body if comment.body
+      resp += " [ " 
+      resp += comment.author.display_name if comment.author
+      resp += " " + comment.created_at.to_s + " ]"
+      comment_no += 1
+    end
+
+    return resp
+  end
+
+  # Check if a note is visible
+  def visible?
+    status != "hidden"
+  end
+
+  # Check if a note is closed
+  def closed?
+    not closed_at.nil?
+  end
+
+  # Return the author object, derived from the first comment
+  def author
+    self.comments.first.author
+  end
+
+  # Return the author IP address, derived from the first comment
+  def author_ip
+    self.comments.first.author_ip
+  end
+
+private
+
+  # Fill in default values for new notes
+  def set_defaults
+    self.status = "open" unless self.attribute_present?(:status)
+  end
+end
diff --git a/app/models/note_comment.rb b/app/models/note_comment.rb
new file mode 100644 (file)
index 0000000..07d43cd
--- /dev/null
@@ -0,0 +1,17 @@
+class NoteComment < ActiveRecord::Base
+  belongs_to :note, :foreign_key => :note_id, :touch => true
+  belongs_to :author, :class_name => "User", :foreign_key => :author_id
+
+  validates_presence_of :id, :on => :update
+  validates_uniqueness_of :id
+  validates_presence_of :note_id
+  validates_associated :note
+  validates_presence_of :visible
+  validates_associated :author
+  validates_inclusion_of :event, :in => [ "opened", "closed", "reopened", "commented", "hidden" ]
+
+  # Return the comment text
+  def body
+    RichText.new("text", read_attribute(:body))
+  end
+end
index 2a5bb15bc96e003693c3f5e27da794eecb425353..5972a700b8af794c9246c777df171a458e445820 100644 (file)
@@ -6,7 +6,7 @@ class Notifier < ActionMailer::Base
 
   def signup_confirm(user, token)
     @locale = user.preferred_language_from(I18n.available_locales)
-    
+
     # If we are passed an email address verification token, create
     # the confirumation URL for account activation.
     #
@@ -19,7 +19,7 @@ class Notifier < ActionMailer::Base
                      :display_name => user.display_name,
                      :confirm_string => token.token)
     end
-      
+
     mail :to => user.email,
          :subject => I18n.t('notifier.signup_confirm.subject', :locale => @locale)
   end
@@ -67,7 +67,7 @@ class Notifier < ActionMailer::Base
     mail :to => trace.user.email,
          :subject => I18n.t('notifier.gpx_notification.failure.subject', :locale => @locale)
   end
-  
+
   def message_notification(message)
     @locale = message.recipient.preferred_language_from(I18n.available_locales)
     @to_user = message.recipient.display_name
@@ -123,6 +123,28 @@ class Notifier < ActionMailer::Base
          :subject => I18n.t('notifier.friend_notification.subject', :user => friend.befriender.display_name, :locale => @locale)
   end
 
+  def note_comment_notification(comment, recipient)
+    @locale = recipient.preferred_language_from(I18n.available_locales)
+    @noteurl = browse_note_url(comment.note, :host => SERVER_URL)
+    @place = Nominatim.describe_location(comment.note.lat, comment.note.lon, 14, @locale)
+    @comment = comment.body
+    @owner = recipient == comment.note.author
+
+    if comment.author
+      @commenter = comment.author.display_name
+    else
+      @commenter = I18n.t("notifier.note_comment_notification.anonymous")
+    end
+
+    if @owner
+      subject = I18n.t('notifier.note_comment_notification.subject_own', :commenter => @commenter)
+    else
+      subject = I18n.t('notifier.note_comment_notification.subject_other', :commenter => @commenter)
+    end
+
+    mail :to => recipient.email, :subject => subject
+  end
+
 private
 
   def from_address(name, type, id, digest)
index 2e312119f8d13e669e7b941890b65932d18ca837..778afbf8a9c7ae26d76339905209a447ae9e92eb 100644 (file)
@@ -12,6 +12,8 @@ class User < ActiveRecord::Base
   has_many :tokens, :class_name => "UserToken"
   has_many :preferences, :class_name => "UserPreference"
   has_many :changesets, :order => 'created_at DESC'
+  has_many :note_comments, :foreign_key => :author_id
+  has_many :notes, :through => :note_comments
 
   has_many :client_applications
   has_many :oauth_tokens, :class_name => "OauthToken", :order => "authorized_at desc", :include => [:client_application]
index c72040955920c6100aecf44a2bb9695707779c0b..ed3cc0faf169b829b828caab84b00ad67a1bce1d 100644 (file)
@@ -2,7 +2,7 @@
 </iframe>
 
 <div id="browse_map" class='clearfix content_map'>
-  <% if map.instance_of? Changeset or (map.instance_of? Node and map.version > 1) or map.visible %>
+  <% if map.instance_of? Changeset or (map.instance_of? Node and map.version > 1) or map.visible? %>
 
   <% content_for :head do %>
     <%= javascript_include_tag "browse" %>
          :maxlon => bbox.max_lon,
          :maxlat => bbox.max_lat
        }
+     elsif map.instance_of? Note
+       data = {
+         :type => "note",
+         :id   => map.id,
+         :lon  => map.lon,
+         :lat  => map.lat
+       }
      else
        data = {
          :type    => map.class.name.downcase,
 
 <ul class='secondary-actions clearfix'>
   <li>
-    <%= link_to t("browse.map.larger.area"),
-                root_path(:box => "yes"),
-                :id => "area_larger_map",
-                :class => "geolink bbox" %>
+    <% if map.instance_of? Note -%>
+      <%= link_to t("browse.map.larger.area"),
+                  root_path(:notes => "yes"),
+                  :id => "area_larger_map",
+                  :class => "geolink bbox" %>
+    <% else -%>
+      <%= link_to t("browse.map.larger.area"),
+                  root_path(:box => "yes"),
+                  :id => "area_larger_map",
+                  :class => "geolink bbox" %>
+    <% end -%>
   </li>
   <li>
     <%= link_to h(t("browse.map.edit.area")) + content_tag(:span, "▼", :class => "menuicon"),
diff --git a/app/views/browse/note.html.erb b/app/views/browse/note.html.erb
new file mode 100644 (file)
index 0000000..740646e
--- /dev/null
@@ -0,0 +1,67 @@
+<% content_for :head do %>
+<%= stylesheet_link_tag 'browse' %>
+<% end %>
+
+<% content_for :heading do %>
+  <h2>
+    <%= image_tag "#{@note.status}_note_marker.png", :alt => @note.status %>
+    <%= t "browse.note.#{@note.status}_title", :note_name => @note.id %>
+  </h2>
+<% end %>
+
+<%= render :partial => "navigation" %>
+
+<%= render :partial => "map", :object => @note %>
+
+<div class='column-1'>
+
+  <% if @note.comments.find { |comment| comment.author.nil? } -%>
+  <div class='browse-section common warning'>
+    <%= t "javascripts.notes.show.anonymous_warning" %>
+  </div>
+  <% end -%>
+
+  <div class='browse-section common'>
+    <div>
+      <h4><%= t "browse.note.opened" %></h4>
+      <p><%= note_event(@note.created_at, @note.author) %></p>
+    </div>
+
+    <% if @note.status == "closed" %>
+      <div>
+        <h4><%= t "browse.note.closed" %></h4>
+        <p><%= note_event(@note.closed_at, @note.comments.last.author) %></p>
+      </div>  
+    <% elsif @note.comments.length > 1 %>
+      <div>
+        <h4><%= t "browse.note.last_modified" %></h4>
+        <p><%= note_event(@note.updated_at, @note.comments.last.author) %></p>
+      </div>  
+    <% end %>
+
+    <div>
+      <h4><%= t "browse.note.description" %></h4>
+      <p><%= h(@note.comments.first.body) %></p>
+    </div>
+
+    <div>
+      <h4><%= t "browse.node_details.coordinates" %></h4>
+      <p><div class="geo"><%= link_to ("<span class='latitude'>#{number_with_delimiter(@note.lat)}</span>, <span class='longitude'>#{number_with_delimiter(@note.lon)}</span>".html_safe), {:controller => 'site', :action => 'index', :lat => h(@note.lat), :lon => h(@note.lon), :zoom => "18"} %></div></p>
+    </div>
+  </div>
+
+  <% if @note.comments.length > 1 %>
+    <div class='browse-section clearfix'>
+      <h4><%= t "browse.note.comments" %></h4>
+      <ul>
+        <% @note.comments[1..-1].each do |comment| %>
+          <li>
+            <%= comment.body.to_html %>
+            <small class="deemphasize"><%= note_event(comment.created_at, comment.author) %></small>
+          </li>
+        <% end %>
+      </ul>
+    </div>
+  <% end %>
+
+</div>
index 4779471de2184b8b0c0d879abad9353b79433a76..a3ba473a8a67e54f11e08cfc79f314e9b3a4201a 100644 (file)
@@ -2,8 +2,6 @@
 
 <a href="<%= url_for :controller => 'site', :action => 'index', :lat => location.latitude, :lon => location.longitude, :zoom => 14 %>">
 <abbr class="geo" title="<%= number_with_precision(location.latitude, :precision => 4) %>; <%= number_with_precision(location.longitude, :precision => 4) %>">
-<% cache(:controller => 'diary_entry', :action => 'view', :display_name => location.user.display_name, :id => location.id, :part => "location") do %>
 <%= describe_location location.latitude, location.longitude, 14, location.language_code %>
-<% end %>
 </abbr>
 </a>
index 19bed2bd3f7640eacc5ac3cc11e3197d0c4c9c4d..84f566e81b8280a92ef53d975abe1fe04726d456 100644 (file)
     I18n.defaultLocale = "<%= I18n.default_locale %>";
     I18n.locale = "<%= I18n.locale %>";
     I18n.fallbacks = true;
-
-    <% if @user and !@user.home_lon.nil? and !@user.home_lat.nil? %>
+    <% if @user and !@user.home_lon.nil? and !@user.home_lat.nil? -%>
     OSM.home = <%= { :lat => @user.home_lat, :lon => @user.home_lon }.to_json.html_safe %>;
-    <% end %>
-
-    <% if session[:location] %>
+    <% end -%>
+    <% if session[:location] -%>
     OSM.location = <%= session[:location].to_json.html_safe %>;
-    <% end %>
-
+    <% end -%>
     OSM.preferred_editor = <%= preferred_editor.to_json.html_safe %>;
+    <% if @oauth -%>
+    OSM.oauth_token = "<%= @oauth.token %>";
+    OSM.oauth_token_secret = "<%= @oauth.secret %>";
+    OSM.oauth_consumer_key = "<%= @oauth.client_application.key %>";
+    OSM.oauth_consumer_secret = "<%= @oauth.client_application.secret %>";
+    <% end -%>
   </script>
   <title><%= t 'layouts.project_name.title' %><%= ' | '+ @title if @title %></title>
 </head>
diff --git a/app/views/notes/_description.html.erb b/app/views/notes/_description.html.erb
new file mode 100644 (file)
index 0000000..761b69e
--- /dev/null
@@ -0,0 +1,12 @@
+<div>
+  <% description.comments.each do |comment| -%>
+  <div class="note-comment" style="margin-top: 5px">
+    <% if comment.author.nil? -%>
+    <div class="note-comment-description" style="font-size: smaller; color: #999999"><%= t "note.description.#{comment.event}_at", :when => friendly_date(comment.created_at) %></div>
+    <% else -%>
+    <div class="note-comment-description" style="font-size: smaller; color: #999999"><%= t "note.description.#{comment.event}_at_by", :when => friendly_date(comment.created_at), :user => note_author(comment.author, :only_path => false) %></div>
+    <% end -%>
+    <div class="note-comment-text"><%= comment.body %></div>
+  </div>
+  <% end -%>
+</div>
diff --git a/app/views/notes/_note.gpx.builder b/app/views/notes/_note.gpx.builder
new file mode 100644 (file)
index 0000000..22d9283
--- /dev/null
@@ -0,0 +1,18 @@
+xml.wpt("lon" => note.lon, "lat" => note.lat) do
+  xml.desc do
+    xml.cdata! render(:partial => "description", :object => note, :formats => [ :html ])
+  end
+
+  xml.extension do
+    if note.status = "open"
+      xml.closed "0"
+    else
+      xml.closed "1"
+    end
+
+    xml.id note.id
+    xml.url note_url(note, :format => params[:format])
+    xml.comment_url comment_note_url(note, :format => params[:format])
+    xml.close_url close_note_url(note, :format => params[:format])
+  end
+end
diff --git a/app/views/notes/_note.json.jsonify b/app/views/notes/_note.json.jsonify
new file mode 100644 (file)
index 0000000..c702d92
--- /dev/null
@@ -0,0 +1,33 @@
+json.type "Feature"
+
+json.geometry do
+  json.type "Point"
+  json.coordinates [ note.lon, note.lat ]
+end
+
+json.properties do
+  json.id note.id
+  json.url note_url(note, :format => params[:format])
+  json.comment_url comment_note_url(note, :format => params[:format])
+  json.close_url close_note_url(note, :format => params[:format])
+  json.date_created note.created_at
+  json.status note.status
+  json.closed_at note.closed_at if note.status == "closed"
+
+  json.comments(note.comments) do |comment|
+    json.date comment.created_at
+
+    if comment.author
+      json.uid comment.author.id
+      json.user comment.author.display_name
+      json.user_url user_url(:display_name => comment.author.display_name)
+    end
+
+    json.action comment.event
+
+    if comment.body
+      json.text comment.body.to_text
+      json.html comment.body.to_html
+    end
+  end
+end
diff --git a/app/views/notes/_note.rss.builder b/app/views/notes/_note.rss.builder
new file mode 100644 (file)
index 0000000..fbd217b
--- /dev/null
@@ -0,0 +1,24 @@
+xml.item do
+  location = describe_location(note.lat, note.lon, 14, locale)
+
+  if note.status == "closed"
+    xml.title t('note.rss.closed', :place => location)
+  elsif note.comments.length > 1
+    xml.title t('note.rss.comment', :place => location)
+  else
+    xml.title t('note.rss.new', :place => location)
+  end
+
+  xml.link browse_note_url(note)
+  xml.guid note_url(note)
+  xml.description render(:partial => "description", :object => note, :formats => [ :html ])
+
+  if note.author
+    xml.author note.author_display_name
+  end
+
+  xml.pubDate note.updated_at.to_s(:rfc822)
+  xml.geo :lat, note.lat
+  xml.geo :long, note.lon
+  xml.georss :point, "#{note.lat} #{note.lon}"
+end
diff --git a/app/views/notes/_note.xml.builder b/app/views/notes/_note.xml.builder
new file mode 100644 (file)
index 0000000..259f704
--- /dev/null
@@ -0,0 +1,31 @@
+xml.note("lon" => note.lon, "lat" => note.lat) do
+  xml.id note.id
+  xml.url note_url(note, :format => params[:format])
+  xml.comment_url comment_note_url(note, :format => params[:format])
+  xml.close_url close_note_url(note, :format => params[:format])
+  xml.date_created note.created_at
+  xml.status note.status
+
+  if note.status == "closed"
+    xml.date_closed note.closed_at
+  end
+
+  xml.comments do
+    note.comments.each do |comment|
+      xml.comment do
+        xml.date comment.created_at
+
+        if comment.author
+          xml.uid comment.author.id
+          xml.user comment.author.display_name
+          xml.user_url user_url(:display_name => comment.author.display_name)
+        end
+
+        if comment.body
+          xml.text comment.body.to_text
+          xml.html comment.body.to_html
+        end
+      end
+    end
+  end
+end
diff --git a/app/views/notes/_notes_paging_nav.html.erb b/app/views/notes/_notes_paging_nav.html.erb
new file mode 100644 (file)
index 0000000..108cbb3
--- /dev/null
@@ -0,0 +1,17 @@
+<p>
+
+<% if @page > 1 %>
+<%= link_to t('changeset.changeset_paging_nav.previous'), params.merge({ :page => @page - 1 }) %>
+<% else %>
+<%= t('changeset.changeset_paging_nav.previous') %>
+<% end %>
+
+| <%= t('changeset.changeset_paging_nav.showing_page', :page => @page) %> |
+
+<% if @notes.size < @page_size %>
+<%= t('changeset.changeset_paging_nav.next') %>
+<% else %>
+<%= link_to t('changeset.changeset_paging_nav.next'), params.merge({ :page => @page + 1 }) %>
+<% end %>
+
+</p>
diff --git a/app/views/notes/_user.html.erb b/app/views/notes/_user.html.erb
new file mode 100644 (file)
index 0000000..0e95076
--- /dev/null
@@ -0,0 +1 @@
+<%= link_to user.display_name, :controller => "user", :action => "view", :display_name => user.display_name %>
diff --git a/app/views/notes/feed.rss.builder b/app/views/notes/feed.rss.builder
new file mode 100644 (file)
index 0000000..4733c1b
--- /dev/null
@@ -0,0 +1,52 @@
+xml.instruct!
+
+xml.rss("version" => "2.0", 
+        "xmlns:geo" => "http://www.w3.org/2003/01/geo/wgs84_pos#",
+        "xmlns:georss" => "http://www.georss.org/georss") do
+  xml.channel do
+    xml.title t('note.rss.title')
+    xml.description t('note.rss.description_area', :min_lat => @min_lat, :min_lon => @min_lon, :max_lat => @max_lat, :max_lon => @max_lon )
+    xml.link url_for(:controller => "site", :action => "index", :only_path => false)
+
+    @comments.each do |comment|
+      location = describe_location(comment.note.lat, comment.note.lon, 14, locale)
+
+      xml.item do
+        if comment.event == "closed"
+          xml.title t('note.rss.closed', :place => location)
+        elsif comment.event == "commented"
+          xml.title t('note.rss.comment', :place => location)
+        elsif comment.event == "opened"
+          xml.title t('note.rss.new', :place => location)
+        else
+          xml.title "unknown event"
+        end
+        
+        xml.link url_for(:controller => "browse", :action => "note", :id => comment.note.id, :only_path => false)
+        xml.guid url_for(:controller => "browse", :action => "note", :id => comment.note.id, :only_path => false)
+
+        description_text = ""
+
+        if comment.event == "commented" and not comment.nil?
+          description_text += "<b>Comment:</b><br>"
+          description_text += comment.body.to_html
+          description_text += "<br>"
+        end
+
+        description_text += "<b>Full note:</b><br>"
+        description_text += comment.note.flatten_comment("<br>", comment.created_at)
+
+        xml.description description_text 
+
+        if comment.author
+          xml.author comment.author.display_name
+        end
+
+        xml.pubDate comment.created_at.to_s(:rfc822)
+        xml.geo :lat, comment.note.lat
+        xml.geo :long, comment.note.lon
+        xml.georss :point, "#{comment.note.lat} #{comment.note.lon}"
+      end
+    end
+  end
+end
diff --git a/app/views/notes/index.gpx.builder b/app/views/notes/index.gpx.builder
new file mode 100644 (file)
index 0000000..7a30460
--- /dev/null
@@ -0,0 +1,7 @@
+xml.instruct!
+
+xml.gpx("version" => "1.1", 
+        "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
+        "xsi:schemaLocation" => "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd") do
+  xml << render(:partial => "note", :collection => @notes)
+end
diff --git a/app/views/notes/index.json.jsonify b/app/views/notes/index.json.jsonify
new file mode 100644 (file)
index 0000000..cb75d41
--- /dev/null
@@ -0,0 +1,5 @@
+json.type "FeatureCollection"
+
+json.features(@notes) do |note|
+  json.ingest! render(:partial => "note", :object => note)
+end
diff --git a/app/views/notes/index.rss.builder b/app/views/notes/index.rss.builder
new file mode 100644 (file)
index 0000000..d6ee2bb
--- /dev/null
@@ -0,0 +1,13 @@
+xml.instruct!
+
+xml.rss("version" => "2.0", 
+        "xmlns:geo" => "http://www.w3.org/2003/01/geo/wgs84_pos#",
+        "xmlns:georss" => "http://www.georss.org/georss") do
+  xml.channel do
+    xml.title t('note.rss.title')
+    xml.description t('note.rss.description_area', :min_lat => @min_lat, :min_lon => @min_lon, :max_lat => @max_lat, :max_lon => @max_lon )
+    xml.link url_for(:controller => "site", :action => "index", :only_path => false)
+
+    xml << render(:partial => "note", :collection => @notes)
+  end
+end
diff --git a/app/views/notes/index.xml.builder b/app/views/notes/index.xml.builder
new file mode 100644 (file)
index 0000000..38b239a
--- /dev/null
@@ -0,0 +1,3 @@
+xml.instruct!
+
+xml << render(:partial => "note", :collection => @notes)
diff --git a/app/views/notes/mine.html.erb b/app/views/notes/mine.html.erb
new file mode 100644 (file)
index 0000000..fd0e291
--- /dev/null
@@ -0,0 +1,35 @@
+<% content_for :heading do %>
+  <h2><%= @heading %></h2>
+  <p><%= raw @description %></p>
+<% end %>
+
+<%= render :partial => 'notes_paging_nav' %>
+
+<table class="note_list">
+  <tr>
+    <th></th>
+    <th><%= t'note.mine.id' %></th>
+    <th><%= t'note.mine.creator' %></th>
+    <th><%= t'note.mine.description' %></th>
+    <th><%= t'note.mine.created_at' %></th>
+    <th><%= t'note.mine.last_changed' %></th>
+  </tr>
+<% @notes.each do |note| -%>
+  <tr<% if note.author != @user2 %> class="creator"<% end %>>
+    <td>
+      <% if note.status == "closed" %>
+        <%= image_tag("closed_note_marker.png", :alt => 'closed') %>
+      <% else %>
+        <%= image_tag("open_note_marker.png", :alt => 'open') %>
+      <% end %>
+    </td>
+    <td><%= link_to note.id.to_s, :controller => "browse", :action => "note", :id => note.id %></td>
+    <td><%= note_author(note.author) %></td>
+    <td><%= note.comments.first.body.to_html %></td>   
+    <td><%= t 'note.mine.ago_html', :when => friendly_date(note.created_at) %></td>
+    <td><%= t 'note.mine.ago_html', :when => friendly_date(note.updated_at) %></td>
+  </tr>
+<% end -%>
+</table>
+
+<%= render :partial => 'notes_paging_nav' %>
diff --git a/app/views/notes/show.gpx.builder b/app/views/notes/show.gpx.builder
new file mode 100644 (file)
index 0000000..e54d772
--- /dev/null
@@ -0,0 +1,7 @@
+xml.instruct!
+
+xml.gpx("version" => "1.1", 
+        "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
+        "xsi:schemaLocation" => "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd") do
+  xml << render(:partial => "note", :object => @note)
+end
diff --git a/app/views/notes/show.json.jsonify b/app/views/notes/show.json.jsonify
new file mode 100644 (file)
index 0000000..3e5685f
--- /dev/null
@@ -0,0 +1 @@
+json.ingest! render(:partial => "note", :object => @note)
diff --git a/app/views/notes/show.rss.builder b/app/views/notes/show.rss.builder
new file mode 100644 (file)
index 0000000..e566ff0
--- /dev/null
@@ -0,0 +1,13 @@
+xml.instruct!
+
+xml.rss("version" => "2.0", 
+        "xmlns:geo" => "http://www.w3.org/2003/01/geo/wgs84_pos#",
+        "xmlns:georss" => "http://www.georss.org/georss") do
+  xml.channel do
+    xml.title t('note.rss.title')
+    xml.description t('note.rss.description_item', :id => @note.id)
+    xml.link url_for(:controller => "site", :action => "index", :only_path => false)
+
+    xml << render(:partial => "note", :object => @note)
+  end
+end
diff --git a/app/views/notes/show.xml.builder b/app/views/notes/show.xml.builder
new file mode 100644 (file)
index 0000000..cfb28c2
--- /dev/null
@@ -0,0 +1,3 @@
+xml.instruct!
+
+xml << render(:partial => "note", :object => @note)
diff --git a/app/views/notifier/note_comment_notification.html.erb b/app/views/notifier/note_comment_notification.html.erb
new file mode 100644 (file)
index 0000000..b17fe67
--- /dev/null
@@ -0,0 +1,13 @@
+<p><%= t 'notifier.note_comment_notification.greeting' %></p>
+
+<% if @owner %>
+<p><%= t 'notifier.note_comment_notification.your_note', :commenter => @commenter, :place => @place %></p>
+<% else %>
+<p><%= t 'notifier.note_comment_notification.commented_note', :commenter => @commenter, :place => @place %></p>
+<% end %>
+
+==
+<%= @comment.to_html %>
+==
+
+<p><%= raw t 'notifier.note_comment_notification.details', :url => link_to(@noteurl, @noteurl) %></p>
diff --git a/app/views/notifier/note_comment_notification.text.erb b/app/views/notifier/note_comment_notification.text.erb
new file mode 100644 (file)
index 0000000..81306f9
--- /dev/null
@@ -0,0 +1,13 @@
+<%= t 'notifier.note_comment_notification.greeting' %>
+
+<% if @owner %>
+<%= t 'notifier.note_comment_notification.your_note', :commenter => @commenter, :place => @place %>
+<% else %>
+<%= t 'notifier.note_comment_notification.commented_note', :commenter => @commenter, :place => @place %>
+<% end %>
+
+==
+<%= @comment.to_text %>
+==
+
+<%= t 'notifier.note_comment_notification.details', :url => @noteurl %>
index 88bf4907320a8b98247ed5d5ecd5867ad2fc2fa7..3efdd9289fd873fbb9a4697777c2406dc52b50f3 100644 (file)
 
 <div id="map">
   <div id="permalink">
-    <a href="/" id="permalinkanchor" class="geolink llz layers object"><%= t 'site.index.permalink' %></a>
-    <a href="/" id="shortlinkanchor"><%= t 'site.index.shortlink' %></a>
+    <ul class="secondary-actions">
+      <li><a href="/" id="permalinkanchor" class="geolink llz layers object"><%= t 'site.index.permalink' %></a></li>
+      <li><a href="/" id="shortlinkanchor"><%= t 'site.index.shortlink' %></a></li>
+      <li><%= link_to t("site.index.createnote"), notes_url(:format => :json),
+          :id => "createnoteanchor",
+          :data => { :minzoom => 12 },
+          :title => "javascripts.site.createnote_tooltip",
+          :class => "geolink"
+      %></li>
+    </ul>
   </div>
 </div>
 
@@ -38,3 +46,4 @@
     </tr>
   </table>
 </div>
index 67619a5369cdb76294320da9110d066153614cf8..cf74fc0e0b9fbfaef0484fbe37a3ddce9ee4b1f9 100644 (file)
@@ -10,6 +10,9 @@
             <%= link_to t('user.view.my edits'), :controller => 'changeset', :action => 'list', :display_name => @user.display_name %>
             <span class='count-number'><%= number_with_delimiter(@user.changesets.size) %></span>
           </li>
+          <li>
+            <%= link_to t('user.view.my notes'), :controller => 'notes', :action=> 'mine' %>
+          </li>
           <li>
             <%= link_to t('user.view.my traces'), :controller => 'trace', :action=>'mine' %>
             <span class='count-number'><%= number_with_delimiter(@user.traces.size) %></span>
@@ -49,6 +52,9 @@
             <%= link_to t('user.view.edits'), :controller => 'changeset', :action => 'list', :display_name => @this_user.display_name %>
             <span class='count-number'><%= number_with_delimiter(@this_user.changesets.size) %></span>
           </li>
+          <li>
+            <%= link_to t('user.view.notes'), :controller => 'notes', :action=> 'mine' %>
+          </li>
           <li>
             <%= link_to t('user.view.traces'), :controller => 'trace', :action => 'list', :display_name => @this_user.display_name %>
             <span class='count-number'><%= number_with_delimiter(@this_user.traces.size) %></span>
index 249e447735ac11f10ccb23fc233c77d8a7ca6459..30f367f1cc0562a3391beabd0e7cd2a00381e93f 100644 (file)
@@ -27,6 +27,8 @@ defaults: &defaults
   max_number_of_nodes: 50000
   # Maximum number of nodes that can be in a way (checked on save)
   max_number_of_way_nodes: 2000
+  # The maximum area you're allowed to request notes from, in square degrees
+  max_note_request_area: 25
   # Zoom level to use for postcode results from the geocoder
   postcode_zoom: 15
   # Zoom level to use for geonames results from the geocoder
@@ -74,6 +76,8 @@ defaults: &defaults
   default_editor: "potlatch2"
   # OAuth consumer key for Potlatch 2
   #potlatch2_key: ""
+  # OAuth consumer key for the web site
+  #oauth_key: ""
   # Whether to require users to view the CTs before continuing to edit...
   require_terms_seen: false
   # Whether to require users to agree to the CTs before editing
index 982d60da74b5a24326adceb1c1c3f1e346f3e139..4882a4357c4a7f56cb38983e5b34581d3fff2ca3 100644 (file)
@@ -23,6 +23,8 @@
 translations:
   - file: "app/assets/javascripts/i18n/translations.js"
     only:
+    - "*.date"
+    - "*.time"
     - "*.browse.start_rjs.*"
     - "*.export.start_rjs.*"
     - "*.javascripts.*"
diff --git a/config/initializers/action_view.rb b/config/initializers/action_view.rb
new file mode 100644 (file)
index 0000000..1789ec1
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Make :formats work when rendering one partial from another
+#
+# Taken from https://github.com/rails/rails/pull/6626
+#
+module ActionView
+  class AbstractRenderer #:nodoc:
+    def prepend_formats(formats)
+      formats = Array(formats)
+      return if formats.empty?
+      @lookup_context.formats = formats | @lookup_context.formats
+    end
+  end
+
+  class PartialRenderer
+    def setup_with_formats(context, options, block)
+      prepend_formats(options[:formats])
+      setup_without_formats(context, options, block)
+    end
+
+    alias_method_chain :setup, :formats
+  end
+
+  class TemplateRenderer
+    def render_with_formats(context, options)
+      prepend_formats(options[:formats])
+      render_without_formats(context, options)
+    end
+
+    alias_method_chain :render, :formats
+  end
+end
index c676f6e46c50aa019fcb728a648bd0998d8ec89e..be247274f290811f0ccf61b7dee2b6a488343bc9 100644 (file)
@@ -4,3 +4,4 @@
 # Mime::Type.register "text/richtext", :rtf
 # Mime::Type.register_alias "text/html", :iphone
 Mime::Type.register "application/x-amf", :amf
+Mime::Type.register "application/gpx+xml", :gpx
index 31ee8d8454618b03f404a6f39836873cc474d57c..338c8bbf1cc06b5141e7966fcc9ddae174e453a7 100644 (file)
@@ -953,6 +953,22 @@ de:
       history_disabled_tooltip: Reinzoomen um Änderungen für diesen Bereich anzuzeigen
       history_tooltip: Änderungen für diesen Bereich anzeigen
       history_zoom_alert: Du musst näher heranzoomen, um die Chronik zu sehen
+    osb:
+      Fixed Error: Behobener Fehler
+      Unresolved Error: Offener Fehler
+      Description: Beschreibung
+      Comment: Kommentar
+      Has been fixed: Der Fehler wurde bereits behoben. Es kann jedoch bis zu einigen Tagen dauern, bis die Kartenansicht aktualisiert wird.
+      Comment/Close: Kommentieren/Schließen
+      Nickname: Benutzername
+      Add comment: Kommentar hinzufügen
+      Mark as fixed: Als behoben markieren
+      Cancel: Abbrechen
+      Create OpenStreetBug: OpenStreetBug melden
+      Create bug: Bug anlegen
+      Bug description: Fehlerbeschreibung
+      Create: Anlegeeen
+      Permalink: Permalink
   layouts: 
     community: Gemeinschaft
     community_blogs: Blogs
index 04ad99f129e0cf242079007709ff1056a01580ea..ba23b11df7047423548488484b51b9dbabb1df3d 100644 (file)
@@ -121,6 +121,8 @@ en:
         next_relation_tooltip: "Next relation"
         prev_changeset_tooltip: "Previous changeset"
         next_changeset_tooltip: "Next changeset"
+        prev_note_tooltip: "Previous note"
+        next_note_tooltip: "Next note"
     changeset_details:
       created_at: "Created at:"
       closed_at: "Closed at:"
@@ -157,11 +159,13 @@ en:
         node: "View node on larger map"
         way: "View way on larger map"
         relation: "View relation on larger map"
+        note: "View note on larger map"
       edit:
         area: "Edit area"
         node: "Edit node"
         way: "Edit way"
         relation: "Edit relation"
+        note: "Edit note"
     node_details:
       coordinates: "Coordinates:"
       part_of: "Part of:"
@@ -221,6 +225,7 @@ en:
       download_xml: "Download XML"
       view_history: "View history"
     start_rjs:
+      notes_layer_name: "Browse Notes"
       data_layer_name: "Browse Map Data"
       data_frame_title: "Data"
       zoom_or_select: "Zoom in or select an area of the map to view"
@@ -280,6 +285,16 @@ en:
       download_xml: "Download XML"
       view_history: "View history"
       edit: "Edit way"
+    note:
+      open_title: "Unresolved issue: %{note_name}"
+      closed_title: "Resolved issue: %{note_name}"
+      opened: "Opened:"
+      last_modified: "Last modified:"
+      closed: "Closed:"
+      at_html: "%{when} ago"
+      at_by_html: "%{when} ago by %{user}"
+      description: "Description:"
+      comments: "Comments:"
   changeset:
     changeset_paging_nav:
       showing_page: "Page %{page}"
@@ -1192,6 +1207,14 @@ en:
       greeting: "Hi,"
       hopefully_you: "Someone (possibly you) has asked for the password to be reset on this email address's openstreetmap.org account."
       click_the_link: "If this is you, please click the link below to reset your password."
+    note_comment_notification:
+      anonymous: An anonymous user
+      subject_own: "[OpenStreetMap] %{commenter} has commented on one of your notes"
+      subject_other: "[OpenStreetMap] %{commenter} has commented on a note you are interested in"
+      greeting: "Hi,"
+      your_note: "%{commenter} has left a comment on one of your map notes near %{place}."
+      commented_note: "%{commenter} has left a comment on a map note you have commented on. The note is near %{place}."
+      details: "More details about the note can be found at %{url}."
   message:
     inbox:
       title: "Inbox"
@@ -1266,6 +1289,7 @@ en:
       js_2: "OpenStreetMap uses JavaScript for its slippy map."
       permalink: Permalink
       shortlink: Shortlink
+      createnote: Add a note
       license:
         copyright: "Copyright OpenStreetMap and contributors, under an open license"
         license_url: "http://openstreetmap.org/copyright"
@@ -1676,6 +1700,7 @@ en:
       new diary entry: new diary entry
       my edits: my edits
       my traces: my traces
+      my notes: my map notes
       my settings: my settings
       my comments: my comments
       oauth settings: oauth settings
@@ -1685,6 +1710,7 @@ en:
       diary: diary
       edits: edits
       traces: traces
+      notes: map notes
       remove as friend: unfriend
       add as friend: add friend
       mapper since: "Mapper since:"
@@ -1955,6 +1981,33 @@ en:
       back: "View all blocks"
       revoker: "Revoker:"
       needs_view: "The user needs to log in before this block will be cleared."
+  note:
+    description:
+      opened_at: "Created %{when} ago"
+      opened_at_by: "Created %{when} ago by %{user}"
+      commented_at: "Updated %{when} ago"
+      commented_at_by: "Updated %{when} ago by %{user}"
+      closed_at: "Resolved %{when} ago"
+      closed_at_by: "Resolved %{when} ago by %{user}"
+      reopened_at: "Reactivated %{when} ago"
+      reopened_at_by: "Reactivated %{when} ago by %{user}"
+    rss:
+      title: "OpenStreetMap Notes"
+      description_area: "A list of notes, reported, commented on or closed in your area [(%{min_lat}|%{min_lon}) -- (%{max_lat}|%{max_lon})]"
+      description_item: "An rss feed for note %{id}"
+      closed: "closed note (near %{place})"
+      new: "new note (near %{place})"
+      comment: "new comment (near %{place})"
+    mine:
+      title: "Notes submitted or commented on by %{user}"
+      heading: "%{user}'s notes"
+      subheading: "Notes submitted or commented on by %{user}"
+      id: "Id"
+      creator: "Creator"
+      description: "Description"
+      created_at: "Created at"
+      last_changed: "Last changed"
+      ago_html: "%{when} ago"
   javascripts:
     map:
       base:
@@ -1971,6 +2024,28 @@ en:
       history_tooltip: View edits for this area
       history_disabled_tooltip: Zoom in to view edits for this area
       history_zoom_alert: You must zoom in to view edits for this area
+      createnote_tooltip: Add a note to the map
+      createnote_disabled_tooltip: Zoom in to add a note to the map
+      createnote_zoom_alert: You must zoom in to add a note to the map
+    notes:
+      new:
+        intro: "In order to improve the map the information you enter is shown to other mappers, so please be as descriptive and precise as possible when moving the marker to the correct position and entering your note below."
+        add: Add Note
+      show:
+        title: Note %{id}
+        anonymous_warning: This note includes comments from anonymous users which should be independently verified.
+        opened_by: "created by <a href='%{user_url}'>%{user}</a> at %{time}"
+        opened_by_anonymous: "created by anonymous at %{time}"
+        commented_by: "comment from <a href='%{user_url}'>%{user}</a> at %{time}"
+        commented_by_anonymous: "comment from anonymous at %{time}"
+        closed_by: "resolved by <a href='%{user_url}'>%{user}</a> at %{time}"
+        closed_by_anonymous: "resolved by anonymous at %{time}"
+        reopened_by: "reactivated by <a href='%{user_url}'>%{user}</a> at %{time}"
+        reopened_by_anonymous: "reactivated by anonymous at %{time}"
+        hide: Hide
+        resolve: Resolve
+        comment_and_resolve: Comment & Resolve
+        comment: Comment
   redaction:
     edit:
       description: "Description"
index 34e19917a5a025929470f2697b846c7af9629e1b..6f6b778a8cd886a17d4160bfbe2f447e03307a8f 100644 (file)
@@ -6,6 +6,7 @@
 OpenLayers/Map.js
 OpenLayers/Control/ArgParser.js
 OpenLayers/Control/Attribution.js
+OpenLayers/Control/DragFeature.js
 OpenLayers/Control/DrawFeature.js
 OpenLayers/Control/LayerSwitcher.js
 OpenLayers/Control/Navigation.js
@@ -25,12 +26,16 @@ OpenLayers/Tile.js
 OpenLayers/Tile/Image.js
 OpenLayers/Feature/Vector.js
 OpenLayers/Strategy/Fixed.js
+OpenLayers/Strategy/BBOX.js
 OpenLayers/Protocol/HTTP.js
+OpenLayers/Format/QueryStringFilter.js
+OpenLayers/Format/GeoJSON.js
 OpenLayers/Format/OSM.js
 OpenLayers/Geometry/Point.js
 OpenLayers/Geometry/LinearRing.js
 OpenLayers/Handler/Point.js
 OpenLayers/Handler/RegularPolygon.js
+OpenLayers/Protocol/HTTP.js
 OpenLayers/Renderer.js
 OpenLayers/Renderer/Canvas.js
 OpenLayers/Renderer/SVG.js
index 1cdaaea4068ec15ef2ca584c94c810f60c86634f..a4a8faf43d423e50fdb929867d39623f8ab4cc84 100644 (file)
@@ -75,11 +75,31 @@ OpenStreetMap::Application.routes.draw do
   match 'api/0.6/gpx/:id/data' => 'trace#api_data', :via => :get
   
   # AMF (ActionScript) API
-
   match 'api/0.6/amf/read' => 'amf#amf_read', :via => :post
   match 'api/0.6/amf/write' => 'amf#amf_write', :via => :post
   match 'api/0.6/swf/trackpoints' => 'swf#trackpoints', :via => :get
 
+  # Map notes API
+  scope "api/0.6" do
+    resources :notes, :except => [ :new, :edit, :update ], :constraints => { :id => /\d+/ }, :defaults => { :format => "xml" } do
+      collection do
+        get 'search'
+        get 'feed', :defaults => { :format => "rss" }
+      end
+
+      member do
+        post 'comment'
+        post 'close'
+      end
+    end
+
+    match 'notes/addPOIexec' => 'notes#create', :via => :post
+    match 'notes/closePOIexec' => 'notes#close', :via => :post
+    match 'notes/editPOIexec' => 'notes#comment', :via => :post
+    match 'notes/getGPX' => 'notes#index', :via => :get, :format => "gpx"
+    match 'notes/getRSSfeed' => 'notes#feed', :via => :get, :format => "rss"
+  end
+
   # Data browsing
   match '/browse/start' => 'browse#start', :via => :get
   match '/browse/way/:id' => 'browse#way', :via => :get, :id => /\d+/
@@ -89,8 +109,10 @@ OpenStreetMap::Application.routes.draw do
   match '/browse/relation/:id' => 'browse#relation', :via => :get, :id => /\d+/
   match '/browse/relation/:id/history' => 'browse#relation_history', :via => :get, :id => /\d+/
   match '/browse/changeset/:id' => 'browse#changeset', :via => :get, :as => :changeset, :id => /\d+/
+  match '/browse/note/:id' => 'browse#note', :via => :get, :id => /\d+/, :as => "browse_note"
   match '/user/:display_name/edits' => 'changeset#list', :via => :get
   match '/user/:display_name/edits/feed' => 'changeset#feed', :via => :get, :format => :atom
+  match '/user/:display_name/notes' => 'notes#mine', :via => :get
   match '/browse/friends' => 'changeset#list', :via => :get, :friends => true, :as => "friend_changesets"
   match '/browse/nearby' => 'changeset#list', :via => :get, :nearby => true, :as => "nearby_changesets"
   match '/browse/changesets' => 'changeset#list', :via => :get
diff --git a/db/migrate/053_add_map_bug_tables.rb b/db/migrate/053_add_map_bug_tables.rb
new file mode 100644 (file)
index 0000000..b3a1ace
--- /dev/null
@@ -0,0 +1,33 @@
+require 'migrate'
+
+class AddMapBugTables < ActiveRecord::Migration
+  def self.up
+    create_enumeration :map_bug_status_enum, ["open", "closed", "hidden"]
+
+    create_table :map_bugs do |t|
+      t.column :id, :bigint, :null => false 
+      t.integer :latitude, :null => false 
+      t.integer :longitude, :null => false 
+      t.column :tile, :bigint, :null => false
+      t.datetime :last_changed, :null => false
+      t.datetime :date_created, :null => false 
+      t.string :nearby_place 
+      t.string :text
+      t.column :status, :map_bug_status_enum, :null => false
+    end
+
+    add_index :map_bugs, [:tile, :status], :name => "map_bugs_tile_idx"
+    add_index :map_bugs, [:last_changed], :name => "map_bugs_changed_idx"
+    add_index :map_bugs, [:date_created], :name => "map_bugs_created_idx"
+  end
+
+  def self.down
+    remove_index :map_bugs, :name => "map_bugs_tile_idx"
+    remove_index :map_bugs, :name => "map_bugs_changed_idx"
+    remove_index :map_bugs, :name => "map_bugs_created_idx"
+
+    drop_table :map_bugs
+
+    drop_enumeration :map_bug_status_enum
+  end
+end
diff --git a/db/migrate/054_refactor_map_bug_tables.rb b/db/migrate/054_refactor_map_bug_tables.rb
new file mode 100644 (file)
index 0000000..b094cc5
--- /dev/null
@@ -0,0 +1,34 @@
+require 'migrate'
+
+class RefactorMapBugTables < ActiveRecord::Migration
+  def self.up
+    create_table :map_bug_comment do |t|
+      t.column :id, :bigint, :null => false
+      t.column :bug_id, :bigint, :null => false
+      t.boolean :visible, :null => false 
+      t.datetime :date_created, :null => false
+      t.string :commenter_name
+      t.string :commenter_ip
+      t.column :commenter_id, :bigint
+      t.string :comment
+    end
+
+    remove_column :map_bugs, :text 
+
+    add_index :map_bug_comment, [:bug_id], :name => "map_bug_comment_id_idx"
+
+    add_foreign_key :map_bug_comment, [:bug_id], :map_bugs, [:id]
+    add_foreign_key :map_bug_comment, [:commenter_id], :users, [:id]
+  end
+
+  def self.down
+    remove_foreign_key :map_bug_comment, [:commenter_id]
+    remove_foreign_key :map_bug_comment, [:bug_id]
+
+    remove_index :map_bugs, :name => "map_bug_comment_id_idx"
+
+    add_column :map_bugs, :text, :string
+
+    drop_table :map_bug_comment
+  end
+end
diff --git a/db/migrate/055_change_map_bug_comment_type.rb b/db/migrate/055_change_map_bug_comment_type.rb
new file mode 100644 (file)
index 0000000..3518610
--- /dev/null
@@ -0,0 +1,11 @@
+require 'migrate'
+
+class ChangeMapBugCommentType < ActiveRecord::Migration
+  def self.up
+    change_column :map_bug_comment, :comment, :text
+  end
+
+  def self.down
+    change_column :map_bug_comment, :comment, :string
+  end
+end
diff --git a/db/migrate/056_add_date_closed.rb b/db/migrate/056_add_date_closed.rb
new file mode 100644 (file)
index 0000000..bb4c19c
--- /dev/null
@@ -0,0 +1,11 @@
+require 'migrate'
+
+class AddDateClosed < ActiveRecord::Migration
+  def self.up
+    add_column :map_bugs, :date_closed, :timestamp
+  end
+
+  def self.down
+    remove_column :map_bugs, :date_closed 
+  end
+end
diff --git a/db/migrate/057_add_map_bug_comment_event.rb b/db/migrate/057_add_map_bug_comment_event.rb
new file mode 100644 (file)
index 0000000..f28aee7
--- /dev/null
@@ -0,0 +1,15 @@
+require 'migrate'
+
+class AddMapBugCommentEvent < ActiveRecord::Migration
+  def self.up
+    create_enumeration :map_bug_event_enum, ["opened", "closed", "reopened", "commented", "hidden"]
+
+    add_column :map_bug_comment, :event, :map_bug_event_enum
+  end
+
+  def self.down
+    remove_column :map_bug_comment, :event
+
+    drop_enumeration :map_bug_event_enum
+  end
+end
diff --git a/db/migrate/20110508145337_cleanup_bug_tables.rb b/db/migrate/20110508145337_cleanup_bug_tables.rb
new file mode 100644 (file)
index 0000000..e7dfcb7
--- /dev/null
@@ -0,0 +1,25 @@
+class CleanupBugTables < ActiveRecord::Migration
+  def self.up
+    rename_column :map_bugs, :date_created, :created_at
+    rename_column :map_bugs, :last_changed, :updated_at
+    rename_column :map_bugs, :date_closed, :closed_at
+
+    rename_column :map_bug_comment, :date_created, :created_at
+    rename_column :map_bug_comment, :commenter_name, :author_name
+    rename_column :map_bug_comment, :commenter_ip, :author_ip
+    rename_column :map_bug_comment, :commenter_id, :author_id
+    rename_column :map_bug_comment, :comment, :body
+  end
+
+  def self.down
+    rename_column :map_bug_comment, :body, :comment
+    rename_column :map_bug_comment, :author_id, :commenter_id
+    rename_column :map_bug_comment, :author_ip, :commenter_ip
+    rename_column :map_bug_comment, :author_name, :commenter_name
+    rename_column :map_bug_comment, :created_at, :date_created
+
+    rename_column :map_bugs, :closed_at, :date_closed
+    rename_column :map_bugs, :updated_at, :last_changed
+    rename_column :map_bugs, :created_at, :date_created
+  end
+end
diff --git a/db/migrate/20110521142405_rename_bugs_to_notes.rb b/db/migrate/20110521142405_rename_bugs_to_notes.rb
new file mode 100644 (file)
index 0000000..2934b73
--- /dev/null
@@ -0,0 +1,51 @@
+require 'migrate'
+
+class RenameBugsToNotes < ActiveRecord::Migration
+  def self.up
+    rename_enumeration "map_bug_status_enum", "note_status_enum"
+    rename_enumeration "map_bug_event_enum", "note_event_enum"
+
+    rename_table :map_bugs, :notes
+    rename_index :notes, "map_bugs_pkey", "notes_pkey"
+    rename_index :notes, "map_bugs_changed_idx", "notes_updated_at_idx"
+    rename_index :notes, "map_bugs_created_idx", "notes_created_at_idx"
+    rename_index :notes, "map_bugs_tile_idx", "notes_tile_status_idx"
+
+    remove_foreign_key :map_bug_comment, [:bug_id], :map_bugs, [:id]
+    rename_column :map_bug_comment, :author_id, :commenter_id
+    remove_foreign_key :map_bug_comment, [:commenter_id], :users, [:id]
+    rename_column :map_bug_comment, :commenter_id, :author_id
+
+    rename_table :map_bug_comment, :note_comments
+    rename_column :note_comments, :bug_id, :note_id
+    rename_index :note_comments, "map_bug_comment_pkey", "note_comments_pkey"
+    rename_index :note_comments, "map_bug_comment_id_idx", "note_comments_note_id_idx"
+
+    add_foreign_key :note_comments, [:note_id], :notes, [:id]
+    add_foreign_key :note_comments, [:author_id], :users, [:id]
+  end
+
+  def self.down
+    remove_foreign_key :note_comments, [:author_id], :users, [:id]
+    remove_foreign_key :note_comments, [:note_id], :notes, [:id]
+
+    rename_index :note_comments, "note_comments_note_id_idx", "map_bug_comment_id_idx"
+    rename_index :notes, "note_comments_pkey", "map_bug_comment_pkey"
+    rename_column :note_comments, :note_id, :bug_id
+    rename_table :note_comments, :map_bug_comment
+
+    rename_column :map_bug_comment, :author_id, :commenter_id
+    add_foreign_key :map_bug_comment, [:commenter_id], :users, [:id]
+    rename_column :map_bug_comment, :commenter_id, :author_id
+    add_foreign_key :map_bug_comment, [:bug_id], :notes, [:id]
+
+    rename_index :notes, "notes_tile_status_idx", "map_bugs_tile_idx"
+    rename_index :notes, "notes_created_at_idx", "map_bugs_created_idx"
+    rename_index :notes, "notes_updated_at_idx", "map_bugs_changed_idx"
+    rename_index :notes, "notes_pkey", "map_bugs_pkey"
+    rename_table :notes, :map_bugs
+
+    rename_enumeration "note_event_enum", "map_bug_event_enum"
+    rename_enumeration "note_status_enum", "map_bug_status_enum"
+  end
+end
diff --git a/db/migrate/20121119165817_drop_nearby_place_from_notes.rb b/db/migrate/20121119165817_drop_nearby_place_from_notes.rb
new file mode 100644 (file)
index 0000000..bbef259
--- /dev/null
@@ -0,0 +1,9 @@
+class DropNearbyPlaceFromNotes < ActiveRecord::Migration
+  def up
+    remove_column :notes, :nearby_place
+  end
+
+  def down
+    add_column :notes, :nearby_place, :string
+  end
+end
diff --git a/db/migrate/20121202155309_remove_author_name_from_note_comment.rb b/db/migrate/20121202155309_remove_author_name_from_note_comment.rb
new file mode 100644 (file)
index 0000000..60d0ab2
--- /dev/null
@@ -0,0 +1,9 @@
+class RemoveAuthorNameFromNoteComment < ActiveRecord::Migration
+  def up
+    remove_column :note_comments, :author_name
+  end
+
+  def down
+    add_column :note_comments, :author_name, :string
+  end
+end
diff --git a/db/migrate/20121203124841_change_note_address_to_inet.rb b/db/migrate/20121203124841_change_note_address_to_inet.rb
new file mode 100644 (file)
index 0000000..e4e53e3
--- /dev/null
@@ -0,0 +1,9 @@
+class ChangeNoteAddressToInet < ActiveRecord::Migration
+  def up
+    execute "ALTER TABLE note_comments ALTER COLUMN author_ip TYPE inet USING CAST(author_ip AS inet)"
+  end
+
+  def down
+    change_column :note_comments, :author_ip, :string
+  end
+end
diff --git a/db/migrate/20130328184137_add_write_notes_permission.rb b/db/migrate/20130328184137_add_write_notes_permission.rb
new file mode 100644 (file)
index 0000000..c7da174
--- /dev/null
@@ -0,0 +1,11 @@
+class AddWriteNotesPermission < ActiveRecord::Migration
+  def up
+    add_column :oauth_tokens, :allow_write_notes, :boolean, :null => false, :default => false
+    add_column :client_applications, :allow_write_notes, :boolean, :null => false, :default => false
+  end
+
+  def down
+    remove_column :client_applications, :allow_write_notes
+    remove_column :oauth_tokens, :allow_write_notes
+  end
+end
index 339533b9292763cc9bed0b0bc0a8fa4a424fe451..4ed87362865295d86174ab18b4ccc6124ed895d2 100644 (file)
@@ -61,6 +61,30 @@ CREATE TYPE gpx_visibility_enum AS ENUM (
 );
 
 
+--
+-- Name: note_event_enum; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE note_event_enum AS ENUM (
+    'opened',
+    'closed',
+    'reopened',
+    'commented',
+    'hidden'
+);
+
+
+--
+-- Name: note_status_enum; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE note_status_enum AS ENUM (
+    'open',
+    'closed',
+    'hidden'
+);
+
+
 --
 -- Name: nwr_enum; Type: TYPE; Schema: public; Owner: -
 --
@@ -101,7 +125,7 @@ CREATE TYPE user_status_enum AS ENUM (
 
 CREATE FUNCTION maptile_for_point(bigint, bigint, integer) RETURNS integer
     LANGUAGE c STRICT
-    AS '/srv/www/master.osm.compton.nu/db/functions/libpgosm.so', 'maptile_for_point';
+    AS '/srv/www/notes.osm.compton.nu/db/functions/libpgosm.so', 'maptile_for_point';
 
 
 --
@@ -110,7 +134,7 @@ CREATE FUNCTION maptile_for_point(bigint, bigint, integer) RETURNS integer
 
 CREATE FUNCTION tile_for_point(integer, integer) RETURNS bigint
     LANGUAGE c STRICT
-    AS '/srv/www/master.osm.compton.nu/db/functions/libpgosm.so', 'tile_for_point';
+    AS '/srv/www/notes.osm.compton.nu/db/functions/libpgosm.so', 'tile_for_point';
 
 
 --
@@ -119,7 +143,7 @@ CREATE FUNCTION tile_for_point(integer, integer) RETURNS bigint
 
 CREATE FUNCTION xid_to_int4(xid) RETURNS integer
     LANGUAGE c IMMUTABLE STRICT
-    AS '/srv/www/master.osm.compton.nu/db/functions/libpgosm.so', 'xid_to_int4';
+    AS '/srv/www/notes.osm.compton.nu/db/functions/libpgosm.so', 'xid_to_int4';
 
 
 SET default_tablespace = '';
@@ -218,14 +242,15 @@ CREATE TABLE client_applications (
     key character varying(50),
     secret character varying(50),
     user_id integer,
-    created_at timestamp without time zone,
-    updated_at timestamp without time zone,
+    created_at timestamp without time zone NOT NULL,
+    updated_at timestamp without time zone NOT NULL,
     allow_read_prefs boolean DEFAULT false NOT NULL,
     allow_write_prefs boolean DEFAULT false NOT NULL,
     allow_write_diary boolean DEFAULT false NOT NULL,
     allow_write_api boolean DEFAULT false NOT NULL,
     allow_read_gpx boolean DEFAULT false NOT NULL,
-    allow_write_gpx boolean DEFAULT false NOT NULL
+    allow_write_gpx boolean DEFAULT false NOT NULL,
+    allow_write_notes boolean DEFAULT false NOT NULL
 );
 
 
@@ -700,6 +725,76 @@ CREATE TABLE nodes (
 );
 
 
+--
+-- Name: note_comments; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE note_comments (
+    id integer NOT NULL,
+    note_id bigint NOT NULL,
+    visible boolean NOT NULL,
+    created_at timestamp without time zone NOT NULL,
+    author_ip inet,
+    author_id bigint,
+    body text,
+    event note_event_enum
+);
+
+
+--
+-- Name: note_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE note_comments_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+--
+-- Name: note_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE note_comments_id_seq OWNED BY note_comments.id;
+
+
+--
+-- Name: notes; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE notes (
+    id integer NOT NULL,
+    latitude integer NOT NULL,
+    longitude integer NOT NULL,
+    tile bigint NOT NULL,
+    updated_at timestamp without time zone NOT NULL,
+    created_at timestamp without time zone NOT NULL,
+    status note_status_enum NOT NULL,
+    closed_at timestamp without time zone
+);
+
+
+--
+-- Name: notes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE notes_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+--
+-- Name: notes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE notes_id_seq OWNED BY notes.id;
+
+
 --
 -- Name: oauth_nonces; Type: TABLE; Schema: public; Owner: -; Tablespace: 
 --
@@ -708,8 +803,8 @@ CREATE TABLE oauth_nonces (
     id integer NOT NULL,
     nonce character varying(255),
     "timestamp" integer,
-    created_at timestamp without time zone,
-    updated_at timestamp without time zone
+    created_at timestamp without time zone NOT NULL,
+    updated_at timestamp without time zone NOT NULL
 );
 
 
@@ -745,8 +840,8 @@ CREATE TABLE oauth_tokens (
     secret character varying(50),
     authorized_at timestamp without time zone,
     invalidated_at timestamp without time zone,
-    created_at timestamp without time zone,
-    updated_at timestamp without time zone,
+    created_at timestamp without time zone NOT NULL,
+    updated_at timestamp without time zone NOT NULL,
     allow_read_prefs boolean DEFAULT false NOT NULL,
     allow_write_prefs boolean DEFAULT false NOT NULL,
     allow_write_diary boolean DEFAULT false NOT NULL,
@@ -756,7 +851,8 @@ CREATE TABLE oauth_tokens (
     callback_url character varying(255),
     verifier character varying(20),
     scope character varying(255),
-    valid_to timestamp without time zone
+    valid_to timestamp without time zone,
+    allow_write_notes boolean DEFAULT false NOT NULL
 );
 
 
@@ -874,8 +970,8 @@ CREATE TABLE user_blocks (
     ends_at timestamp without time zone NOT NULL,
     needs_view boolean DEFAULT false NOT NULL,
     revoker_id bigint,
-    created_at timestamp without time zone,
-    updated_at timestamp without time zone,
+    created_at timestamp without time zone NOT NULL,
+    updated_at timestamp without time zone NOT NULL,
     reason_format format_enum DEFAULT 'html'::format_enum NOT NULL
 );
 
@@ -917,8 +1013,8 @@ CREATE TABLE user_preferences (
 CREATE TABLE user_roles (
     id integer NOT NULL,
     user_id bigint NOT NULL,
-    created_at timestamp without time zone,
-    updated_at timestamp without time zone,
+    created_at timestamp without time zone NOT NULL,
+    updated_at timestamp without time zone NOT NULL,
     role user_role_enum NOT NULL,
     granter_id bigint NOT NULL
 );
@@ -1000,9 +1096,9 @@ CREATE TABLE users (
     status user_status_enum DEFAULT 'pending'::user_status_enum NOT NULL,
     terms_agreed timestamp without time zone,
     consider_pd boolean DEFAULT false NOT NULL,
+    openid_url character varying(255),
     preferred_editor character varying(255),
     terms_seen boolean DEFAULT false NOT NULL,
-    openid_url character varying(255),
     description_format format_enum DEFAULT 'html'::format_enum NOT NULL,
     image_fingerprint character varying(255),
     changesets_count integer DEFAULT 0 NOT NULL,
@@ -1160,6 +1256,20 @@ ALTER TABLE ONLY gpx_files ALTER COLUMN id SET DEFAULT nextval('gpx_files_id_seq
 ALTER TABLE ONLY messages ALTER COLUMN id SET DEFAULT nextval('messages_id_seq'::regclass);
 
 
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY note_comments ALTER COLUMN id SET DEFAULT nextval('note_comments_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY notes ALTER COLUMN id SET DEFAULT nextval('notes_id_seq'::regclass);
+
+
 --
 -- Name: id; Type: DEFAULT; Schema: public; Owner: -
 --
@@ -1377,6 +1487,22 @@ ALTER TABLE ONLY nodes
     ADD CONSTRAINT nodes_pkey PRIMARY KEY (node_id, version);
 
 
+--
+-- Name: note_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY note_comments
+    ADD CONSTRAINT note_comments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: notes_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY notes
+    ADD CONSTRAINT notes_pkey PRIMARY KEY (id);
+
+
 --
 -- Name: oauth_nonces_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
 --
@@ -1727,6 +1853,34 @@ CREATE INDEX nodes_tile_idx ON nodes USING btree (tile);
 CREATE INDEX nodes_timestamp_idx ON nodes USING btree ("timestamp");
 
 
+--
+-- Name: note_comments_note_id_idx; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX note_comments_note_id_idx ON note_comments USING btree (note_id);
+
+
+--
+-- Name: notes_created_at_idx; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX notes_created_at_idx ON notes USING btree (created_at);
+
+
+--
+-- Name: notes_tile_status_idx; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX notes_tile_status_idx ON notes USING btree (tile, status);
+
+
+--
+-- Name: notes_updated_at_idx; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX notes_updated_at_idx ON notes USING btree (updated_at);
+
+
 --
 -- Name: points_gpxid_idx; Type: INDEX; Schema: public; Owner: -; Tablespace: 
 --
@@ -2061,6 +2215,22 @@ ALTER TABLE ONLY nodes
     ADD CONSTRAINT nodes_redaction_id_fkey FOREIGN KEY (redaction_id) REFERENCES redactions(id);
 
 
+--
+-- Name: note_comments_author_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY note_comments
+    ADD CONSTRAINT note_comments_author_id_fkey FOREIGN KEY (author_id) REFERENCES users(id);
+
+
+--
+-- Name: note_comments_note_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY note_comments
+    ADD CONSTRAINT note_comments_note_id_fkey FOREIGN KEY (note_id) REFERENCES notes(id);
+
+
 --
 -- Name: oauth_tokens_client_application_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
 --
@@ -2245,6 +2415,10 @@ INSERT INTO schema_migrations (version) VALUES ('20101114011429');
 
 INSERT INTO schema_migrations (version) VALUES ('20110322001319');
 
+INSERT INTO schema_migrations (version) VALUES ('20110508145337');
+
+INSERT INTO schema_migrations (version) VALUES ('20110521142405');
+
 INSERT INTO schema_migrations (version) VALUES ('20110925112722');
 
 INSERT INTO schema_migrations (version) VALUES ('20111116184519');
@@ -2273,6 +2447,14 @@ INSERT INTO schema_migrations (version) VALUES ('20121005195010');
 
 INSERT INTO schema_migrations (version) VALUES ('20121012044047');
 
+INSERT INTO schema_migrations (version) VALUES ('20121119165817');
+
+INSERT INTO schema_migrations (version) VALUES ('20121202155309');
+
+INSERT INTO schema_migrations (version) VALUES ('20121203124841');
+
+INSERT INTO schema_migrations (version) VALUES ('20130328184137');
+
 INSERT INTO schema_migrations (version) VALUES ('21');
 
 INSERT INTO schema_migrations (version) VALUES ('22');
@@ -2343,6 +2525,16 @@ INSERT INTO schema_migrations (version) VALUES ('51');
 
 INSERT INTO schema_migrations (version) VALUES ('52');
 
+INSERT INTO schema_migrations (version) VALUES ('53');
+
+INSERT INTO schema_migrations (version) VALUES ('54');
+
+INSERT INTO schema_migrations (version) VALUES ('55');
+
+INSERT INTO schema_migrations (version) VALUES ('56');
+
+INSERT INTO schema_migrations (version) VALUES ('57');
+
 INSERT INTO schema_migrations (version) VALUES ('6');
 
 INSERT INTO schema_migrations (version) VALUES ('7');
index e560dbefa6c7f3e4c1c7bdf975b0a26917bd953a..38b994d26a6e11233983adcf6cbd730e5198af70 100644 (file)
@@ -37,6 +37,13 @@ public
     from_bbox_array(bbox_array)
   end
 
+  def self.from_lrbt_params(params)
+    if params[:l] and params[:b] and params[:t] and params[:t]
+      bbox_array = [params[:l], params[:b], params[:r], params[:t]]
+    end
+    from_bbox_array(bbox_array)
+  end
+
   def expand!(bbox, margin = 0)
     update!(bbox) unless complete?
     # only try to expand the bbox if there is a value for every coordinate
@@ -71,10 +78,10 @@ public
     self
   end
 
-  def check_size
+  def check_size(max_area = MAX_REQUEST_AREA)
     # check the bbox isn't too large
-    if area > MAX_REQUEST_AREA
-      raise OSM::APIBadBoundingBox.new("The maximum bbox size is " + MAX_REQUEST_AREA.to_s +
+    if area > max_area
+      raise OSM::APIBadBoundingBox.new("The maximum bbox size is " + max_area.to_s +
         ", and your request was too large. Either request a smaller area, or use planet.osm")
     end
     self
index 0d010eb869b6f6116c5024e2fa8bff300acf8d68..0c261dc69c8d3330f5ad4ea17b603e8a848dd9e1 100644 (file)
@@ -45,4 +45,3 @@ private
     180/Math::PI * Math.log(Math.tan(Math::PI/4+a*(Math::PI/180)/2))
   end
 end
-
index 7549add2abfb7e5623a23dbd26f8981c0e4ab6a2..baa7faecde3703d438548bb6c210ad812434d682 100644 (file)
@@ -87,18 +87,23 @@ module ActiveRecord
         @enumerations ||= Hash.new
       end
 
-      def create_enumeration (enumeration_name, values)
+      def create_enumeration(enumeration_name, values)
         enumerations[enumeration_name] = values
-        execute "create type #{enumeration_name} as enum ('#{values.join '\',\''}')"
+        execute "CREATE TYPE #{enumeration_name} AS ENUM ('#{values.join '\',\''}')"
       end
 
-      def drop_enumeration (enumeration_name)
-        execute "drop type #{enumeration_name}"
+      def drop_enumeration(enumeration_name)
+        execute "DROP TYPE #{enumeration_name}"
         enumerations.delete(enumeration_name)
       end
 
+      def rename_enumeration(old_name, new_name)
+        execute "ALTER TYPE #{quote_table_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
+      end
+
       def alter_primary_key(table_name, new_columns)
-        execute "alter table #{table_name} drop constraint #{table_name}_pkey; alter table #{table_name} add primary key (#{new_columns.join(',')})"
+        execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{table_name}_pkey"
+        execute "ALTER TABLE #{table_name} ADD PRIMARY KEY (#{new_columns.join(',')})"
       end
 
       def interval_constant(interval)
@@ -125,6 +130,10 @@ module ActiveRecord
 
         execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} USING #{index_method} (#{quoted_column_names})"
       end
+
+      def rename_index(table_name, old_name, new_name)
+        execute "ALTER INDEX #{quote_table_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
+      end
     end
   end
 end
diff --git a/lib/nominatim.rb b/lib/nominatim.rb
new file mode 100644 (file)
index 0000000..1d2037d
--- /dev/null
@@ -0,0 +1,26 @@
+module Nominatim
+  extend ActionView::Helpers::NumberHelper
+
+  def self.describe_location(lat, lon, zoom = nil, language = nil)
+    zoom = zoom || 14
+    language = language || request.user_preferred_languages.join(',')
+
+    Rails.cache.fetch "/nominatim/location/#{lat}/#{lon}/#{zoom}/#{language}" do
+      url = "http://nominatim.openstreetmap.org/reverse?lat=#{lat}&lon=#{lon}&zoom=#{zoom}&accept-language=#{language}"
+
+      begin
+        response = OSM::Timer.timeout(4) do
+          REXML::Document.new(Net::HTTP.get(URI.parse(url)))
+        end
+      rescue Exception
+        response = nil
+      end
+
+      if response and result = response.get_text("reversegeocode/result")
+        result.to_s
+      else
+        "#{number_with_precision(lat, :precision => 3)}, #{number_with_precision(lon, :precision => 3)}"
+      end
+    end
+  end
+end
index 3da9671c13840ccca0e61de2df5ca00626d14d36..393011dac563a4e205b7511c6f4a62e7f2c2f769 100644 (file)
@@ -281,6 +281,23 @@ module OSM
     end
   end
 
+  # Raised when the note provided is already closed
+  class APINoteAlreadyClosedError < APIError
+    def initialize(note)
+      @note = note
+    end
+
+    attr_reader :note
+
+    def status
+      :conflict
+    end
+
+    def to_s
+      "The note #{@note.id} was closed at #{@note.closed_at}"
+    end
+  end
+
   # Helper methods for going to/from mercator and lat/lng.
   class Mercator
     include Math
diff --git a/test/fixtures/note_comments.yml b/test/fixtures/note_comments.yml
new file mode 100644 (file)
index 0000000..881adb6
--- /dev/null
@@ -0,0 +1,107 @@
+t1:
+  id: 1
+  note_id: 1
+  visible: true
+  created_at: 2007-01-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'This is the initial description of the note 1'
+
+t2:
+  id: 2
+  note_id: 2
+  visible: true
+  created_at: 2007-01-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'This is the initial description of the note 2'
+
+t3:
+  id: 3
+  note_id: 2
+  visible: true
+  created_at: 2007-02-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'This is an additional comment for note 2'
+
+t4:
+  id: 4
+  note_id: 3
+  visible: true
+  created_at: 2007-01-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'This is the initial comment for note 3'
+
+t5:
+  id: 5
+  note_id: 4
+  visible: true
+  created_at: 2007-01-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'Spam for note 4'
+
+t6:
+  id: 6
+  note_id: 5
+  visible: true
+  created_at: 2007-01-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'Valid comment for note 5'
+
+t7:
+  id: 7
+  note_id: 5
+  visible: false
+  created_at: 2007-02-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'Spam for note 5'
+
+t8:
+  id: 8
+  note_id: 5
+  visible: true
+  created_at: 2007-02-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'Another valid comment for note 5'
+
+t9:
+  id: 9
+  note_id: 6
+  visible: true
+  created_at: 2007-01-01 00:00:00
+  event: opened
+  author_id: 1
+  body: 'This is a note with from a logged-in user'
+
+t10:
+  id: 10
+  note_id: 6
+  visible: true
+  created_at: 2007-02-01 00:00:00
+  event: commented
+  author_id: 4
+  body: 'A comment from another logged-in user'
+
+t11:
+  id: 11
+  note_id: 7
+  visible: true
+  event: opened
+  created_at: 2007-01-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'Initial note description'
+
+t12:
+  id: 12
+  note_id: 7
+  visible: true
+  event: commented
+  created_at: 2007-02-01 00:00:00
+  author_ip: '192.168.1.1'
+  body: 'A comment description'
+
+t13:
+  id: 13
+  note_id: 7
+  visible: true
+  event: closed
+  created_at: 2007-03-01 00:00:00
+  author_id: 4
diff --git a/test/fixtures/notes.yml b/test/fixtures/notes.yml
new file mode 100644 (file)
index 0000000..ffecba8
--- /dev/null
@@ -0,0 +1,67 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+<% SCALE = 10000000 unless defined?(SCALE) %>
+
+open_note:
+  id: 1
+  latitude: <%= 1*SCALE %>
+  longitude: <%= 1*SCALE %>
+  status: open
+  tile: <%= QuadTile.tile_for_point(1,1) %>
+  created_at: 2007-01-01 00:00:00
+  updated_at: 2007-01-01 00:00:00
+
+open_note_with_comment:
+  id: 2
+  latitude: <%= 1.1*SCALE %>
+  longitude: <%= 1.1*SCALE %>
+  status: open
+  tile: <%= QuadTile.tile_for_point(1.1,1.1) %>
+  created_at: 2007-01-01 00:00:00
+  updated_at: 2007-02-01 00:00:00
+
+closed_note_with_comment:
+  id: 3
+  latitude: <%= 1.2*SCALE %>
+  longitude: <%= 1.2*SCALE %>
+  status: closed
+  tile: <%= QuadTile.tile_for_point(1.2,1.2) %>
+  created_at: 2007-01-01 00:00:00
+  updated_at: 2007-03-01 00:00:00
+  closed_at:  2007-03-01 00:00:00
+
+hidden_note_with_comment:
+  id: 4
+  latitude: <%= 1.3*SCALE %>
+  longitude: <%= 1.3*SCALE %>
+  status: hidden
+  tile: <%= QuadTile.tile_for_point(1.3,1.3) %>
+  created_at: 2007-01-01 00:00:00
+  updated_at: 2007-03-01 00:00:00
+
+note_with_hidden_comment:
+  id: 5
+  latitude: <%= 1.4*SCALE %>
+  longitude: <%= 1.4*SCALE %>
+  status: open
+  tile: <%= QuadTile.tile_for_point(1.4,1.4) %>
+  created_at: 2007-01-01 00:00:00
+  updated_at: 2007-03-01 00:00:00
+
+note_with_comments_by_users:
+  id: 6
+  latitude: <%= 1.5*SCALE %>
+  longitude: <%= 1.5*SCALE %>
+  status: open
+  tile: <%= QuadTile.tile_for_point(1.5,1.5) %>
+  created_at: 2007-01-01 00:00:00
+  updated_at: 2007-03-01 00:00:00
+
+note_closed_by_user:
+  id: 7
+  latitude: <%= 1.6*SCALE %>
+  longitude: <%= 1.6*SCALE %>
+  status: closed
+  tile: <%= QuadTile.tile_for_point(1.6,1.6) %>
+  created_at: 2007-01-01 00:00:00
+  updated_at: 2007-03-01 00:00:00
+  closed_at:  2007-03-01 00:00:00
index 9ba8dd8f0dab22dd26ecbeddfc03e88d57e32c37..87a3e748967320e80b4d1f82b5e1959183b5ee25 100644 (file)
@@ -39,6 +39,10 @@ class BrowseControllerTest < ActionController::TestCase
       { :path => "/browse/changeset/1", :method => :get },
       { :controller => "browse", :action => "changeset", :id => "1" }
     )
+    assert_routing(
+      { :path => "/browse/note/1", :method => :get },
+      { :controller => "browse", :action => "note", :id => "1" }
+    )
   end
 
   def test_start
diff --git a/test/functional/notes_controller_test.rb b/test/functional/notes_controller_test.rb
new file mode 100644 (file)
index 0000000..4bd0aa6
--- /dev/null
@@ -0,0 +1,523 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class NotesControllerTest < ActionController::TestCase
+  fixtures :users, :notes, :note_comments
+
+  ##
+  # test all routes which lead to this controller
+  def test_routes
+    assert_routing(
+      { :path => "/api/0.6/notes", :method => :post },
+      { :controller => "notes", :action => "create", :format => "xml" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/1", :method => :get },
+      { :controller => "notes", :action => "show", :id => "1", :format => "xml" }
+    )
+    assert_recognizes(
+      { :controller => "notes", :action => "show", :id => "1", :format => "xml" },
+      { :path => "/api/0.6/notes/1.xml", :method => :get }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/1.rss", :method => :get },
+      { :controller => "notes", :action => "show", :id => "1", :format => "rss" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/1.json", :method => :get },
+      { :controller => "notes", :action => "show", :id => "1", :format => "json" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/1.gpx", :method => :get },
+      { :controller => "notes", :action => "show", :id => "1", :format => "gpx" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/1/comment", :method => :post },
+      { :controller => "notes", :action => "comment", :id => "1", :format => "xml" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/1/close", :method => :post },
+      { :controller => "notes", :action => "close", :id => "1", :format => "xml" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/1", :method => :delete },
+      { :controller => "notes", :action => "destroy", :id => "1", :format => "xml" }
+    )
+
+    assert_routing(
+      { :path => "/api/0.6/notes", :method => :get },
+      { :controller => "notes", :action => "index", :format => "xml" }
+    )
+    assert_recognizes(
+      { :controller => "notes", :action => "index", :format => "xml" },
+      { :path => "/api/0.6/notes.xml", :method => :get }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes.rss", :method => :get },
+      { :controller => "notes", :action => "index", :format => "rss" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes.json", :method => :get },
+      { :controller => "notes", :action => "index", :format => "json" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes.gpx", :method => :get },
+      { :controller => "notes", :action => "index", :format => "gpx" }
+    )
+
+    assert_routing(
+      { :path => "/api/0.6/notes/search", :method => :get },
+      { :controller => "notes", :action => "search", :format => "xml" }
+    )
+    assert_recognizes(
+      { :controller => "notes", :action => "search", :format => "xml" },
+      { :path => "/api/0.6/notes/search.xml", :method => :get }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/search.rss", :method => :get },
+      { :controller => "notes", :action => "search", :format => "rss" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/search.json", :method => :get },
+      { :controller => "notes", :action => "search", :format => "json" }
+    )
+    assert_routing(
+      { :path => "/api/0.6/notes/search.gpx", :method => :get },
+      { :controller => "notes", :action => "search", :format => "gpx" }
+    )
+
+    assert_routing(
+      { :path => "/api/0.6/notes/feed", :method => :get },
+      { :controller => "notes", :action => "feed", :format => "rss" }
+    )
+
+    assert_recognizes(
+      { :controller => "notes", :action => "create" },
+      { :path => "/api/0.6/notes/addPOIexec", :method => :post }
+    )
+    assert_recognizes(
+      { :controller => "notes", :action => "close" },
+      { :path => "/api/0.6/notes/closePOIexec", :method => :post }
+    )
+    assert_recognizes(
+      { :controller => "notes", :action => "comment" },
+      { :path => "/api/0.6/notes/editPOIexec", :method => :post }
+    )
+    assert_recognizes(
+      { :controller => "notes", :action => "index", :format => "gpx" },
+      { :path => "/api/0.6/notes/getGPX", :method => :get }
+    )
+    assert_recognizes(
+      { :controller => "notes", :action => "feed", :format => "rss" },
+      { :path => "/api/0.6/notes/getRSSfeed", :method => :get }
+    )
+
+    assert_routing(
+      { :path => "/user/username/notes", :method => :get },
+      { :controller => "notes", :action => "mine", :display_name => "username" }
+    )
+  end
+
+  def test_note_create_success
+    assert_difference('Note.count') do
+      assert_difference('NoteComment.count') do
+        post :create, {:lat => -1.0, :lon => -1.0, :text => "This is a comment", :format => "json"}
+      end
+    end
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "Feature", js["type"]
+    assert_equal "Point", js["geometry"]["type"]
+    assert_equal [-1.0, -1.0], js["geometry"]["coordinates"]
+    assert_equal "open", js["properties"]["status"]
+    assert_equal 1, js["properties"]["comments"].count
+    assert_equal "opened", js["properties"]["comments"].last["action"]
+    assert_equal "This is a comment", js["properties"]["comments"].last["text"]
+    assert_nil js["properties"]["comments"].last["user"]
+    id = js["properties"]["id"]
+
+    get :show, {:id => id, :format => "json"}
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "Feature", js["type"]
+    assert_equal "Point", js["geometry"]["type"]
+    assert_equal [-1.0, -1.0], js["geometry"]["coordinates"]
+    assert_equal id, js["properties"]["id"]
+    assert_equal "open", js["properties"]["status"]
+    assert_equal 1, js["properties"]["comments"].count
+    assert_equal "opened", js["properties"]["comments"].last["action"]
+    assert_equal "This is a comment", js["properties"]["comments"].last["text"]
+    assert_nil js["properties"]["comments"].last["user"]
+  end
+
+  def test_note_create_fail
+    assert_no_difference('Note.count') do
+      assert_no_difference('NoteComment.count') do
+        post :create, {:lon => -1.0, :text => "This is a comment"}
+      end
+    end
+    assert_response :bad_request
+
+    assert_no_difference('Note.count') do
+      assert_no_difference('NoteComment.count') do
+        post :create, {:lat => -1.0, :text => "This is a comment"}
+      end
+    end
+    assert_response :bad_request
+
+    assert_no_difference('Note.count') do
+      assert_no_difference('NoteComment.count') do
+        post :create, {:lat => -1.0, :lon => -1.0}
+      end
+    end
+    assert_response :bad_request
+
+    assert_no_difference('Note.count') do
+      assert_no_difference('NoteComment.count') do
+        post :create, {:lat => -1.0, :lon => -1.0, :text => ""}
+      end
+    end
+    assert_response :bad_request
+
+    assert_no_difference('Note.count') do
+      assert_no_difference('NoteComment.count') do
+        post :create, {:lat => -100.0, :lon => -1.0, :text => "This is a comment"}
+      end
+    end
+    assert_response :bad_request
+
+    assert_no_difference('Note.count') do
+      assert_no_difference('NoteComment.count') do
+        post :create, {:lat => -1.0, :lon => -200.0, :text => "This is a comment"}
+      end
+    end
+    assert_response :bad_request
+  end
+
+  def test_note_comment_create_success
+    assert_difference('NoteComment.count') do
+      post :comment, {:id => notes(:open_note_with_comment).id, :text => "This is an additional comment", :format => "json"}
+    end
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "Feature", js["type"]
+    assert_equal notes(:open_note_with_comment).id, js["properties"]["id"]
+    assert_equal "open", js["properties"]["status"]
+    assert_equal 3, js["properties"]["comments"].count
+    assert_equal "commented", js["properties"]["comments"].last["action"]
+    assert_equal "This is an additional comment", js["properties"]["comments"].last["text"]
+    assert_nil js["properties"]["comments"].last["user"]
+
+    get :show, {:id => notes(:open_note_with_comment).id, :format => "json"}
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "Feature", js["type"]
+    assert_equal notes(:open_note_with_comment).id, js["properties"]["id"]
+    assert_equal "open", js["properties"]["status"]
+    assert_equal 3, js["properties"]["comments"].count
+    assert_equal "commented", js["properties"]["comments"].last["action"]
+    assert_equal "This is an additional comment", js["properties"]["comments"].last["text"]
+    assert_nil js["properties"]["comments"].last["user"]
+  end
+
+  def test_note_comment_create_fail
+    assert_no_difference('NoteComment.count') do
+      post :comment, {:text => "This is an additional comment"}
+    end
+    assert_response :bad_request
+
+    assert_no_difference('NoteComment.count') do
+      post :comment, {:id => notes(:open_note_with_comment).id}
+    end
+    assert_response :bad_request
+
+    assert_no_difference('NoteComment.count') do
+      post :comment, {:id => notes(:open_note_with_comment).id, :text => ""}
+    end
+    assert_response :bad_request
+
+    assert_no_difference('NoteComment.count') do
+      post :comment, {:id => 12345, :text => "This is an additional comment"}
+    end
+    assert_response :not_found
+
+    assert_no_difference('NoteComment.count') do
+      post :comment, {:id => notes(:hidden_note_with_comment).id, :text => "This is an additional comment"}
+    end
+    assert_response :gone
+
+    assert_no_difference('NoteComment.count') do
+      post :comment, {:id => notes(:closed_note_with_comment).id, :text => "This is an additional comment"}
+    end
+    assert_response :conflict
+  end
+
+  def test_note_close_success
+    post :close, {:id => notes(:open_note_with_comment).id, :text => "This is a close comment", :format => "json"}
+    assert_response :unauthorized
+
+    basic_authorization(users(:public_user).email, "test")
+
+    post :close, {:id => notes(:open_note_with_comment).id, :text => "This is a close comment", :format => "json"}
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "Feature", js["type"]
+    assert_equal notes(:open_note_with_comment).id, js["properties"]["id"]
+    assert_equal "closed", js["properties"]["status"]
+    assert_equal 3, js["properties"]["comments"].count
+    assert_equal "closed", js["properties"]["comments"].last["action"]
+    assert_equal "This is a close comment", js["properties"]["comments"].last["text"]
+    assert_equal "test2", js["properties"]["comments"].last["user"]
+
+    get :show, {:id => notes(:open_note_with_comment).id, :format => "json"}
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "Feature", js["type"]
+    assert_equal notes(:open_note_with_comment).id, js["properties"]["id"]
+    assert_equal "closed", js["properties"]["status"]
+    assert_equal 3, js["properties"]["comments"].count
+    assert_equal "closed", js["properties"]["comments"].last["action"]
+    assert_equal "This is a close comment", js["properties"]["comments"].last["text"]
+    assert_equal "test2", js["properties"]["comments"].last["user"]
+  end
+
+  def test_note_close_fail
+    post :close
+    assert_response :unauthorized
+
+    basic_authorization(users(:public_user).email, "test")
+
+    post :close
+    assert_response :bad_request
+
+    post :close, {:id => 12345}
+    assert_response :not_found
+
+    post :close, {:id => notes(:hidden_note_with_comment).id}
+    assert_response :gone
+
+    post :close, {:id => notes(:closed_note_with_comment).id}
+    assert_response :conflict
+  end
+
+  def test_note_read_success
+    get :show, {:id => notes(:open_note).id, :format => "xml"}
+    assert_response :success
+    assert_equal "application/xml", @response.content_type
+
+    get :show, {:id => notes(:open_note).id, :format => "rss"}
+    assert_response :success
+    assert_equal "application/rss+xml", @response.content_type
+
+    get :show, {:id => notes(:open_note).id, :format => "json"}
+    assert_response :success
+    assert_equal "application/json", @response.content_type
+
+    get :show, {:id => notes(:open_note).id, :format => "gpx"}
+    assert_response :success
+    assert_equal "application/gpx+xml", @response.content_type
+  end
+
+  def test_note_read_hidden_comment
+    get :show, {:id => notes(:note_with_hidden_comment).id, :format => "json"}
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal notes(:note_with_hidden_comment).id, js["properties"]["id"]
+    assert_equal 2, js["properties"]["comments"].count
+    assert_equal "Valid comment for note 5", js["properties"]["comments"][0]["text"]
+    assert_equal "Another valid comment for note 5", js["properties"]["comments"][1]["text"]
+  end
+
+  def test_note_read_fail
+    get :show, {:id => 12345}
+    assert_response :not_found
+
+    get :show, {:id => notes(:hidden_note_with_comment).id}
+    assert_response :gone
+  end
+
+  def test_note_delete_success
+    delete :destroy, {:id => notes(:open_note_with_comment).id, :text => "This is a hide comment", :format => "json"}
+    assert_response :unauthorized
+
+    basic_authorization(users(:public_user).email, "test")
+
+    delete :destroy, {:id => notes(:open_note_with_comment).id, :text => "This is a hide comment", :format => "json"}
+    assert_response :forbidden
+
+    basic_authorization(users(:moderator_user).email, "test")
+
+    delete :destroy, {:id => notes(:open_note_with_comment).id, :text => "This is a hide comment", :format => "json"}
+    assert_response :success
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "Feature", js["type"]
+    assert_equal notes(:open_note_with_comment).id, js["properties"]["id"]
+    assert_equal "hidden", js["properties"]["status"]
+    assert_equal 3, js["properties"]["comments"].count
+    assert_equal "hidden", js["properties"]["comments"].last["action"]
+    assert_equal "This is a hide comment", js["properties"]["comments"].last["text"]
+    assert_equal "moderator", js["properties"]["comments"].last["user"]
+
+    get :show, {:id => notes(:open_note_with_comment).id, :format => 'json'}
+    assert_response :gone
+  end
+
+  def test_note_delete_fail
+    delete :destroy, {:id => 12345, :format => "json"}
+    assert_response :unauthorized
+
+    basic_authorization(users(:public_user).email, "test")
+
+    delete :destroy, {:id => 12345, :format => "json"}
+    assert_response :forbidden
+
+    basic_authorization(users(:moderator_user).email, "test")
+
+    delete :destroy, {:id => 12345, :format => "json"}
+    assert_response :not_found
+
+    delete :destroy, {:id => notes(:hidden_note_with_comment).id, :format => "json"}
+    assert_response :gone
+  end
+
+  def test_get_notes_success
+#    get :index, {:bbox => '1,1,1.2,1.2'}
+#    assert_response :success
+#    assert_equal "text/javascript", @response.content_type
+
+    get :index, {:bbox => '1,1,1.2,1.2', :format => 'rss'}
+    assert_response :success
+    assert_equal "application/rss+xml", @response.content_type
+
+    get :index, {:bbox => '1,1,1.2,1.2', :format => 'json'}
+    assert_response :success
+    assert_equal "application/json", @response.content_type
+
+    get :index, {:bbox => '1,1,1.2,1.2', :format => 'xml'}
+    assert_response :success
+    assert_equal "application/xml", @response.content_type
+
+    get :index, {:bbox => '1,1,1.2,1.2', :format => 'gpx'}
+    assert_response :success
+    assert_equal "application/gpx+xml", @response.content_type
+  end
+
+  def test_get_notes_large_area
+#    get :index, {:bbox => '-2.5,-2.5,2.5,2.5'}
+#    assert_response :success
+
+#    get :index, {:l => '-2.5', :b => '-2.5', :r => '2.5', :t => '2.5'}
+#    assert_response :success
+
+    get :index, {:bbox => '-10,-10,12,12'}
+    assert_response :bad_request
+
+    get :index, {:l => '-10', :b => '-10', :r => '12', :t => '12'}
+    assert_response :bad_request
+  end
+
+  def test_get_notes_closed
+    get :index, {:bbox => '1,1,1.7,1.7', :closed => '7', :format => 'json'}
+    assert_response :success
+    assert_equal "application/json", @response.content_type
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "FeatureCollection", js["type"]
+    assert_equal 4, js["features"].count
+
+    get :index, {:bbox => '1,1,1.7,1.7', :closed => '0', :format => 'json'}
+    assert_response :success
+    assert_equal "application/json", @response.content_type
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "FeatureCollection", js["type"]
+    assert_equal 4, js["features"].count
+
+    get :index, {:bbox => '1,1,1.7,1.7', :closed => '-1', :format => 'json'}
+    assert_response :success
+    assert_equal "application/json", @response.content_type
+    js = ActiveSupport::JSON.decode(@response.body)
+    assert_not_nil js
+    assert_equal "FeatureCollection", js["type"]
+    assert_equal 6, js["features"].count
+  end
+
+  def test_get_notes_bad_params
+    get :index, {:bbox => '-2.5,-2.5,2.5'}
+    assert_response :bad_request
+
+    get :index, {:bbox => '-2.5,-2.5,2.5,2.5,2.5'}
+    assert_response :bad_request
+
+    get :index, {:b => '-2.5', :r => '2.5', :t => '2.5'}
+    assert_response :bad_request
+
+    get :index, {:l => '-2.5', :r => '2.5', :t => '2.5'}
+    assert_response :bad_request
+
+    get :index, {:l => '-2.5', :b => '-2.5', :t => '2.5'}
+    assert_response :bad_request
+
+    get :index, {:l => '-2.5', :b => '-2.5', :r => '2.5'}
+    assert_response :bad_request
+  end
+
+  def test_search_success
+    get :search, {:q => 'note 1', :format => 'xml'}
+    assert_response :success
+    assert_equal "application/xml", @response.content_type
+
+    get :search, {:q => 'note 1', :format => 'json'}
+    assert_response :success
+    assert_equal "application/json", @response.content_type
+
+    get :search, {:q => 'note 1', :format => 'rss'}
+    assert_response :success
+    assert_equal "application/rss+xml", @response.content_type
+
+    get :search, {:q => 'note 1', :format => 'gpx'}
+    assert_response :success
+    assert_equal "application/gpx+xml", @response.content_type
+  end
+
+  def test_search_bad_params
+    get :search
+    assert_response :bad_request
+  end
+
+  def test_rss_success
+    get :feed, {:format => "rss"}
+    assert_response :success
+    assert_equal "application/rss+xml", @response.content_type
+
+    get :feed, {:bbox => "1,1,1.2,1.2", :format => "rss"}
+    assert_response :success   
+    assert_equal "application/rss+xml", @response.content_type
+  end
+
+  def test_rss_fail
+    get :feed, {:bbox => "1,1,1.2"}
+    assert_response :bad_request
+
+    get :feed, {:bbox => "1,1,1.2,1.2,1.2"}
+    assert_response :bad_request
+  end
+
+  def test_user_notes_success
+    get :mine, {:display_name => "test"}
+    assert_response :success
+
+    get :mine, {:display_name => "pulibc_test2"}
+    assert_response :success
+
+    get :mine, {:display_name => "non-existent"}
+    assert_response :not_found 
+  end
+end
diff --git a/vendor/assets/ohauth/ohauth.js b/vendor/assets/ohauth/ohauth.js
new file mode 100644 (file)
index 0000000..0497da8
--- /dev/null
@@ -0,0 +1,86 @@
+(function(context) {
+
+var ohauth = {};
+
+ohauth.qsString = function(obj) {
+    return Object.keys(obj).sort().map(function(key) {
+        return encodeURIComponent(key) + '=' +
+            encodeURIComponent(obj[key]);
+    }).join('&');
+};
+
+ohauth.sha = sha1();
+
+ohauth.stringQs = function(str) {
+    return str.split('&').reduce(function(obj, pair){
+        var parts = pair.split('=');
+        obj[parts[0]] = (null === parts[1]) ?
+            '' : decodeURIComponent(parts[1]);
+        return obj;
+    }, {});
+};
+
+ohauth.rawxhr = function(method, url, data, headers, callback) {
+    var xhr = new XMLHttpRequest(), twoHundred = /^20\d$/;
+    xhr.onreadystatechange = function() {
+        if (4 == xhr.readyState && 0 !== xhr.status) {
+            if (twoHundred.test(xhr.status)) callback(null, xhr);
+            else return callback(xhr, null);
+        }
+    };
+    xhr.onerror = function(e) { return callback(e, null); };
+    xhr.open(method, url, true);
+    for (var h in headers) xhr.setRequestHeader(h, headers[h]);
+    xhr.send(data);
+};
+
+ohauth.xhr = function(method, url, auth, data, options, callback) {
+    var headers = (options && options.header) || {
+        'Content-Type': 'application/x-www-form-urlencoded'
+    };
+    headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
+    ohauth.rawxhr(method, url, auth, data, headers, callback);
+};
+
+ohauth.nonce = function() {
+    for (var o = ''; o.length < 6;) {
+        o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
+    }
+    return o;
+};
+
+ohauth.authHeader = function(obj) {
+    return Object.keys(obj).sort().map(function(key) {
+        return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
+    }).join(', ');
+};
+
+ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
+
+ohauth.percentEncode = function(s) {
+    return encodeURIComponent(s)
+        .replace(/\!/g, '%21').replace(/\'/g, '%27')
+        .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
+};
+
+ohauth.baseString = function(method, url, params) {
+    if (params.oauth_signature) delete params.oauth_signature;
+    return [
+        method,
+        ohauth.percentEncode(url),
+        ohauth.percentEncode(ohauth.qsString(params))].join('&');
+};
+
+ohauth.signature = function(oauth_secret, token_secret, baseString) {
+    return ohauth.sha.b64_hmac_sha1(
+        ohauth.percentEncode(oauth_secret) + '&' +
+        ohauth.percentEncode(token_secret),
+        baseString);
+};
+
+context.ohauth = ohauth;
+
+// export for npm/browserify compatibility
+if (typeof module !== 'undefined') module.exports = ohauth;
+
+})(this);
diff --git a/vendor/assets/ohauth/sha.js b/vendor/assets/ohauth/sha.js
new file mode 100644 (file)
index 0000000..5b6aa65
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
+ * in FIPS PUB 180-1
+ * Version 2.1a Copyright Paul Johnston 2000 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ */
+
+function sha1() {
+
+    /*
+     * Configurable variables. You may need to tweak these to be compatible with
+     * the server-side, but the defaults work in most cases.
+     */
+    var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+    var b64pad  = "="; /* base-64 pad character. "=" for strict RFC compliance   */
+    var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+    /*
+     * These are the functions you'll usually want to call
+     * They take string arguments and return either hex or base-64 encoded strings
+     */
+    function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
+    function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
+    function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
+    function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
+    function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
+    function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
+
+    /*
+     * Perform a simple self-test to see if the VM is working
+     */
+    function sha1_vm_test() {
+      return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
+    }
+
+    /*
+     * Calculate the SHA-1 of an array of big-endian words, and a bit length
+     */
+    function core_sha1(x, len) {
+      /* append padding */
+      x[len >> 5] |= 0x80 << (24 - len % 32);
+      x[((len + 64 >> 9) << 4) + 15] = len;
+
+      var w = Array(80);
+      var a =  1732584193;
+      var b = -271733879;
+      var c = -1732584194;
+      var d =  271733878;
+      var e = -1009589776;
+
+      for(var i = 0; i < x.length; i += 16) {
+        var olda = a;
+        var oldb = b;
+        var oldc = c;
+        var oldd = d;
+        var olde = e;
+
+        for(var j = 0; j < 80; j++) {
+          if(j < 16) w[j] = x[i + j];
+          else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
+          var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
+                           safe_add(safe_add(e, w[j]), sha1_kt(j)));
+          e = d;
+          d = c;
+          c = rol(b, 30);
+          b = a;
+          a = t;
+        }
+
+        a = safe_add(a, olda);
+        b = safe_add(b, oldb);
+        c = safe_add(c, oldc);
+        d = safe_add(d, oldd);
+        e = safe_add(e, olde);
+      }
+      return Array(a, b, c, d, e);
+
+    }
+
+    /*
+     * Perform the appropriate triplet combination function for the current
+     * iteration
+     */
+    function sha1_ft(t, b, c, d) {
+      if(t < 20) return (b & c) | ((~b) & d);
+      if(t < 40) return b ^ c ^ d;
+      if(t < 60) return (b & c) | (b & d) | (c & d);
+      return b ^ c ^ d;
+    }
+
+    /*
+     * Determine the appropriate additive constant for the current iteration
+     */
+    function sha1_kt(t) {
+      return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
+             (t < 60) ? -1894007588 : -899497514;
+    }
+
+    /*
+     * Calculate the HMAC-SHA1 of a key and some data
+     */
+    function core_hmac_sha1(key, data) {
+      var bkey = str2binb(key);
+      if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
+
+      var ipad = Array(16), opad = Array(16);
+      for(var i = 0; i < 16; i++) {
+        ipad[i] = bkey[i] ^ 0x36363636;
+        opad[i] = bkey[i] ^ 0x5C5C5C5C;
+      }
+
+      var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
+      return core_sha1(opad.concat(hash), 512 + 160);
+    }
+
+    /*
+     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+     * to work around bugs in some JS interpreters.
+     */
+    function safe_add(x, y) {
+      var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+      var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+      return (msw << 16) | (lsw & 0xFFFF);
+    }
+
+    /*
+     * Bitwise rotate a 32-bit number to the left.
+     */
+    function rol(num, cnt) {
+      return (num << cnt) | (num >>> (32 - cnt));
+    }
+
+    /*
+     * Convert an 8-bit or 16-bit string to an array of big-endian words
+     * In 8-bit function, characters >255 have their hi-byte silently ignored.
+     */
+    function str2binb(str) {
+      var bin = Array();
+      var mask = (1 << chrsz) - 1;
+      for(var i = 0; i < str.length * chrsz; i += chrsz)
+        bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
+      return bin;
+    }
+
+    /*
+     * Convert an array of big-endian words to a string
+     */
+    function binb2str(bin) {
+      var str = "";
+      var mask = (1 << chrsz) - 1;
+      for(var i = 0; i < bin.length * 32; i += chrsz)
+        str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
+      return str;
+    }
+
+    /*
+     * Convert an array of big-endian words to a hex string.
+     */
+    function binb2hex(binarray) {
+      var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+      var str = "";
+      for(var i = 0; i < binarray.length * 4; i++) {
+        str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
+               hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
+      }
+      return str;
+    }
+
+    /*
+     * Convert an array of big-endian words to a base-64 string
+     */
+    function binb2b64(binarray) {
+      var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+      var str = "";
+      for(var i = 0; i < binarray.length * 4; i += 3) {
+        var triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16)
+                    | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
+                    |  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
+        for(var j = 0; j < 4; j++) {
+          if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
+          else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
+        }
+      }
+      return str;
+    }
+
+    return { b64_hmac_sha1: b64_hmac_sha1 };
+}
+
index ae17272adf401156b7c03fab6cfe0b166cd2126b..ad5df5a32defcd77173a0605fad74c304f7beec1 100644 (file)
@@ -809,7 +809,22 @@ if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera&&window.opera.version()<
 this.delta=this.delta+delta;if(this.interval){window.clearTimeout(this._timeoutId);this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(e);},this),this.interval);}else{this.wheelZoom(e);}}
 OpenLayers.Event.stop(e);}},wheelZoom:function(e){var delta=this.delta;this.delta=0;if(delta){if(this.mousePosition){e.xy=this.mousePosition;}
 if(!e.xy){e.xy=this.map.getPixelFromLonLat(this.map.getCenter());}
-if(delta<0){this.callback("down",[e,this.cumulative?delta:-1]);}else{this.callback("up",[e,this.cumulative?delta:1]);}}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.observe(window,"mousewheel",wheelListener);OpenLayers.Event.observe(document,"mousewheel",wheelListener);return true;}else{return false;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Lang.en={'unhandledRequest':"Unhandled request return ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Base Layer",'noFID':"Can't update a feature for which there is no FID.",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS ${response}",'commitFailed':"WFS Transaction: FAILED ${response}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the ${layerLib} library "+"script was not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>click here</a>",'Scale = 1 : ${scaleDenom}':"Scale = 1 : ${scaleDenom}",'W':'W','E':'E','N':'N','S':'S','Graticule':'Graticule','reprojectDeprecated':"You are using the 'reproject' option "+"on the ${layerName} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use ${newMethod} instead.",'proxyNeeded':"You probably need to set OpenLayers.ProxyHost to access ${url}."+"See http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost",'end':''};OpenLayers.Lang['en-CA']=OpenLayers.Util.applyDefaults({},OpenLayers.Lang["en"]);OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:false,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:false,fixPadding:function(){if(typeof this.padding=="number"){this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding);}},panMapIfOutOfView:false,keepInMap:false,closeOnMove:false,map:null,initialize:function(id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback){if(id==null){id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}
+if(delta<0){this.callback("down",[e,this.cumulative?delta:-1]);}else{this.callback("up",[e,this.cumulative?delta:1]);}}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.observe(window,"mousewheel",wheelListener);OpenLayers.Event.observe(document,"mousewheel",wheelListener);return true;}else{return false;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Lang.en={'unhandledRequest':"Unhandled request return ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Base Layer",'noFID':"Can't update a feature for which there is no FID.",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS ${response}",'commitFailed':"WFS Transaction: FAILED ${response}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the ${layerLib} library "+"script was not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>click here</a>",'Scale = 1 : ${scaleDenom}':"Scale = 1 : ${scaleDenom}",'W':'W','E':'E','N':'N','S':'S','Graticule':'Graticule','reprojectDeprecated':"You are using the 'reproject' option "+"on the ${layerName} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use ${newMethod} instead.",'proxyNeeded':"You probably need to set OpenLayers.ProxyHost to access ${url}."+"See http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost",'end':''};OpenLayers.Lang['en-CA']=OpenLayers.Util.applyDefaults({},OpenLayers.Lang["en"]);OpenLayers.Geometry.MultiLineString=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LineString"],split:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,sourceLine,sourceLines,sourceSplit,targetSplit;var sourceParts=[];var targetParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){sourceLine=this.components[i];sourceSplit=false;for(var j=0;j<targetParts.length;++j){splits=sourceLine.split(targetParts[j],options);if(splits){if(mutual){sourceLines=splits[0];for(var k=0,klen=sourceLines.length;k<klen;++k){if(k===0&&sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLines[k]);}else{sourceParts.push(new OpenLayers.Geometry.MultiLineString([sourceLines[k]]));}}
+sourceSplit=true;splits=splits[1];}
+if(splits.length){splits.unshift(j,1);Array.prototype.splice.apply(targetParts,splits);break;}}}
+if(!sourceSplit){if(sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLine.clone());}else{sourceParts=[new OpenLayers.Geometry.MultiLineString(sourceLine.clone())];}}}
+if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
+if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
+if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
+return results;},splitWith:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,targetLine,sourceLines,sourceSplit,targetSplit,sourceParts,targetParts;if(geometry instanceof OpenLayers.Geometry.LineString){targetParts=[];sourceParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){targetSplit=false;targetLine=this.components[i];for(var j=0;j<sourceParts.length;++j){splits=sourceParts[j].split(targetLine,options);if(splits){if(mutual){sourceLines=splits[0];if(sourceLines.length){sourceLines.unshift(j,1);Array.prototype.splice.apply(sourceParts,sourceLines);j+=sourceLines.length-2;}
+splits=splits[1];if(splits.length===0){splits=[targetLine.clone()];}}
+for(var k=0,klen=splits.length;k<klen;++k){if(k===0&&targetParts.length){targetParts[targetParts.length-1].addComponent(splits[k]);}else{targetParts.push(new OpenLayers.Geometry.MultiLineString([splits[k]]));}}
+targetSplit=true;}}
+if(!targetSplit){if(targetParts.length){targetParts[targetParts.length-1].addComponent(targetLine.clone());}else{targetParts=[new OpenLayers.Geometry.MultiLineString([targetLine.clone()])];}}}}else{results=geometry.split(this);}
+if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
+if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
+if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
+return results;},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:false,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:false,fixPadding:function(){if(typeof this.padding=="number"){this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding);}},panMapIfOutOfView:false,keepInMap:false,closeOnMove:false,map:null,initialize:function(id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback){if(id==null){id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}
 this.id=id;this.lonlat=lonlat;this.contentSize=(contentSize!=null)?contentSize:new OpenLayers.Size(OpenLayers.Popup.WIDTH,OpenLayers.Popup.HEIGHT);if(contentHTML!=null){this.contentHTML=contentHTML;}
 this.backgroundColor=OpenLayers.Popup.COLOR;this.opacity=OpenLayers.Popup.OPACITY;this.border=OpenLayers.Popup.BORDER;this.div=OpenLayers.Util.createDiv(this.id,null,null,null,null,null,"hidden");this.div.className=this.displayClass;var groupDivId=this.id+"_GroupDiv";this.groupDiv=OpenLayers.Util.createDiv(groupDivId,null,null,null,"relative",null,"hidden");var id=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(id,null,this.contentSize.clone(),null,"relative");this.contentDiv.className=this.contentDisplayClass;this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);if(closeBox){this.addCloseBox(closeBoxCallback);}
 this.registerEvents();},destroy:function(){this.id=null;this.lonlat=null;this.size=null;this.contentHTML=null;this.backgroundColor=null;this.opacity=null;this.border=null;if(this.closeOnMove&&this.map){this.map.events.unregister("movestart",this,this.hide);}
@@ -902,21 +917,7 @@ return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Control.Zo
 eventsInstance.register("buttonclick",this,this.onZoomClick);this.zoomInLink=zoomIn;this.zoomOutLink=zoomOut;return div;},getOrCreateLinks:function(el){var zoomIn=document.getElementById(this.zoomInId),zoomOut=document.getElementById(this.zoomOutId);if(!zoomIn){zoomIn=document.createElement("a");zoomIn.href="#zoomIn";zoomIn.appendChild(document.createTextNode(this.zoomInText));zoomIn.className="olControlZoomIn";el.appendChild(zoomIn);}
 OpenLayers.Element.addClass(zoomIn,"olButton");if(!zoomOut){zoomOut=document.createElement("a");zoomOut.href="#zoomOut";zoomOut.appendChild(document.createTextNode(this.zoomOutText));zoomOut.className="olControlZoomOut";el.appendChild(zoomOut);}
 OpenLayers.Element.addClass(zoomOut,"olButton");return{zoomIn:zoomIn,zoomOut:zoomOut};},onZoomClick:function(evt){var button=evt.buttonElement;if(button===this.zoomInLink){this.map.zoomIn();}else if(button===this.zoomOutLink){this.map.zoomOut();}},destroy:function(){if(this.map){this.map.events.unregister("buttonclick",this,this.onZoomClick);}
-delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this);},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Lang.it={'unhandledRequest':"Codice di ritorno della richiesta ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Livello base",'noFID':"Impossibile aggiornare un elemento grafico che non abbia il FID.",'browserNotSupported':"Il tuo browser non supporta il rendering vettoriale. I renderizzatore attualemnte supportati sono:\n${renderers}",'minZoomLevelError':"La proprietà minZoomLevel è da utilizzare solamente "+"con livelli che abbiano FixedZoomLevels. Il fatto che "+"questo livello wfs controlli la proprietà minZoomLevel è "+"un retaggio del passato. Non possiamo comunque rimuoverla "+"senza rompere le vecchie applicazioni che dipendono su di essa."+"Quindi siamo costretti a deprecarla -- minZoomLevel "+"e sarà rimossa dalla vesione 3.0. Si prega di utilizzare i "+"settaggi di risoluzione min/max come descritto qui: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transazione WFS: SUCCESS ${response}",'commitFailed':"Transazione WFS: FAILED ${response}",'googleWarning':"Il livello Google non è riuscito a caricare correttamente.<br><br>"+"Per evitare questo messaggio, seleziona un nuovo BaseLayer "+"nel selettore di livelli nell'angolo in alto a destra.<br><br>"+"Più precisamente, ciò accade perchè la libreria Google Maps "+"non è stata inclusa nella pagina, oppure non contiene la "+"corretta API key per il tuo sito.<br><br>"+"Sviluppatori: Per aiuto su come farlo funzionare correttamente, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>clicca qui</a>",'getLayerWarning':"Il livello ${layerType} non è riuscito a caricare correttamente.<br><br>"+"Per evitare questo messaggio, seleziona un nuovo BaseLayer "+"nel selettore di livelli nell'angolo in alto a destra.<br><br>"+"Più precisamente, ciò accade perchè la libreria ${layerLib} "+"non è stata inclusa nella pagina.<br><br>"+"Sviluppatori: Per aiuto su come farlo funzionare correttamente, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>clicca qui</a>",'Scale = 1 : ${scaleDenom}':"Scala = 1 : ${scaleDenom}",'reprojectDeprecated':"Stai utilizzando l'opzione 'reproject' sul livello ${layerName}. "+"Questa opzione è deprecata: il suo utilizzo è stato introdotto per"+"supportare il disegno dei dati sopra mappe commerciali, ma tale "+"funzionalità dovrebbe essere ottenuta tramite l'utilizzo della proiezione "+"Spherical Mercator. Per maggiori informazioni consultare qui "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Questo metodo è stato deprecato e sarà rimosso dalla versione 3.0. "+"Si prega di utilizzare il metodo ${newMethod} in alternativa.",'end':''};OpenLayers.Lang["oc"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Requèsta pas gerida, retorna ${statusText}",'Permalink':"Permaligam",'Overlays':"Calques",'Base Layer':"Calc de basa",'noFID':"Impossible de metre a jorn un objècte sens identificant (fid).",'browserNotSupported':"Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}",'minZoomLevelError':"La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu\'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d\'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d\'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaccion WFS : SUCCES ${response}",'commitFailed':"Transaccion WFS : FRACAS ${response}",'googleWarning':"Lo jaç Google es pas estat en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l\'API correspond pas a vòstre site.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquò, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'getLayerWarning':"Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una  BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquí, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Escala ~ 1 : ${scaleDenom}",'W':"O",'E':"È",'N':"N",'S':"S",'reprojectDeprecated':"Utilizatz l\'opcion \'reproject\' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d\'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d\'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d\'utilizar ${newMethod} a la plaça."});OpenLayers.Lang["gsw"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nit behandleti Aafrogsruckmäldig ${statusText}",'Permalink':"Permalink",'Overlays':"Iberlagerige",'Base Layer':"Grundcharte",'noFID':"E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.",'browserNotSupported':"Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}",'minZoomLevelError':"D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge.  Us däm Grund het die Funktion d Eigeschaft \'deprecated\' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transaktion: ERFOLGRYCH ${response}",'commitFailed':"WFS-Transaktion: FÄHLGSCHLAA ${response}",'googleWarning':"Dr Google-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'getLayerWarning':"Dr ${layerType}-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr \'${layerLib}\'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vu Layer \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Maßstab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Du bruchsch d \'reproject\'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go   Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}."});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{'click':{'in':'click','out':'clickout'},'mousemove':{'in':'over','out':'out'},'dblclick':{'in':'dblclick','out':null},'mousedown':{'in':null,'out':null},'mouseup':{'in':null,'out':null},'touchstart':{'in':'click','out':'clickout'}},feature:null,lastFeature:null,down:null,up:null,touch:false,clickTolerance:4,geometryTypes:null,stopClick:true,stopDown:true,stopUp:false,initialize:function(control,layer,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,[control,callbacks,options]);this.layer=layer;},touchstart:function(evt){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this});}
-return OpenLayers.Event.isMultiTouch(evt)?true:this.mousedown(evt);},touchmove:function(evt){OpenLayers.Event.stop(evt);},mousedown:function(evt){if(OpenLayers.Event.isLeftClick(evt)||OpenLayers.Event.isSingleTouch(evt)){this.down=evt.xy;}
-return this.handle(evt)?!this.stopDown:true;},mouseup:function(evt){this.up=evt.xy;return this.handle(evt)?!this.stopUp:true;},click:function(evt){return this.handle(evt)?!this.stopClick:true;},mousemove:function(evt){if(!this.callbacks['over']&&!this.callbacks['out']){return true;}
-this.handle(evt);return true;},dblclick:function(evt){return!this.handle(evt);},geometryTypeMatches:function(feature){return this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1;},handle:function(evt){if(this.feature&&!this.feature.layer){this.feature=null;}
-var type=evt.type;var handled=false;var previouslyIn=!!(this.feature);var click=(type=="click"||type=="dblclick"||type=="touchstart");this.feature=this.layer.getFeatureFromEvent(evt);if(this.feature&&!this.feature.layer){this.feature=null;}
-if(this.lastFeature&&!this.lastFeature.layer){this.lastFeature=null;}
-if(this.feature){if(type==="touchstart"){OpenLayers.Event.stop(evt);}
-var inNew=(this.feature!=this.lastFeature);if(this.geometryTypeMatches(this.feature)){if(previouslyIn&&inNew){if(this.lastFeature){this.triggerCallback(type,'out',[this.lastFeature]);}
-this.triggerCallback(type,'in',[this.feature]);}else if(!previouslyIn||click){this.triggerCallback(type,'in',[this.feature]);}
-this.lastFeature=this.feature;handled=true;}else{if(this.lastFeature&&(previouslyIn&&inNew||click)){this.triggerCallback(type,'out',[this.lastFeature]);}
-this.feature=null;}}else{if(this.lastFeature&&(previouslyIn||click)){this.triggerCallback(type,'out',[this.lastFeature]);}}
-return handled;},triggerCallback:function(type,mode,args){var key=this.EVENTMAP[type][mode];if(key){if(type=='click'&&this.up&&this.down){var dpx=Math.sqrt(Math.pow(this.up.x-this.down.x,2)+
-Math.pow(this.up.y-this.down.y,2));if(dpx<=this.clickTolerance){this.callback(key,args);}}else{this.callback(key,args);}}},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.moveLayerToTop();this.map.events.on({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});activated=true;}
-return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.feature=null;this.lastFeature=null;this.down=null;this.up=null;this.touch=false;this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});deactivated=true;}
-return deactivated;},handleMapEvents:function(evt){if(evt.type=="removelayer"||evt.property=="order"){this.moveLayerToTop();}},moveLayerToTop:function(){var index=Math.max(this.map.Z_INDEX_BASE['Feature']-1,this.layer.getZIndex())+1;this.layer.setZIndex(index);},moveLayerBack:function(){var index=this.layer.getZIndex()-1;if(index>=this.map.Z_INDEX_BASE['Feature']){this.layer.setZIndex(index);}else{this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer));}},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:false,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:false,propertyStyles:null,initialize:function(style,options){OpenLayers.Util.extend(this,options);this.rules=[];if(options&&options.rules){this.addRules(options.rules);}
+delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this);},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Lang.it={'unhandledRequest':"Codice di ritorno della richiesta ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Livello base",'noFID':"Impossibile aggiornare un elemento grafico che non abbia il FID.",'browserNotSupported':"Il tuo browser non supporta il rendering vettoriale. I renderizzatore attualemnte supportati sono:\n${renderers}",'minZoomLevelError':"La proprietà minZoomLevel è da utilizzare solamente "+"con livelli che abbiano FixedZoomLevels. Il fatto che "+"questo livello wfs controlli la proprietà minZoomLevel è "+"un retaggio del passato. Non possiamo comunque rimuoverla "+"senza rompere le vecchie applicazioni che dipendono su di essa."+"Quindi siamo costretti a deprecarla -- minZoomLevel "+"e sarà rimossa dalla vesione 3.0. Si prega di utilizzare i "+"settaggi di risoluzione min/max come descritto qui: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transazione WFS: SUCCESS ${response}",'commitFailed':"Transazione WFS: FAILED ${response}",'googleWarning':"Il livello Google non è riuscito a caricare correttamente.<br><br>"+"Per evitare questo messaggio, seleziona un nuovo BaseLayer "+"nel selettore di livelli nell'angolo in alto a destra.<br><br>"+"Più precisamente, ciò accade perchè la libreria Google Maps "+"non è stata inclusa nella pagina, oppure non contiene la "+"corretta API key per il tuo sito.<br><br>"+"Sviluppatori: Per aiuto su come farlo funzionare correttamente, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>clicca qui</a>",'getLayerWarning':"Il livello ${layerType} non è riuscito a caricare correttamente.<br><br>"+"Per evitare questo messaggio, seleziona un nuovo BaseLayer "+"nel selettore di livelli nell'angolo in alto a destra.<br><br>"+"Più precisamente, ciò accade perchè la libreria ${layerLib} "+"non è stata inclusa nella pagina.<br><br>"+"Sviluppatori: Per aiuto su come farlo funzionare correttamente, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>clicca qui</a>",'Scale = 1 : ${scaleDenom}':"Scala = 1 : ${scaleDenom}",'reprojectDeprecated':"Stai utilizzando l'opzione 'reproject' sul livello ${layerName}. "+"Questa opzione è deprecata: il suo utilizzo è stato introdotto per"+"supportare il disegno dei dati sopra mappe commerciali, ma tale "+"funzionalità dovrebbe essere ottenuta tramite l'utilizzo della proiezione "+"Spherical Mercator. Per maggiori informazioni consultare qui "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Questo metodo è stato deprecato e sarà rimosso dalla versione 3.0. "+"Si prega di utilizzare il metodo ${newMethod} in alternativa.",'end':''};OpenLayers.Lang["oc"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Requèsta pas gerida, retorna ${statusText}",'Permalink':"Permaligam",'Overlays':"Calques",'Base Layer':"Calc de basa",'noFID':"Impossible de metre a jorn un objècte sens identificant (fid).",'browserNotSupported':"Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}",'minZoomLevelError':"La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu\'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d\'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d\'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaccion WFS : SUCCES ${response}",'commitFailed':"Transaccion WFS : FRACAS ${response}",'googleWarning':"Lo jaç Google es pas estat en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l\'API correspond pas a vòstre site.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquò, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'getLayerWarning':"Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una  BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquí, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Escala ~ 1 : ${scaleDenom}",'W':"O",'E':"È",'N':"N",'S':"S",'reprojectDeprecated':"Utilizatz l\'opcion \'reproject\' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d\'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d\'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d\'utilizar ${newMethod} a la plaça."});OpenLayers.Lang["gsw"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nit behandleti Aafrogsruckmäldig ${statusText}",'Permalink':"Permalink",'Overlays':"Iberlagerige",'Base Layer':"Grundcharte",'noFID':"E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.",'browserNotSupported':"Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}",'minZoomLevelError':"D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge.  Us däm Grund het die Funktion d Eigeschaft \'deprecated\' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transaktion: ERFOLGRYCH ${response}",'commitFailed':"WFS-Transaktion: FÄHLGSCHLAA ${response}",'googleWarning':"Dr Google-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'getLayerWarning':"Dr ${layerType}-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr \'${layerLib}\'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vu Layer \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Maßstab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Du bruchsch d \'reproject\'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go   Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}."});OpenLayers.Geometry.MultiPolygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Polygon"],CLASS_NAME:"OpenLayers.Geometry.MultiPolygon"});OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:false,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:false,propertyStyles:null,initialize:function(style,options){OpenLayers.Util.extend(this,options);this.rules=[];if(options&&options.rules){this.addRules(options.rules);}
 this.setDefaultStyle(style||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){for(var i=0,len=this.rules.length;i<len;i++){this.rules[i].destroy();this.rules[i]=null;}
 this.rules=null;this.defaultStyle=null;},createSymbolizer:function(feature){var style=this.defaultsPerSymbolizer?{}:this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),feature);var rules=this.rules;var rule,context;var elseRules=[];var appliedRules=false;for(var i=0,len=rules.length;i<len;i++){rule=rules[i];var applies=rule.evaluate(feature);if(applies){if(rule instanceof OpenLayers.Rule&&rule.elseFilter){elseRules.push(rule);}else{appliedRules=true;this.applySymbolizer(rule,style,feature);}}}
 if(appliedRules==false&&elseRules.length>0){appliedRules=true;for(var i=0,len=elseRules.length;i<len;i++){this.applySymbolizer(elseRules[i],style,feature);}}
@@ -930,7 +931,36 @@ return style;},findPropertyStyles:function(){var propertyStyles={};var style=thi
 return propertyStyles;},addPropertyStyles:function(propertyStyles,symbolizer){var property;for(var key in symbolizer){property=symbolizer[key];if(typeof property=="string"&&property.match(/\$\{\w+\}/)){propertyStyles[key]=true;}}
 return propertyStyles;},addRules:function(rules){Array.prototype.push.apply(this.rules,rules);this.propertyStyles=this.findPropertyStyles();},setDefaultStyle:function(style){this.defaultStyle=style;this.propertyStyles=this.findPropertyStyles();},getSymbolizerPrefix:function(geometry){var prefixes=OpenLayers.Style.SYMBOLIZER_PREFIXES;for(var i=0,len=prefixes.length;i<len;i++){if(geometry.CLASS_NAME.indexOf(prefixes[i])!=-1){return prefixes[i];}}},clone:function(){var options=OpenLayers.Util.extend({},this);if(this.rules){options.rules=[];for(var i=0,len=this.rules.length;i<len;++i){options.rules.push(this.rules[i].clone());}}
 options.context=this.context&&OpenLayers.Util.extend({},this.context);var defaultStyle=OpenLayers.Util.extend({},this.defaultStyle);return new OpenLayers.Style(defaultStyle,options);},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(value,context,feature,property){if(typeof value=="string"&&value.indexOf("${")!=-1){value=OpenLayers.String.format(value,context,[feature,property]);value=(isNaN(value)||!value)?value:parseFloat(value);}
-return value;};OpenLayers.Style.SYMBOLIZER_PREFIXES=['Point','Line','Polygon','Text','Raster'];OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,initialize:function(style,options){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),"select":new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"]),"temporary":new OpenLayers.Style(OpenLayers.Feature.Vector.style["temporary"]),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(style instanceof OpenLayers.Style){this.styles["default"]=style;this.styles["select"]=style;this.styles["temporary"]=style;this.styles["delete"]=style;}else if(typeof style=="object"){for(var key in style){if(style[key]instanceof OpenLayers.Style){this.styles[key]=style[key];}else if(typeof style[key]=="object"){this.styles[key]=new OpenLayers.Style(style[key]);}else{this.styles["default"]=new OpenLayers.Style(style);this.styles["select"]=new OpenLayers.Style(style);this.styles["temporary"]=new OpenLayers.Style(style);this.styles["delete"]=new OpenLayers.Style(style);break;}}}
+return value;};OpenLayers.Style.SYMBOLIZER_PREFIXES=['Point','Line','Polygon','Text','Raster'];OpenLayers.Filter=OpenLayers.Class({initialize:function(options){OpenLayers.Util.extend(this,options);},destroy:function(){},evaluate:function(context){return true;},clone:function(){return null;},toString:function(){var string;if(OpenLayers.Format&&OpenLayers.Format.CQL){string=OpenLayers.Format.CQL.prototype.write(this);}else{string=Object.prototype.toString.call(this);}
+return string;},CLASS_NAME:"OpenLayers.Filter"});OpenLayers.Filter.Spatial=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,distance:null,distanceUnits:null,evaluate:function(feature){var intersect=false;switch(this.type){case OpenLayers.Filter.Spatial.BBOX:case OpenLayers.Filter.Spatial.INTERSECTS:if(feature.geometry){var geom=this.value;if(this.value.CLASS_NAME=="OpenLayers.Bounds"){geom=this.value.toGeometry();}
+if(feature.geometry.intersects(geom)){intersect=true;}}
+break;default:throw new Error('evaluate is not implemented for this filter type.');}
+return intersect;},clone:function(){var options=OpenLayers.Util.applyDefaults({value:this.value&&this.value.clone&&this.value.clone()},this);return new OpenLayers.Filter.Spatial(options);},CLASS_NAME:"OpenLayers.Filter.Spatial"});OpenLayers.Filter.Spatial.BBOX="BBOX";OpenLayers.Filter.Spatial.INTERSECTS="INTERSECTS";OpenLayers.Filter.Spatial.DWITHIN="DWITHIN";OpenLayers.Filter.Spatial.WITHIN="WITHIN";OpenLayers.Filter.Spatial.CONTAINS="CONTAINS";OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){this.layer.events.on({"moveend":this.update,"refresh":this.update,"visibilitychanged":this.update,scope:this});this.update();}
+return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.layer.events.un({"moveend":this.update,"refresh":this.update,"visibilitychanged":this.update,scope:this});}
+return deactivated;},update:function(options){var mapBounds=this.getMapBounds();if(mapBounds!==null&&((options&&options.force)||(this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(mapBounds)))){this.calculateBounds(mapBounds);this.resolution=this.layer.map.getResolution();this.triggerRead(options);}},getMapBounds:function(){if(this.layer.map===null){return null;}
+var bounds=this.layer.map.getExtent();if(bounds&&!this.layer.projection.equals(this.layer.map.getProjectionObject())){bounds=bounds.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection);}
+return bounds;},invalidBounds:function(mapBounds){if(!mapBounds){mapBounds=this.getMapBounds();}
+var invalid=!this.bounds||!this.bounds.containsBounds(mapBounds);if(!invalid&&this.resFactor){var ratio=this.resolution/this.layer.map.getResolution();invalid=(ratio>=this.resFactor||ratio<=(1/this.resFactor));}
+return invalid;},calculateBounds:function(mapBounds){if(!mapBounds){mapBounds=this.getMapBounds();}
+var center=mapBounds.getCenterLonLat();var dataWidth=mapBounds.getWidth()*this.ratio;var dataHeight=mapBounds.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(center.lon-(dataWidth/2),center.lat-(dataHeight/2),center.lon+(dataWidth/2),center.lat+(dataHeight/2));},triggerRead:function(options){if(this.response&&!(options&&options.noAbort===true)){this.layer.protocol.abort(this.response);this.layer.events.triggerEvent("loadend");}
+this.layer.events.triggerEvent("loadstart");this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:this.createFilter(),callback:this.merge,scope:this},options));},createFilter:function(){var filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});if(this.layer.filter){filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.layer.filter,filter]});}
+return filter;},merge:function(resp){this.layer.destroyFeatures();if(resp.code==OpenLayers.Protocol.Response.SUCCESS){var features=resp.features;if(features&&features.length>0){var remote=this.layer.projection;var local=this.layer.map.getProjectionObject();if(!local.equals(remote)){var geom;for(var i=0,len=features.length;i<len;++i){geom=features[i].geometry;if(geom){geom.transform(remote,local);}}}
+this.layer.addFeatures(features);}}else{this.bounds=null;}
+this.response=null;this.layer.events.triggerEvent("loadend");},CLASS_NAME:"OpenLayers.Strategy.BBOX"});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{'click':{'in':'click','out':'clickout'},'mousemove':{'in':'over','out':'out'},'dblclick':{'in':'dblclick','out':null},'mousedown':{'in':null,'out':null},'mouseup':{'in':null,'out':null},'touchstart':{'in':'click','out':'clickout'}},feature:null,lastFeature:null,down:null,up:null,touch:false,clickTolerance:4,geometryTypes:null,stopClick:true,stopDown:true,stopUp:false,initialize:function(control,layer,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,[control,callbacks,options]);this.layer=layer;},touchstart:function(evt){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this});}
+return OpenLayers.Event.isMultiTouch(evt)?true:this.mousedown(evt);},touchmove:function(evt){OpenLayers.Event.stop(evt);},mousedown:function(evt){if(OpenLayers.Event.isLeftClick(evt)||OpenLayers.Event.isSingleTouch(evt)){this.down=evt.xy;}
+return this.handle(evt)?!this.stopDown:true;},mouseup:function(evt){this.up=evt.xy;return this.handle(evt)?!this.stopUp:true;},click:function(evt){return this.handle(evt)?!this.stopClick:true;},mousemove:function(evt){if(!this.callbacks['over']&&!this.callbacks['out']){return true;}
+this.handle(evt);return true;},dblclick:function(evt){return!this.handle(evt);},geometryTypeMatches:function(feature){return this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1;},handle:function(evt){if(this.feature&&!this.feature.layer){this.feature=null;}
+var type=evt.type;var handled=false;var previouslyIn=!!(this.feature);var click=(type=="click"||type=="dblclick"||type=="touchstart");this.feature=this.layer.getFeatureFromEvent(evt);if(this.feature&&!this.feature.layer){this.feature=null;}
+if(this.lastFeature&&!this.lastFeature.layer){this.lastFeature=null;}
+if(this.feature){if(type==="touchstart"){OpenLayers.Event.stop(evt);}
+var inNew=(this.feature!=this.lastFeature);if(this.geometryTypeMatches(this.feature)){if(previouslyIn&&inNew){if(this.lastFeature){this.triggerCallback(type,'out',[this.lastFeature]);}
+this.triggerCallback(type,'in',[this.feature]);}else if(!previouslyIn||click){this.triggerCallback(type,'in',[this.feature]);}
+this.lastFeature=this.feature;handled=true;}else{if(this.lastFeature&&(previouslyIn&&inNew||click)){this.triggerCallback(type,'out',[this.lastFeature]);}
+this.feature=null;}}else{if(this.lastFeature&&(previouslyIn||click)){this.triggerCallback(type,'out',[this.lastFeature]);}}
+return handled;},triggerCallback:function(type,mode,args){var key=this.EVENTMAP[type][mode];if(key){if(type=='click'&&this.up&&this.down){var dpx=Math.sqrt(Math.pow(this.up.x-this.down.x,2)+
+Math.pow(this.up.y-this.down.y,2));if(dpx<=this.clickTolerance){this.callback(key,args);}}else{this.callback(key,args);}}},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.moveLayerToTop();this.map.events.on({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.feature=null;this.lastFeature=null;this.down=null;this.up=null;this.touch=false;this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});deactivated=true;}
+return deactivated;},handleMapEvents:function(evt){if(evt.type=="removelayer"||evt.property=="order"){this.moveLayerToTop();}},moveLayerToTop:function(){var index=Math.max(this.map.Z_INDEX_BASE['Feature']-1,this.layer.getZIndex())+1;this.layer.setZIndex(index);},moveLayerBack:function(){var index=this.layer.getZIndex()-1;if(index>=this.map.Z_INDEX_BASE['Feature']){this.layer.setZIndex(index);}else{this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer));}},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,initialize:function(style,options){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),"select":new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"]),"temporary":new OpenLayers.Style(OpenLayers.Feature.Vector.style["temporary"]),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(style instanceof OpenLayers.Style){this.styles["default"]=style;this.styles["select"]=style;this.styles["temporary"]=style;this.styles["delete"]=style;}else if(typeof style=="object"){for(var key in style){if(style[key]instanceof OpenLayers.Style){this.styles[key]=style[key];}else if(typeof style[key]=="object"){this.styles[key]=new OpenLayers.Style(style[key]);}else{this.styles["default"]=new OpenLayers.Style(style);this.styles["select"]=new OpenLayers.Style(style);this.styles["temporary"]=new OpenLayers.Style(style);this.styles["delete"]=new OpenLayers.Style(style);break;}}}
 OpenLayers.Util.extend(this,options);},destroy:function(){for(var key in this.styles){this.styles[key].destroy();}
 this.styles=null;},createSymbolizer:function(feature,intent){if(!feature){feature=new OpenLayers.Feature.Vector();}
 if(!this.styles[intent]){intent="default";}
@@ -1044,7 +1074,11 @@ OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this,arguments);},onD
 layer.drawFeature(this.handles[i],this.renderIntent);}},transformFeature:function(mods){if(!this._setfeature){this.scale*=(mods.scale||1);this.ratio*=(mods.ratio||1);var oldRotation=this.rotation;this.rotation=(this.rotation+(mods.rotation||0))%360;if(this.events.triggerEvent("beforetransform",mods)!==false){var feature=this.feature;var geom=feature.geometry;var center=this.center;geom.rotate(-oldRotation,center);if(mods.scale||mods.ratio){geom.resize(mods.scale,center,mods.ratio);}else if(mods.center){feature.move(mods.center.getBounds().getCenterLonLat());}
 geom.rotate(this.rotation,center);this.layer.drawFeature(feature);feature.toState(OpenLayers.State.UPDATE);this.events.triggerEvent("transform",mods);}}
 this.layer.drawFeature(this.box,this.renderIntent);this.drawHandles();},destroy:function(){var geom;for(var i=0;i<8;++i){geom=this.box.geometry.components[i];geom._handle.destroy();geom._handle=null;geom._rotationHandle&&geom._rotationHandle.destroy();geom._rotationHandle=null;}
-this.center=null;this.feature=null;this.handles=null;this.rotationHandleSymbolizer=null;this.rotationHandles=null;this.box.destroy();this.box=null;this.layer=null;this.dragControl.destroy();this.dragControl=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.TransformFeature"});OpenLayers.Lang["ia"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Le responsa a un requesta non esseva maneate: ${statusText}",'Permalink':"Permaligamine",'Overlays':"Superpositiones",'Base Layer':"Strato de base",'noFID':"Non pote actualisar un elemento sin FID.",'browserNotSupported':"Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}",'minZoomLevelError':"Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaction WFS: SUCCESSO ${response}",'commitFailed':"Transaction WFS: FALLEVA ${response}",'googleWarning':"Le strato Google non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicca hic\x3c/a",'getLayerWarning':"Le strato ${layerType} non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicca hic\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Scala = 1 : ${scaleDenom}",'W':"W",'E':"E",'N':"N",'S':"S",'reprojectDeprecated':"Tu usa le option \'reproject\' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco."});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:'olHandlerBoxZoomBox',boxOffsets:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.dragHandler=new OpenLayers.Handler.Drag(this,{down:this.startBox,move:this.moveBox,out:this.removeBox,up:this.endBox},{keyMask:this.keyMask});},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler){this.dragHandler.destroy();this.dragHandler=null;}},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv('zoomBox',{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox");},moveBox:function(xy){var startX=this.dragHandler.start.x;var startY=this.dragHandler.start.y;var deltaX=Math.abs(startX-xy.x);var deltaY=Math.abs(startY-xy.y);var offset=this.getBoxOffsets();this.zoomBox.style.width=(deltaX+offset.width+1)+"px";this.zoomBox.style.height=(deltaY+offset.height+1)+"px";this.zoomBox.style.left=(xy.x<startX?startX-deltaX-offset.left:startX-offset.left)+"px";this.zoomBox.style.top=(xy.y<startY?startY-deltaY-offset.top:startY-offset.top)+"px";},endBox:function(end){var result;if(Math.abs(this.dragHandler.start.x-end.x)>5||Math.abs(this.dragHandler.start.y-end.y)>5){var start=this.dragHandler.start;var top=Math.min(start.y,end.y);var bottom=Math.max(start.y,end.y);var left=Math.min(start.x,end.x);var right=Math.max(start.x,end.x);result=new OpenLayers.Bounds(left,bottom,right,top);}else{result=this.dragHandler.start.clone();}
+this.center=null;this.feature=null;this.handles=null;this.rotationHandleSymbolizer=null;this.rotationHandles=null;this.box.destroy();this.box=null;this.layer=null;this.dragControl.destroy();this.dragControl=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.TransformFeature"});OpenLayers.Filter.Logical=OpenLayers.Class(OpenLayers.Filter,{filters:null,type:null,initialize:function(options){this.filters=[];OpenLayers.Filter.prototype.initialize.apply(this,[options]);},destroy:function(){this.filters=null;OpenLayers.Filter.prototype.destroy.apply(this);},evaluate:function(context){var i,len;switch(this.type){case OpenLayers.Filter.Logical.AND:for(i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==false){return false;}}
+return true;case OpenLayers.Filter.Logical.OR:for(i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==true){return true;}}
+return false;case OpenLayers.Filter.Logical.NOT:return(!this.filters[0].evaluate(context));}
+return undefined;},clone:function(){var filters=[];for(var i=0,len=this.filters.length;i<len;++i){filters.push(this.filters[i].clone());}
+return new OpenLayers.Filter.Logical({type:this.type,filters:filters});},CLASS_NAME:"OpenLayers.Filter.Logical"});OpenLayers.Filter.Logical.AND="&&";OpenLayers.Filter.Logical.OR="||";OpenLayers.Filter.Logical.NOT="!";OpenLayers.Lang["ia"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Le responsa a un requesta non esseva maneate: ${statusText}",'Permalink':"Permaligamine",'Overlays':"Superpositiones",'Base Layer':"Strato de base",'noFID':"Non pote actualisar un elemento sin FID.",'browserNotSupported':"Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}",'minZoomLevelError':"Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaction WFS: SUCCESSO ${response}",'commitFailed':"Transaction WFS: FALLEVA ${response}",'googleWarning':"Le strato Google non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicca hic\x3c/a",'getLayerWarning':"Le strato ${layerType} non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicca hic\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Scala = 1 : ${scaleDenom}",'W':"W",'E':"E",'N':"N",'S':"S",'reprojectDeprecated':"Tu usa le option \'reproject\' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco."});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:'olHandlerBoxZoomBox',boxOffsets:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.dragHandler=new OpenLayers.Handler.Drag(this,{down:this.startBox,move:this.moveBox,out:this.removeBox,up:this.endBox},{keyMask:this.keyMask});},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler){this.dragHandler.destroy();this.dragHandler=null;}},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv('zoomBox',{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox");},moveBox:function(xy){var startX=this.dragHandler.start.x;var startY=this.dragHandler.start.y;var deltaX=Math.abs(startX-xy.x);var deltaY=Math.abs(startY-xy.y);var offset=this.getBoxOffsets();this.zoomBox.style.width=(deltaX+offset.width+1)+"px";this.zoomBox.style.height=(deltaY+offset.height+1)+"px";this.zoomBox.style.left=(xy.x<startX?startX-deltaX-offset.left:startX-offset.left)+"px";this.zoomBox.style.top=(xy.y<startY?startY-deltaY-offset.top:startY-offset.top)+"px";},endBox:function(end){var result;if(Math.abs(this.dragHandler.start.x-end.x)>5||Math.abs(this.dragHandler.start.y-end.y)>5){var start=this.dragHandler.start;var top=Math.min(start.y,end.y);var bottom=Math.max(start.y,end.y);var left=Math.min(start.x,end.x);var right=Math.max(start.x,end.x);result=new OpenLayers.Bounds(left,bottom,right,top);}else{result=this.dragHandler.start.clone();}
 this.removeBox();this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;this.boxOffsets=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox");},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){if(this.dragHandler.deactivate()){if(this.zoomBox){this.removeBox();}}
 return true;}else{return false;}},getBoxOffsets:function(){if(!this.boxOffsets){var testDiv=document.createElement("div");testDiv.style.position="absolute";testDiv.style.border="1px solid black";testDiv.style.width="3px";document.body.appendChild(testDiv);var w3cBoxModel=testDiv.clientWidth==3;document.body.removeChild(testDiv);var left=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width"));var right=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width"));var top=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-top-width"));var bottom=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:left,right:right,top:top,bottom:bottom,width:w3cBoxModel===false?left+right:0,height:w3cBoxModel===false?top+bottom:0};}
 return this.boxOffsets;},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,keyMask:null,alwaysZoom:false,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var bounds;if(!this.out){var minXY=this.map.getLonLatFromPixel({x:position.left,y:position.bottom});var maxXY=this.map.getLonLatFromPixel({x:position.right,y:position.top});bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);}else{var pixWidth=Math.abs(position.right-position.left);var pixHeight=Math.abs(position.top-position.bottom);var zoomFactor=Math.min((this.map.size.h/pixHeight),(this.map.size.w/pixWidth));var extent=this.map.getExtent();var center=this.map.getLonLatFromPixel(position.getCenterPixel());var xmin=center.lon-(extent.getWidth()/2)*zoomFactor;var xmax=center.lon+(extent.getWidth()/2)*zoomFactor;var ymin=center.lat-(extent.getHeight()/2)*zoomFactor;var ymax=center.lat+(extent.getHeight()/2)*zoomFactor;bounds=new OpenLayers.Bounds(xmin,ymin,xmax,ymax);}
@@ -1138,9 +1172,78 @@ if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calc
 OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x:this.px.x+this.offset.x,y:this.px.y+this.offset.y});}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},isDrawn:function(){var isDrawn=(this.imageDiv&&this.imageDiv.parentNode&&(this.imageDiv.parentNode.nodeType!=11));return isDrawn;},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
 this.events=new OpenLayers.Events(this,this.icon.imageDiv);},destroy:function(){this.erase();this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},erase:function(){if(this.icon!=null){this.icon.erase();}},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
 this.lonlat=this.map.getLonLatFromLayerPx(px);},isDrawn:function(){var isDrawn=(this.icon&&this.icon.isDrawn());return isDrawn;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
-return onScreen;},inflate:function(inflate){if(this.icon){this.icon.setSize({w:this.icon.size.w*inflate,h:this.icon.size.h*inflate});}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),{w:21,h:25},{x:-10.5,y:-25});};OpenLayers.Lang["ru"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Необработанный запрос вернул ${statusText}",'Permalink':"Постоянная ссылка",'Overlays':"Слои",'Base Layer':"Основной слой",'noFID':"Невозможно обновить объект, для которого нет FID.",'browserNotSupported':"Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}",'minZoomLevelError':"Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Транзакция WFS: УСПЕШНО ${response}",'commitFailed':"Транзакция WFS: ОШИБКА ${response}",'googleWarning':"Слой Google не удалось нормально загрузить.\x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'getLayerWarning':"Слой ${layerType} не удалось нормально загрузить. \x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Масштаб = 1 : ${scaleDenom}",'W':"З",'E':"В",'N':"С",'S':"Ю",'reprojectDeprecated':"Вы используете опцию \'reproject\' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}."});OpenLayers.Lang["nn"]=OpenLayers.Util.applyDefaults({'Scale = 1 : ${scaleDenom}':"Skala = 1 : ${scaleDenom}"});OpenLayers.Lang["fi"]=OpenLayers.Util.applyDefaults({'Permalink':"Ikilinkki",'Overlays':"Kerrokset",'Base Layer':"Peruskerros",'W':"L",'E':"I",'N':"P",'S':"E"});OpenLayers.Lang.es={'unhandledRequest':"Respuesta a petición no gestionada ${statusText}",'Permalink':"Enlace permanente",'Overlays':"Capas superpuestas",'Base Layer':"Capa Base",'noFID':"No se puede actualizar un elemento para el que no existe FID.",'browserNotSupported':"Su navegador no soporta renderización vectorial. Los renderizadores soportados actualmente son:\n${renderers}",'minZoomLevelError':"La propiedad minZoomLevel debe sólo utilizarse "+"con las capas que tienen FixedZoomLevels. El hecho de que "+"una capa wfs compruebe minZoomLevel es una reliquia del "+"pasado. Sin embargo, no podemos eliminarla sin discontinuar "+"probablemente las aplicaciones OL que puedan depender de ello. "+"Así pues estamos haciéndolo obsoleto --la comprobación "+"minZoomLevel se eliminará en la versión 3.0. Utilice el ajuste "+"de resolution min/max en su lugar, tal como se describe aquí: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacción WFS: ÉXITO ${response}",'commitFailed':"Transacción WFS: FALLÓ ${response}",'googleWarning':"La capa Google no pudo ser cargada correctamente.<br><br>"+"Para evitar este mensaje, seleccione una nueva Capa Base "+"en el selector de capas en la esquina superior derecha.<br><br>"+"Probablemente, esto se debe a que el script de la biblioteca de "+"Google Maps no fue correctamente incluido en su página, o no "+"contiene la clave del API correcta para su sitio.<br><br>"+"Desarrolladores: Para ayudar a hacer funcionar esto correctamente, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>haga clic aquí</a>",'getLayerWarning':"La capa ${layerType} no pudo ser cargada correctamente.<br><br>"+"Para evitar este mensaje, seleccione una nueva Capa Base "+"en el selector de capas en la esquina superior derecha.<br><br>"+"Probablemente, esto se debe a que el script de "+"la biblioteca ${layerLib} "+"no fue correctamente incluido en su página.<br><br>"+"Desarrolladores: Para ayudar a hacer funcionar esto correctamente, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>haga clic aquí</a>",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':'O','E':'E','N':'N','S':'S','Graticule':'Retícula','reprojectDeprecated':"Está usando la opción 'reproject' en la capa "+"${layerName}. Esta opción es obsoleta: su uso fue diseñado "+"para soportar la visualización de datos sobre mapas base comerciales, "+"pero ahora esa funcionalidad debería conseguirse mediante el soporte "+"de la proyección Spherical Mercator. Más información disponible en "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Este método es obsoleto y se eliminará en la versión 3.0. "+"Por favor utilice el método ${newMethod} en su lugar.",'end':''};OpenLayers.Layer.SphericalMercator={getExtent:function(){var extent=null;if(this.sphericalMercator){extent=this.map.calculateBounds();}else{extent=OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);}
+return onScreen;},inflate:function(inflate){if(this.icon){this.icon.setSize({w:this.icon.size.w*inflate,h:this.icon.size.h*inflate});}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),{w:21,h:25},{x:-10.5,y:-25});};OpenLayers.Format.JSON=OpenLayers.Class(OpenLayers.Format,{indent:"    ",space:" ",newline:"\n",level:0,pretty:false,nativeJSON:(function(){return!!(window.JSON&&typeof JSON.parse=="function"&&typeof JSON.stringify=="function");})(),read:function(json,filter){var object;if(this.nativeJSON){object=JSON.parse(json,filter);}else try{if(/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){object=eval('('+json+')');if(typeof filter==='function'){function walk(k,v){if(v&&typeof v==='object'){for(var i in v){if(v.hasOwnProperty(i)){v[i]=walk(i,v[i]);}}}
+return filter(k,v);}
+object=walk('',object);}}}catch(e){}
+if(this.keepData){this.data=object;}
+return object;},write:function(value,pretty){this.pretty=!!pretty;var json=null;var type=typeof value;if(this.serialize[type]){try{json=(!this.pretty&&this.nativeJSON)?JSON.stringify(value):this.serialize[type].apply(this,[value]);}catch(err){OpenLayers.Console.error("Trouble serializing: "+err);}}
+return json;},writeIndent:function(){var pieces=[];if(this.pretty){for(var i=0;i<this.level;++i){pieces.push(this.indent);}}
+return pieces.join('');},writeNewline:function(){return(this.pretty)?this.newline:'';},writeSpace:function(){return(this.pretty)?this.space:'';},serialize:{'object':function(object){if(object==null){return"null";}
+if(object.constructor==Date){return this.serialize.date.apply(this,[object]);}
+if(object.constructor==Array){return this.serialize.array.apply(this,[object]);}
+var pieces=['{'];this.level+=1;var key,keyJSON,valueJSON;var addComma=false;for(key in object){if(object.hasOwnProperty(key)){keyJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[key,this.pretty]);valueJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[object[key],this.pretty]);if(keyJSON!=null&&valueJSON!=null){if(addComma){pieces.push(',');}
+pieces.push(this.writeNewline(),this.writeIndent(),keyJSON,':',this.writeSpace(),valueJSON);addComma=true;}}}
+this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),'}');return pieces.join('');},'array':function(array){var json;var pieces=['['];this.level+=1;for(var i=0,len=array.length;i<len;++i){json=OpenLayers.Format.JSON.prototype.write.apply(this,[array[i],this.pretty]);if(json!=null){if(i>0){pieces.push(',');}
+pieces.push(this.writeNewline(),this.writeIndent(),json);}}
+this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),']');return pieces.join('');},'string':function(string){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};if(/["\\\x00-\x1f]/.test(string)){return'"'+string.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];if(c){return c;}
+c=b.charCodeAt();return'\\u00'+
+Math.floor(c/16).toString(16)+
+(c%16).toString(16);})+'"';}
+return'"'+string+'"';},'number':function(number){return isFinite(number)?String(number):"null";},'boolean':function(bool){return String(bool);},'date':function(date){function format(number){return(number<10)?'0'+number:number;}
+return'"'+date.getFullYear()+'-'+
+format(date.getMonth()+1)+'-'+
+format(date.getDate())+'T'+
+format(date.getHours())+':'+
+format(date.getMinutes())+':'+
+format(date.getSeconds())+'"';}},CLASS_NAME:"OpenLayers.Format.JSON"});OpenLayers.Format.GeoJSON=OpenLayers.Class(OpenLayers.Format.JSON,{ignoreExtraDims:false,read:function(json,type,filter){type=(type)?type:"FeatureCollection";var results=null;var obj=null;if(typeof json=="string"){obj=OpenLayers.Format.JSON.prototype.read.apply(this,[json,filter]);}else{obj=json;}
+if(!obj){OpenLayers.Console.error("Bad JSON: "+json);}else if(typeof(obj.type)!="string"){OpenLayers.Console.error("Bad GeoJSON - no type: "+json);}else if(this.isValidType(obj,type)){switch(type){case"Geometry":try{results=this.parseGeometry(obj);}catch(err){OpenLayers.Console.error(err);}
+break;case"Feature":try{results=this.parseFeature(obj);results.type="Feature";}catch(err){OpenLayers.Console.error(err);}
+break;case"FeatureCollection":results=[];switch(obj.type){case"Feature":try{results.push(this.parseFeature(obj));}catch(err){results=null;OpenLayers.Console.error(err);}
+break;case"FeatureCollection":for(var i=0,len=obj.features.length;i<len;++i){try{results.push(this.parseFeature(obj.features[i]));}catch(err){results=null;OpenLayers.Console.error(err);}}
+break;default:try{var geom=this.parseGeometry(obj);results.push(new OpenLayers.Feature.Vector(geom));}catch(err){results=null;OpenLayers.Console.error(err);}}
+break;}}
+return results;},isValidType:function(obj,type){var valid=false;switch(type){case"Geometry":if(OpenLayers.Util.indexOf(["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon","Box","GeometryCollection"],obj.type)==-1){OpenLayers.Console.error("Unsupported geometry type: "+
+obj.type);}else{valid=true;}
+break;case"FeatureCollection":valid=true;break;default:if(obj.type==type){valid=true;}else{OpenLayers.Console.error("Cannot convert types from "+
+obj.type+" to "+type);}}
+return valid;},parseFeature:function(obj){var feature,geometry,attributes,bbox;attributes=(obj.properties)?obj.properties:{};bbox=(obj.geometry&&obj.geometry.bbox)||obj.bbox;try{geometry=this.parseGeometry(obj.geometry);}catch(err){throw err;}
+feature=new OpenLayers.Feature.Vector(geometry,attributes);if(bbox){feature.bounds=OpenLayers.Bounds.fromArray(bbox);}
+if(obj.id){feature.fid=obj.id;}
+return feature;},parseGeometry:function(obj){if(obj==null){return null;}
+var geometry,collection=false;if(obj.type=="GeometryCollection"){if(!(OpenLayers.Util.isArray(obj.geometries))){throw"GeometryCollection must have geometries array: "+obj;}
+var numGeom=obj.geometries.length;var components=new Array(numGeom);for(var i=0;i<numGeom;++i){components[i]=this.parseGeometry.apply(this,[obj.geometries[i]]);}
+geometry=new OpenLayers.Geometry.Collection(components);collection=true;}else{if(!(OpenLayers.Util.isArray(obj.coordinates))){throw"Geometry must have coordinates array: "+obj;}
+if(!this.parseCoords[obj.type.toLowerCase()]){throw"Unsupported geometry type: "+obj.type;}
+try{geometry=this.parseCoords[obj.type.toLowerCase()].apply(this,[obj.coordinates]);}catch(err){throw err;}}
+if(this.internalProjection&&this.externalProjection&&!collection){geometry.transform(this.externalProjection,this.internalProjection);}
+return geometry;},parseCoords:{"point":function(array){if(this.ignoreExtraDims==false&&array.length!=2){throw"Only 2D points are supported: "+array;}
+return new OpenLayers.Geometry.Point(array[0],array[1]);},"multipoint":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
+points.push(p);}
+return new OpenLayers.Geometry.MultiPoint(points);},"linestring":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
+points.push(p);}
+return new OpenLayers.Geometry.LineString(points);},"multilinestring":function(array){var lines=[];var l=null;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
+lines.push(l);}
+return new OpenLayers.Geometry.MultiLineString(lines);},"polygon":function(array){var rings=[];var r,l;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
+r=new OpenLayers.Geometry.LinearRing(l.components);rings.push(r);}
+return new OpenLayers.Geometry.Polygon(rings);},"multipolygon":function(array){var polys=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["polygon"].apply(this,[array[i]]);}catch(err){throw err;}
+polys.push(p);}
+return new OpenLayers.Geometry.MultiPolygon(polys);},"box":function(array){if(array.length!=2){throw"GeoJSON box coordinates must have 2 elements";}
+return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(array[0][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[0][1])])]);}},write:function(obj,pretty){var geojson={"type":null};if(OpenLayers.Util.isArray(obj)){geojson.type="FeatureCollection";var numFeatures=obj.length;geojson.features=new Array(numFeatures);for(var i=0;i<numFeatures;++i){var element=obj[i];if(!element instanceof OpenLayers.Feature.Vector){var msg="FeatureCollection only supports collections "+"of features: "+element;throw msg;}
+geojson.features[i]=this.extract.feature.apply(this,[element]);}}else if(obj.CLASS_NAME.indexOf("OpenLayers.Geometry")==0){geojson=this.extract.geometry.apply(this,[obj]);}else if(obj instanceof OpenLayers.Feature.Vector){geojson=this.extract.feature.apply(this,[obj]);if(obj.layer&&obj.layer.projection){geojson.crs=this.createCRSObject(obj);}}
+return OpenLayers.Format.JSON.prototype.write.apply(this,[geojson,pretty]);},createCRSObject:function(object){var proj=object.layer.projection.toString();var crs={};if(proj.match(/epsg:/i)){var code=parseInt(proj.substring(proj.indexOf(":")+1));if(code==4326){crs={"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}};}else{crs={"type":"name","properties":{"name":"EPSG:"+code}};}}
+return crs;},extract:{'feature':function(feature){var geom=this.extract.geometry.apply(this,[feature.geometry]);var json={"type":"Feature","properties":feature.attributes,"geometry":geom};if(feature.fid!=null){json.id=feature.fid;}
+return json;},'geometry':function(geometry){if(geometry==null){return null;}
+if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
+var geometryType=geometry.CLASS_NAME.split('.')[2];var data=this.extract[geometryType.toLowerCase()].apply(this,[geometry]);var json;if(geometryType=="Collection"){json={"type":"GeometryCollection","geometries":data};}else{json={"type":geometryType,"coordinates":data};}
+return json;},'point':function(point){return[point.x,point.y];},'multipoint':function(multipoint){var array=[];for(var i=0,len=multipoint.components.length;i<len;++i){array.push(this.extract.point.apply(this,[multipoint.components[i]]));}
+return array;},'linestring':function(linestring){var array=[];for(var i=0,len=linestring.components.length;i<len;++i){array.push(this.extract.point.apply(this,[linestring.components[i]]));}
+return array;},'multilinestring':function(multilinestring){var array=[];for(var i=0,len=multilinestring.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[multilinestring.components[i]]));}
+return array;},'polygon':function(polygon){var array=[];for(var i=0,len=polygon.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[polygon.components[i]]));}
+return array;},'multipolygon':function(multipolygon){var array=[];for(var i=0,len=multipolygon.components.length;i<len;++i){array.push(this.extract.polygon.apply(this,[multipolygon.components[i]]));}
+return array;},'collection':function(collection){var len=collection.components.length;var array=new Array(len);for(var i=0;i<len;++i){array[i]=this.extract.geometry.apply(this,[collection.components[i]]);}
+return array;}},CLASS_NAME:"OpenLayers.Format.GeoJSON"});OpenLayers.Lang["nn"]=OpenLayers.Util.applyDefaults({'Scale = 1 : ${scaleDenom}':"Skala = 1 : ${scaleDenom}"});OpenLayers.Lang["fi"]=OpenLayers.Util.applyDefaults({'Permalink':"Ikilinkki",'Overlays':"Kerrokset",'Base Layer':"Peruskerros",'W':"L",'E':"I",'N':"P",'S':"E"});OpenLayers.Lang["pl"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nieobsługiwane żądanie zwróciło ${statusText}",'Permalink':"Permalink",'Overlays':"Nakładki",'Base Layer':"Warstwa podstawowa",'noFID':"Nie można zaktualizować funkcji, dla których nie ma FID.",'browserNotSupported':"Twoja przeglądarka nie obsługuje renderowania wektorów. Obecnie obsługiwane renderowanie to:\n${renderers}",'minZoomLevelError':"Właściwość minZoomLevel jest przeznaczona tylko do użytku "+"z warstwami FixedZoomLevels-descendent."+"Warstwa wfs, która sprawdza minZoomLevel jest reliktem przeszłości."+"Nie możemy jej jednak usunąc bez mozliwości łamania OL aplikacji, "+"które mogą być od niej zależne. "+"Dlatego jesteśmy za deprecjację -- minZoomLevel "+"zostanie usunięta w wersji 3.0. W zamian prosze użyj "+"min/max rozdzielczości w sposób opisany tutaj: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transakcja WFS: SUKCES ${response}",'commitFailed':"Transakcja WFS: FAILED ${response}",'googleWarning':"Warstwa Google nie był w stanie załadować się poprawnie.<br><br>"+"Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową "+"w przełączniku warstw w górnym prawym rogu mapy.<br><br>"+"Najprawdopodobniej jest to spowodowane tym, że biblioteka Google Maps "+"nie jest załadowana, lub nie zawiera poprawnego klucza do API dla twojej strony<br><br>"+"Programisto: Aby uzyskać pomoc , "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>kliknij tutaj</a>",'getLayerWarning':"Warstwa ${layerType} nie mogła zostać załadowana poprawnie.<br><br>"+"Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową "+"w przełączniku warstw w górnym prawym rogu mapy.<br><br>"+"Najprawdopodobniej jest to spowodowane tym, że biblioteka ${layerLib} "+"nie jest załadowana, lub może(o ile biblioteka tego wymaga) "+"byc potrzebny klucza do API dla twojej strony<br><br>"+"Programisto: Aby uzyskać pomoc , "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>kliknij tutaj</a>",'Scale = 1 : ${scaleDenom}':"Skala = 1 : ${scaleDenom}",'W':'ZACH','E':'WSCH','N':'PN','S':'PD','Graticule':'Siatka','reprojectDeprecated':"w warstwie ${layerName} używasz opcji 'reproject'. "+"Ta opcja jest przestarzała: "+"jej zastosowanie został zaprojektowany, aby wspierać wyświetlania danych przez komercyjne mapy, "+"jednak obecnie ta funkcjonalność powinien zostać osiągnięty za pomocą Spherical Mercator "+"its use was designed to support displaying data over commercial. Więcje informacji na ten temat możesz znaleźć na stronie "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Ta metoda jest przestarzała i będzie usunięta od wersji 3.0. "+"W zamian użyj ${newMethod}.",'proxyNeeded':"Prawdopodobnie musisz ustawić OpenLayers.ProxyHost aby otrzymać dostęp do ${url}."+"See http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost"});OpenLayers.Lang.es={'unhandledRequest':"Respuesta a petición no gestionada ${statusText}",'Permalink':"Enlace permanente",'Overlays':"Capas superpuestas",'Base Layer':"Capa Base",'noFID':"No se puede actualizar un elemento para el que no existe FID.",'browserNotSupported':"Su navegador no soporta renderización vectorial. Los renderizadores soportados actualmente son:\n${renderers}",'minZoomLevelError':"La propiedad minZoomLevel debe sólo utilizarse "+"con las capas que tienen FixedZoomLevels. El hecho de que "+"una capa wfs compruebe minZoomLevel es una reliquia del "+"pasado. Sin embargo, no podemos eliminarla sin discontinuar "+"probablemente las aplicaciones OL que puedan depender de ello. "+"Así pues estamos haciéndolo obsoleto --la comprobación "+"minZoomLevel se eliminará en la versión 3.0. Utilice el ajuste "+"de resolution min/max en su lugar, tal como se describe aquí: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacción WFS: ÉXITO ${response}",'commitFailed':"Transacción WFS: FALLÓ ${response}",'googleWarning':"La capa Google no pudo ser cargada correctamente.<br><br>"+"Para evitar este mensaje, seleccione una nueva Capa Base "+"en el selector de capas en la esquina superior derecha.<br><br>"+"Probablemente, esto se debe a que el script de la biblioteca de "+"Google Maps no fue correctamente incluido en su página, o no "+"contiene la clave del API correcta para su sitio.<br><br>"+"Desarrolladores: Para ayudar a hacer funcionar esto correctamente, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>haga clic aquí</a>",'getLayerWarning':"La capa ${layerType} no pudo ser cargada correctamente.<br><br>"+"Para evitar este mensaje, seleccione una nueva Capa Base "+"en el selector de capas en la esquina superior derecha.<br><br>"+"Probablemente, esto se debe a que el script de "+"la biblioteca ${layerLib} "+"no fue correctamente incluido en su página.<br><br>"+"Desarrolladores: Para ayudar a hacer funcionar esto correctamente, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>haga clic aquí</a>",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':'O','E':'E','N':'N','S':'S','Graticule':'Retícula','reprojectDeprecated':"Está usando la opción 'reproject' en la capa "+"${layerName}. Esta opción es obsoleta: su uso fue diseñado "+"para soportar la visualización de datos sobre mapas base comerciales, "+"pero ahora esa funcionalidad debería conseguirse mediante el soporte "+"de la proyección Spherical Mercator. Más información disponible en "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Este método es obsoleto y se eliminará en la versión 3.0. "+"Por favor utilice el método ${newMethod} en su lugar.",'end':''};OpenLayers.Layer.SphericalMercator={getExtent:function(){var extent=null;if(this.sphericalMercator){extent=this.map.calculateBounds();}else{extent=OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);}
 return extent;},getLonLatFromViewPortPx:function(viewPortPx){return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this,arguments);},getViewPortPxFromLonLat:function(lonlat){return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this,arguments);},initMercatorParameters:function(){this.RESOLUTIONS=[];var maxResolution=156543.03390625;for(var zoom=0;zoom<=this.MAX_ZOOM_LEVEL;++zoom){this.RESOLUTIONS[zoom]=maxResolution/Math.pow(2,zoom);}
-this.units="m";this.projection=this.projection||"EPSG:900913";},forwardMercator:(function(){var gg=new OpenLayers.Projection("EPSG:4326");var sm=new OpenLayers.Projection("EPSG:900913");return function(lon,lat){var point=OpenLayers.Projection.transform({x:lon,y:lat},gg,sm);return new OpenLayers.LonLat(point.x,point.y);};})(),inverseMercator:(function(){var gg=new OpenLayers.Projection("EPSG:4326");var sm=new OpenLayers.Projection("EPSG:900913");return function(x,y){var point=OpenLayers.Projection.transform({x:x,y:y},sm,gg);return new OpenLayers.LonLat(point.x,point.y);};})()};OpenLayers.Lang["hsb"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Wotmołwa njewobdźěłaneho naprašowanja ${statusText}",'Permalink':"Trajny wotkaz",'Overlays':"Naworštowanja",'Base Layer':"Zakładna runina",'noFID':"Funkcija, za kotruž FID njeje, njeda so aktualizować.",'browserNotSupported':"Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}",'minZoomLevelError':"Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transakcija: WUSPĚŠNA ${response}",'commitFailed':"WFS-Transakcija: NJEPORADŹENA ${response}",'googleWarning':"Woršta Google njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'getLayerWarning':"Woršta ${layerType} njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Měritko = 1 : ${scaleDenom}",'W':"Z",'E':"W",'N':"S",'S':"J",'reprojectDeprecated':"Wužiwaš opciju \"reproject\" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.",'methodDeprecated':"Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho."});OpenLayers.Lang["de"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Unbehandelte Anfragerückmeldung ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Grundkarte",'noFID':"Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.",'browserNotSupported':"Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}",'minZoomLevelError':"Die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft ist nur für die Verwendung mit \x3ccode\x3eFixedZoomLevels\x3c/code\x3e-untergeordneten Layers vorgesehen. Das dieser \x3ctt\x3ewfs\x3c/tt\x3e-Layer die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft überprüft ist ein Relikt der Vergangenheit. Wir können diese Überprüfung nicht entfernen, ohne das OL basierende Applikationen nicht mehr funktionieren. Daher markieren wir es als veraltet - die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Überprüfung wird in Version 3.0 entfernt werden. Bitte verwenden Sie stattdessen die Min-/Max-Lösung, wie sie unter http://trac.openlayers.org/wiki/SettingZoomLevels beschrieben ist.",'commitSuccess':"WFS-Transaktion: Erfolgreich ${response}",'commitFailed':"WFS-Transaktion: Fehlgeschlagen ${response}",'googleWarning':"Der Google-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen API-Schlüssel für Ihre URL enthält.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden des Google-Layers",'getLayerWarning':"Der ${layerType}-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der \'${layerLib}\'-Bibliothek nicht eingebunden wurde.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden von Layern",'Scale = 1 : ${scaleDenom}':"Maßstab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Sie verwenden die „Reproject“-Option des Layers ${layerName}. Diese Option ist veraltet: Sie wurde entwickelt um die Anzeige von Daten auf kommerziellen Basiskarten zu unterstützen, aber diese Funktion sollte jetzt durch Unterstützung der „Spherical Mercator“ erreicht werden. Weitere Informationen sind unter http://trac.openlayers.org/wiki/SphericalMercator verfügbar.",'methodDeprecated':"Die Methode ist veraltet und wird in 3.0 entfernt. Bitte verwende stattdessen ${newMethod}."});OpenLayers.ProxyHost="";OpenLayers.Request={DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:true,user:undefined,password:undefined,params:null,proxy:OpenLayers.ProxyHost,headers:{},data:null,callback:function(){},success:null,failure:null,scope:null},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(url,proxy){var sameOrigin=url.indexOf("http")!==0;var urlParts=!sameOrigin&&url.match(this.URL_SPLIT_REGEX);if(urlParts){var location=window.location;sameOrigin=urlParts[1]==location.protocol&&urlParts[3]==location.hostname;var uPort=urlParts[4],lPort=location.port;if(uPort!=80&&uPort!=""||lPort!="80"&&lPort!=""){sameOrigin=sameOrigin&&uPort==lPort;}}
+this.units="m";this.projection=this.projection||"EPSG:900913";},forwardMercator:(function(){var gg=new OpenLayers.Projection("EPSG:4326");var sm=new OpenLayers.Projection("EPSG:900913");return function(lon,lat){var point=OpenLayers.Projection.transform({x:lon,y:lat},gg,sm);return new OpenLayers.LonLat(point.x,point.y);};})(),inverseMercator:(function(){var gg=new OpenLayers.Projection("EPSG:4326");var sm=new OpenLayers.Projection("EPSG:900913");return function(x,y){var point=OpenLayers.Projection.transform({x:x,y:y},sm,gg);return new OpenLayers.LonLat(point.x,point.y);};})()};OpenLayers.Lang["ru"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Необработанный запрос вернул ${statusText}",'Permalink':"Постоянная ссылка",'Overlays':"Слои",'Base Layer':"Основной слой",'noFID':"Невозможно обновить объект, для которого нет FID.",'browserNotSupported':"Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}",'minZoomLevelError':"Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Транзакция WFS: УСПЕШНО ${response}",'commitFailed':"Транзакция WFS: ОШИБКА ${response}",'googleWarning':"Слой Google не удалось нормально загрузить.\x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'getLayerWarning':"Слой ${layerType} не удалось нормально загрузить. \x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Масштаб = 1 : ${scaleDenom}",'W':"З",'E':"В",'N':"С",'S':"Ю",'reprojectDeprecated':"Вы используете опцию \'reproject\' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}."});OpenLayers.Lang["hsb"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Wotmołwa njewobdźěłaneho naprašowanja ${statusText}",'Permalink':"Trajny wotkaz",'Overlays':"Naworštowanja",'Base Layer':"Zakładna runina",'noFID':"Funkcija, za kotruž FID njeje, njeda so aktualizować.",'browserNotSupported':"Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}",'minZoomLevelError':"Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transakcija: WUSPĚŠNA ${response}",'commitFailed':"WFS-Transakcija: NJEPORADŹENA ${response}",'googleWarning':"Woršta Google njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'getLayerWarning':"Woršta ${layerType} njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Měritko = 1 : ${scaleDenom}",'W':"Z",'E':"W",'N':"S",'S':"J",'reprojectDeprecated':"Wužiwaš opciju \"reproject\" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.",'methodDeprecated':"Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho."});OpenLayers.Lang["de"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Unbehandelte Anfragerückmeldung ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Grundkarte",'noFID':"Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.",'browserNotSupported':"Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}",'minZoomLevelError':"Die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft ist nur für die Verwendung mit \x3ccode\x3eFixedZoomLevels\x3c/code\x3e-untergeordneten Layers vorgesehen. Das dieser \x3ctt\x3ewfs\x3c/tt\x3e-Layer die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft überprüft ist ein Relikt der Vergangenheit. Wir können diese Überprüfung nicht entfernen, ohne das OL basierende Applikationen nicht mehr funktionieren. Daher markieren wir es als veraltet - die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Überprüfung wird in Version 3.0 entfernt werden. Bitte verwenden Sie stattdessen die Min-/Max-Lösung, wie sie unter http://trac.openlayers.org/wiki/SettingZoomLevels beschrieben ist.",'commitSuccess':"WFS-Transaktion: Erfolgreich ${response}",'commitFailed':"WFS-Transaktion: Fehlgeschlagen ${response}",'googleWarning':"Der Google-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen API-Schlüssel für Ihre URL enthält.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden des Google-Layers",'getLayerWarning':"Der ${layerType}-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der \'${layerLib}\'-Bibliothek nicht eingebunden wurde.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden von Layern",'Scale = 1 : ${scaleDenom}':"Maßstab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Sie verwenden die „Reproject“-Option des Layers ${layerName}. Diese Option ist veraltet: Sie wurde entwickelt um die Anzeige von Daten auf kommerziellen Basiskarten zu unterstützen, aber diese Funktion sollte jetzt durch Unterstützung der „Spherical Mercator“ erreicht werden. Weitere Informationen sind unter http://trac.openlayers.org/wiki/SphericalMercator verfügbar.",'methodDeprecated':"Die Methode ist veraltet und wird in 3.0 entfernt. Bitte verwende stattdessen ${newMethod}."});OpenLayers.ProxyHost="";OpenLayers.Request={DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:true,user:undefined,password:undefined,params:null,proxy:OpenLayers.ProxyHost,headers:{},data:null,callback:function(){},success:null,failure:null,scope:null},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(url,proxy){var sameOrigin=url.indexOf("http")!==0;var urlParts=!sameOrigin&&url.match(this.URL_SPLIT_REGEX);if(urlParts){var location=window.location;sameOrigin=urlParts[1]==location.protocol&&urlParts[3]==location.hostname;var uPort=urlParts[4],lPort=location.port;if(uPort!=80&&uPort!=""||lPort!="80"&&lPort!=""){sameOrigin=sameOrigin&&uPort==lPort;}}
 if(!sameOrigin){if(proxy){if(typeof proxy=="function"){url=proxy(url);}else{url=proxy+encodeURIComponent(url);}}else{OpenLayers.Console.warn(OpenLayers.i18n("proxyNeeded"),{url:url});}}
 return url;},issue:function(config){var defaultConfig=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});config=OpenLayers.Util.applyDefaults(config,defaultConfig);var customRequestedWithHeader=false,headerKey;for(headerKey in config.headers){if(config.headers.hasOwnProperty(headerKey)){if(headerKey.toLowerCase()==='x-requested-with'){customRequestedWithHeader=true;}}}
 if(customRequestedWithHeader===false){config.headers['X-Requested-With']='XMLHttpRequest';}
@@ -1169,7 +1272,19 @@ return true;},touchend:function(evt){if(this.started){this.started=false;this.pi
 return true;},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.pinching=false;activated=true;}
 return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.started=false;this.pinching=false;this.start=null;this.last=null;deactivated=true;}
 return deactivated;},getDistance:function(touches){var t0=touches[0];var t1=touches[1];return Math.sqrt(Math.pow(t0.clientX-t1.clientX,2)+
-Math.pow(t0.clientY-t1.clientY,2));},getPinchData:function(evt){var distance=this.getDistance(evt.touches);var scale=distance/this.start.distance;return{distance:distance,delta:this.last.distance-distance,scale:scale};},CLASS_NAME:"OpenLayers.Handler.Pinch"});OpenLayers.Lang['lt']=OpenLayers.Util.applyDefaults({'unhandledRequest':"Neapdorota užklausa gražino ${statusText}",'Permalink':"Pastovi nuoroda",'Overlays':"Papildomi sluoksniai",'Base Layer':"Pagrindinis sluoksnis",'noFID':"Negaliu atnaujinti objekto, kuris neturi FID.",'browserNotSupported':"Jūsų naršyklė nemoka parodyti vektorių. Šiuo metu galima naudotis tokiais rodymo varikliais:\n{renderers}",'commitSuccess':"WFS Tranzakcija: PAVYKO ${response}",'commitFailed':"WFS Tranzakcija: ŽLUGO ${response}",'Scale = 1 : ${scaleDenom}':"Mastelis = 1 : ${scaleDenom}",'W':'V','E':'R','N':'Š','S':'P','Graticule':'Tinklelis','methodDeprecated':"Šis metodas yra pasenęs ir 3.0 versijoje bus pašalintas. "+"Prašome naudoti ${newMethod}.",'end':''});OpenLayers.Lang.ca={'unhandledRequest':"Resposta a petició no gestionada ${statusText}",'Permalink':"Enllaç permanent",'Overlays':"Capes addicionals",'Base Layer':"Capa Base",'noFID':"No es pot actualitzar un element per al que no existeix FID.",'browserNotSupported':"El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualment són:\n${renderers}",'minZoomLevelError':"La propietat minZoomLevel s'ha d'utilitzar només "+"amb les capes que tenen FixedZoomLevels. El fet que "+"una capa wfs comprovi minZoomLevel és una relíquia del "+"passat. No podem, però, eliminar-la sense trencar "+"les aplicacions d'OpenLayers que en puguin dependre. "+"Així doncs estem fent-la obsoleta -- la comprovació "+"minZoomLevel s'eliminarà a la versió 3.0. Feu servir "+"els paràmetres min/max resolution en substitució, tal com es descriu aquí: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacció WFS: CORRECTA ${response}",'commitFailed':"Transacció WFS: HA FALLAT ${response}",'googleWarning':"La capa Google no s'ha pogut carregar correctament.<br><br>"+"Per evitar aquest missatge, seleccioneu una nova Capa Base "+"al gestor de capes de la cantonada superior dreta.<br><br>"+"Probablement això és degut a que l'script de la biblioteca de "+"Google Maps no ha estat inclòs a la vostra pàgina, o no "+"conté la clau de l'API correcta per a la vostra adreça.<br><br>"+"Desenvolupadors: Per obtenir consells sobre com fer anar això, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>féu clic aquí</a>",'getLayerWarning':"Per evitar aquest missatge, seleccioneu una nova Capa Base "+"al gestor de capes de la cantonada superior dreta.<br><br>"+"Probablement això és degut a que l'script de la biblioteca "+"${layerLib} "+"no ha estat inclòs a la vostra pàgina.<br><br>"+"Desenvolupadors: Per obtenir consells sobre com fer anar això, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>féu clic aquí</a>",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':'O','E':'E','N':'N','S':'S','Graticule':'Retícula','reprojectDeprecated':"Esteu fent servir l'opció 'reproject' a la capa "+"${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut "+"per suportar la visualització de dades sobre mapes base comercials, "+"però ara aquesta funcionalitat s'hauria d'assolir mitjançant el suport "+"de la projecció Spherical Mercator. Més informació disponible a "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Aquest mètode és obsolet i s'eliminarà a la versió 3.0. "+"Si us plau feu servir em mètode alternatiu ${newMethod}.",'end':''};OpenLayers.Lang["id"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Permintaan yang tak tertangani menghasilkan ${statusText}",'Permalink':"Pranala permanen",'Overlays':"Hamparan",'Base Layer':"Lapisan Dasar",'noFID':"Tidak dapat memperbarui fitur yang tidak memiliki FID.",'browserNotSupported':"Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}",'minZoomLevelError':"Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaksi: BERHASIL ${respon}",'commitFailed':"WFS Transaksi: GAGAL ${respon}",'googleWarning':"Lapisan Google tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'getLayerWarning':"Lapisan ${layerType} tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Sekala = 1 : ${scaleDenom}",'W':"B",'E':"T",'N':"U",'S':"S",'reprojectDeprecated':"Anda menggunakan opsi \'reproject\' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}."});OpenLayers.Lang["km"]=OpenLayers.Util.applyDefaults({'Permalink':"តំណភ្ជាប់អចិន្ត្រៃយ៍",'Base Layer':"ស្រទាប់បាត​",'Scale = 1 : ${scaleDenom}':"មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}"});OpenLayers.Lang["nl"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Het verzoek is niet afgehandeld met de volgende melding: ${statusText}",'Permalink':"Permanente verwijzing",'Overlays':"Overlays",'Base Layer':"Achtergrondkaart",'noFID':"Een optie die geen FID heeft kan niet bijgewerkt worden.",'browserNotSupported':"Uw browser ondersteunt het weergeven van vectoren niet.\nMomenteel ondersteunde weergavemogelijkheden:\n${renderers}",'minZoomLevelError':"De eigenschap minZoomLevel is alleen bedoeld voor gebruik lagen met die afstammen van FixedZoomLevels-lagen.\nDat deze WFS-laag minZoomLevel controleert, is een overblijfsel uit het verleden.\nWe kunnen deze controle echter niet verwijderen zonder op OL gebaseerde applicaties die hervan afhankelijk zijn stuk te maken.\nDaarom heeft deze functionaliteit de eigenschap \'deprecated\' gekregen - de minZoomLevel wordt verwijderd in versie 3.0.\nGebruik in plaats van deze functie de mogelijkheid om min/max voor resolutie in te stellen zoals op de volgende pagina wordt beschreven:\nhttp://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-transactie: succesvol ${response}",'commitFailed':"WFS-transactie: mislukt ${response}",'googleWarning':"De Google-Layer kon niet correct geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct ingevoegd is.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.",'getLayerWarning':"De laag ${layerType} kon niet goed geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct is ingevoegd.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.",'Scale = 1 : ${scaleDenom}':"Schaal = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"Z",'reprojectDeprecated':"U gebruikt de optie \'reproject\' op de laag ${layerName}.\nDeze optie is vervallen: deze optie was ontwikkeld om gegevens over commerciële basiskaarten weer te geven, maar deze functionaliteit wordt nu bereikt door ondersteuning van Spherical Mercator.\nMeer informatie is beschikbaar op http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Deze methode is verouderd en wordt verwijderd in versie 3.0.\nGebruik ${newMethod}."});OpenLayers.Lang["fr"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Requête non gérée, retournant ${statusText}",'Permalink':"Permalien",'Overlays':"Calques",'Base Layer':"Calque de base",'noFID':"Impossible de mettre à jour un objet sans identifiant (fid).",'browserNotSupported':"Votre navigateur ne supporte pas le rendu vectoriel. Les renderers actuellement supportés sont : \n${renderers}",'minZoomLevelError':"La propriété minZoomLevel doit seulement être utilisée pour des couches FixedZoomLevels-descendent. Le fait que cette couche WFS vérifie la présence de minZoomLevel est une relique du passé. Nous ne pouvons toutefois la supprimer sans casser des applications qui pourraient en dépendre. C\'est pourquoi nous la déprécions -- la vérification du minZoomLevel sera supprimée en version 3.0. A la place, merci d\'utiliser les paramètres de résolutions min/max tel que décrit sur : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaction WFS : SUCCES ${response}",'commitFailed':"Transaction WFS : ECHEC ${response}",'googleWarning':"La couche Google n\'a pas été en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie Google Maps, ou alors parce que la clé de l\'API ne correspond pas à votre site.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e",'getLayerWarning':"La couche ${layerType} n\'est pas en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie ${layerLib}.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Echelle ~ 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S",'reprojectDeprecated':"Vous utilisez l\'option \'reproject\' sur la couche ${layerName}. Cette option est dépréciée : Son usage permettait d\'afficher des données au dessus de couches raster commerciales.Cette fonctionalité est maintenant supportée en utilisant le support de la projection Mercator Sphérique. Plus d\'information est disponible sur http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Cette méthode est dépréciée, et sera supprimée à la version 3.0. Merci d\'utiliser ${newMethod} à la place.",'proxyNeeded':"Vous avez très probablement besoin de renseigner OpenLayers.ProxyHost pour accéder à ${url}. Voir http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost"});OpenLayers.Lang["ksh"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}",'Permalink':"Lengk op Duuer",'Overlays':"Drövver jelaat",'Base Layer':"Jrund-Nivoh",'noFID':"En Saach, woh kein \x3ci lang=\"en\"\x3eFID\x3c/i\x3e för doh es, löht sesch nit ändere.",'browserNotSupported':"Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}",'minZoomLevelError':"De Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun \x3ccode lang=\"en\"\x3eFixedZoomLevels\x3c/code\x3e affhange don. Dat dat \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Nivvoh övverhoup de Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.",'commitSuccess':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es joot jeloufe: ${response}",'commitFailed':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es scheif jejange: ${response}",'googleWarning':"Dat Nivvoh \x3ccode lang=\"en\"\x3eGoogle\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat wiel dat \x3ci lang=\"en\"\x3eGoogle-Maps\x3c/i\x3e-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje \x3ci lang=\"en\"\x3eAPI\x3c/i\x3e-Schlößel för Ding Web-ßait scheke deiht.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/Google\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'getLayerWarning':"Dat Nivvoh \x3ccode\x3e${layerType}\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat, wiel dat Skrepp \x3ccode\x3e${layerLib}\x3c/code\x3e nit reschtesch enjebonge wood.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_Et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/${layerLib}\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'Scale = 1 : ${scaleDenom}':"Mohßshtaab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Do bruchs de Ußwahl \x3ccode\x3ereproject\x3c/code\x3e op däm Nivvoh \x3ccode\x3e${layerName}\x3c/code\x3e. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm \x3ccode\x3e${newMethod}\x3c/code\x3e doföör."});OpenLayers.Lang["fur"]=OpenLayers.Util.applyDefaults({'Permalink':"Leam Permanent",'Overlays':"Livei parsore",'Base Layer':"Livel di base",'browserNotSupported':"Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}",'Scale = 1 : ${scaleDenom}':"Scjale = 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S"});OpenLayers.Lang["ja"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"未処理の要求は ${statusText} を返します",'Permalink':"パーマリンク",'Overlays':"オーバーレイ",'Base Layer':"基底レイヤー",'noFID':"FID のない地物は更新できません。",'browserNotSupported':"あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}",'minZoomLevelError':"minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。",'commitSuccess':"WFS トランザクション: 成功 ${response}",'commitFailed':"WFS トランザクション: 失敗 ${response}",'googleWarning':"Google レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'getLayerWarning':"${layerType} レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'Scale = 1 : ${scaleDenom}':"縮尺 = 1 : ${scaleDenom}",'W':"西",'E':"東",'N':"北",'S':"南",'reprojectDeprecated':"あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。",'methodDeprecated':"このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。"});(function(){var oXMLHttpRequest=window.XMLHttpRequest;var bGecko=!!window.controllers,bIE=window.document.all&&!window.opera,bIE7=bIE&&window.navigator.userAgent.match(/MSIE 7.0/);function fXMLHttpRequest(){this._object=oXMLHttpRequest&&!bIE7?new oXMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[];};function cXMLHttpRequest(){return new fXMLHttpRequest;};cXMLHttpRequest.prototype=fXMLHttpRequest.prototype;if(bGecko&&oXMLHttpRequest.wrapped)
+Math.pow(t0.clientY-t1.clientY,2));},getPinchData:function(evt){var distance=this.getDistance(evt.touches);var scale=distance/this.start.distance;return{distance:distance,delta:this.last.distance-distance,scale:scale};},CLASS_NAME:"OpenLayers.Handler.Pinch"});OpenLayers.Lang['lt']=OpenLayers.Util.applyDefaults({'unhandledRequest':"Neapdorota užklausa gražino ${statusText}",'Permalink':"Pastovi nuoroda",'Overlays':"Papildomi sluoksniai",'Base Layer':"Pagrindinis sluoksnis",'noFID':"Negaliu atnaujinti objekto, kuris neturi FID.",'browserNotSupported':"Jūsų naršyklė nemoka parodyti vektorių. Šiuo metu galima naudotis tokiais rodymo varikliais:\n{renderers}",'commitSuccess':"WFS Tranzakcija: PAVYKO ${response}",'commitFailed':"WFS Tranzakcija: ŽLUGO ${response}",'Scale = 1 : ${scaleDenom}':"Mastelis = 1 : ${scaleDenom}",'W':'V','E':'R','N':'Š','S':'P','Graticule':'Tinklelis','methodDeprecated':"Šis metodas yra pasenęs ir 3.0 versijoje bus pašalintas. "+"Prašome naudoti ${newMethod}.",'end':''});OpenLayers.Lang.ca={'unhandledRequest':"Resposta a petició no gestionada ${statusText}",'Permalink':"Enllaç permanent",'Overlays':"Capes addicionals",'Base Layer':"Capa Base",'noFID':"No es pot actualitzar un element per al que no existeix FID.",'browserNotSupported':"El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualment són:\n${renderers}",'minZoomLevelError':"La propietat minZoomLevel s'ha d'utilitzar només "+"amb les capes que tenen FixedZoomLevels. El fet que "+"una capa wfs comprovi minZoomLevel és una relíquia del "+"passat. No podem, però, eliminar-la sense trencar "+"les aplicacions d'OpenLayers que en puguin dependre. "+"Així doncs estem fent-la obsoleta -- la comprovació "+"minZoomLevel s'eliminarà a la versió 3.0. Feu servir "+"els paràmetres min/max resolution en substitució, tal com es descriu aquí: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacció WFS: CORRECTA ${response}",'commitFailed':"Transacció WFS: HA FALLAT ${response}",'googleWarning':"La capa Google no s'ha pogut carregar correctament.<br><br>"+"Per evitar aquest missatge, seleccioneu una nova Capa Base "+"al gestor de capes de la cantonada superior dreta.<br><br>"+"Probablement això és degut a que l'script de la biblioteca de "+"Google Maps no ha estat inclòs a la vostra pàgina, o no "+"conté la clau de l'API correcta per a la vostra adreça.<br><br>"+"Desenvolupadors: Per obtenir consells sobre com fer anar això, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>féu clic aquí</a>",'getLayerWarning':"Per evitar aquest missatge, seleccioneu una nova Capa Base "+"al gestor de capes de la cantonada superior dreta.<br><br>"+"Probablement això és degut a que l'script de la biblioteca "+"${layerLib} "+"no ha estat inclòs a la vostra pàgina.<br><br>"+"Desenvolupadors: Per obtenir consells sobre com fer anar això, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>féu clic aquí</a>",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':'O','E':'E','N':'N','S':'S','Graticule':'Retícula','reprojectDeprecated':"Esteu fent servir l'opció 'reproject' a la capa "+"${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut "+"per suportar la visualització de dades sobre mapes base comercials, "+"però ara aquesta funcionalitat s'hauria d'assolir mitjançant el suport "+"de la projecció Spherical Mercator. Més informació disponible a "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Aquest mètode és obsolet i s'eliminarà a la versió 3.0. "+"Si us plau feu servir em mètode alternatiu ${newMethod}.",'end':''};OpenLayers.Lang["id"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Permintaan yang tak tertangani menghasilkan ${statusText}",'Permalink':"Pranala permanen",'Overlays':"Hamparan",'Base Layer':"Lapisan Dasar",'noFID':"Tidak dapat memperbarui fitur yang tidak memiliki FID.",'browserNotSupported':"Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}",'minZoomLevelError':"Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaksi: BERHASIL ${respon}",'commitFailed':"WFS Transaksi: GAGAL ${respon}",'googleWarning':"Lapisan Google tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'getLayerWarning':"Lapisan ${layerType} tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Sekala = 1 : ${scaleDenom}",'W':"B",'E':"T",'N':"U",'S':"S",'reprojectDeprecated':"Anda menggunakan opsi \'reproject\' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}."});OpenLayers.Filter.Comparison=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,matchCase:true,lowerBoundary:null,upperBoundary:null,initialize:function(options){OpenLayers.Filter.prototype.initialize.apply(this,[options]);if(this.type===OpenLayers.Filter.Comparison.LIKE&&options.matchCase===undefined){this.matchCase=null;}},evaluate:function(context){if(context instanceof OpenLayers.Feature.Vector){context=context.attributes;}
+var result=false;var got=context[this.property];var exp;switch(this.type){case OpenLayers.Filter.Comparison.EQUAL_TO:exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()==exp.toUpperCase());}else{result=(got==exp);}
+break;case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()!=exp.toUpperCase());}else{result=(got!=exp);}
+break;case OpenLayers.Filter.Comparison.LESS_THAN:result=got<this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN:result=got>this.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:result=got<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:result=got>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:result=(got>=this.lowerBoundary)&&(got<=this.upperBoundary);break;case OpenLayers.Filter.Comparison.LIKE:var regexp=new RegExp(this.value,"gi");result=regexp.test(got);break;}
+return result;},value2regex:function(wildCard,singleChar,escapeChar){if(wildCard=="."){throw new Error("'.' is an unsupported wildCard character for "+"OpenLayers.Filter.Comparison");}
+wildCard=wildCard?wildCard:"*";singleChar=singleChar?singleChar:".";escapeChar=escapeChar?escapeChar:"!";this.value=this.value.replace(new RegExp("\\"+escapeChar+"(.|$)","g"),"\\$1");this.value=this.value.replace(new RegExp("\\"+singleChar,"g"),".");this.value=this.value.replace(new RegExp("\\"+wildCard,"g"),".*");this.value=this.value.replace(new RegExp("\\\\.\\*","g"),"\\"+wildCard);this.value=this.value.replace(new RegExp("\\\\\\.","g"),"\\"+singleChar);return this.value;},regex2value:function(){var value=this.value;value=value.replace(/!/g,"!!");value=value.replace(/(\\)?\\\./g,function($0,$1){return $1?$0:"!.";});value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"!*";});value=value.replace(/\\\\/g,"\\");value=value.replace(/\.\*/g,"*");return value;},clone:function(){return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(),this);},CLASS_NAME:"OpenLayers.Filter.Comparison"});OpenLayers.Filter.Comparison.EQUAL_TO="==";OpenLayers.Filter.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Filter.Comparison.LESS_THAN="<";OpenLayers.Filter.Comparison.GREATER_THAN=">";OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Filter.Comparison.BETWEEN="..";OpenLayers.Filter.Comparison.LIKE="~";OpenLayers.Format.QueryStringFilter=(function(){var cmpToStr={};cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO]="eq";cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO]="ne";cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN]="lt";cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO]="lte";cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN]="gt";cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO]="gte";cmpToStr[OpenLayers.Filter.Comparison.LIKE]="ilike";function regex2value(value){value=value.replace(/%/g,"\\%");value=value.replace(/\\\\\.(\*)?/g,function($0,$1){return $1?$0:"\\\\_";});value=value.replace(/\\\\\.\*/g,"\\\\%");value=value.replace(/(\\)?\.(\*)?/g,function($0,$1,$2){return $1||$2?$0:"_";});value=value.replace(/(\\)?\.\*/g,function($0,$1){return $1?$0:"%";});value=value.replace(/\\\./g,".");value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"*";});return value;}
+return OpenLayers.Class(OpenLayers.Format,{wildcarded:false,srsInBBOX:false,write:function(filter,params){params=params||{};var className=filter.CLASS_NAME;var filterType=className.substring(className.lastIndexOf(".")+1);switch(filterType){case"Spatial":switch(filter.type){case OpenLayers.Filter.Spatial.BBOX:params.bbox=filter.value.toArray();if(this.srsInBBOX&&filter.projection){params.bbox.push(filter.projection.getCode());}
+break;case OpenLayers.Filter.Spatial.DWITHIN:params.tolerance=filter.distance;case OpenLayers.Filter.Spatial.WITHIN:params.lon=filter.value.x;params.lat=filter.value.y;break;default:OpenLayers.Console.warn("Unknown spatial filter type "+filter.type);}
+break;case"Comparison":var op=cmpToStr[filter.type];if(op!==undefined){var value=filter.value;if(filter.type==OpenLayers.Filter.Comparison.LIKE){value=regex2value(value);if(this.wildcarded){value="%"+value+"%";}}
+params[filter.property+"__"+op]=value;params.queryable=params.queryable||[];params.queryable.push(filter.property);}else{OpenLayers.Console.warn("Unknown comparison filter type "+filter.type);}
+break;case"Logical":if(filter.type===OpenLayers.Filter.Logical.AND){for(var i=0,len=filter.filters.length;i<len;i++){params=this.write(filter.filters[i],params);}}else{OpenLayers.Console.warn("Unsupported logical filter type "+filter.type);}
+break;default:OpenLayers.Console.warn("Unknown filter type "+filterType);}
+return params;},CLASS_NAME:"OpenLayers.Format.QueryStringFilter"});})();OpenLayers.Lang["km"]=OpenLayers.Util.applyDefaults({'Permalink':"តំណភ្ជាប់អចិន្ត្រៃយ៍",'Base Layer':"ស្រទាប់បាត​",'Scale = 1 : ${scaleDenom}':"មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}"});OpenLayers.Lang["nl"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Het verzoek is niet afgehandeld met de volgende melding: ${statusText}",'Permalink':"Permanente verwijzing",'Overlays':"Overlays",'Base Layer':"Achtergrondkaart",'noFID':"Een optie die geen FID heeft kan niet bijgewerkt worden.",'browserNotSupported':"Uw browser ondersteunt het weergeven van vectoren niet.\nMomenteel ondersteunde weergavemogelijkheden:\n${renderers}",'minZoomLevelError':"De eigenschap minZoomLevel is alleen bedoeld voor gebruik lagen met die afstammen van FixedZoomLevels-lagen.\nDat deze WFS-laag minZoomLevel controleert, is een overblijfsel uit het verleden.\nWe kunnen deze controle echter niet verwijderen zonder op OL gebaseerde applicaties die hervan afhankelijk zijn stuk te maken.\nDaarom heeft deze functionaliteit de eigenschap \'deprecated\' gekregen - de minZoomLevel wordt verwijderd in versie 3.0.\nGebruik in plaats van deze functie de mogelijkheid om min/max voor resolutie in te stellen zoals op de volgende pagina wordt beschreven:\nhttp://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-transactie: succesvol ${response}",'commitFailed':"WFS-transactie: mislukt ${response}",'googleWarning':"De Google-Layer kon niet correct geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct ingevoegd is.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.",'getLayerWarning':"De laag ${layerType} kon niet goed geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct is ingevoegd.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.",'Scale = 1 : ${scaleDenom}':"Schaal = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"Z",'reprojectDeprecated':"U gebruikt de optie \'reproject\' op de laag ${layerName}.\nDeze optie is vervallen: deze optie was ontwikkeld om gegevens over commerciële basiskaarten weer te geven, maar deze functionaliteit wordt nu bereikt door ondersteuning van Spherical Mercator.\nMeer informatie is beschikbaar op http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Deze methode is verouderd en wordt verwijderd in versie 3.0.\nGebruik ${newMethod}."});OpenLayers.Lang["fr"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Requête non gérée, retournant ${statusText}",'Permalink':"Permalien",'Overlays':"Calques",'Base Layer':"Calque de base",'noFID':"Impossible de mettre à jour un objet sans identifiant (fid).",'browserNotSupported':"Votre navigateur ne supporte pas le rendu vectoriel. Les renderers actuellement supportés sont : \n${renderers}",'minZoomLevelError':"La propriété minZoomLevel doit seulement être utilisée pour des couches FixedZoomLevels-descendent. Le fait que cette couche WFS vérifie la présence de minZoomLevel est une relique du passé. Nous ne pouvons toutefois la supprimer sans casser des applications qui pourraient en dépendre. C\'est pourquoi nous la déprécions -- la vérification du minZoomLevel sera supprimée en version 3.0. A la place, merci d\'utiliser les paramètres de résolutions min/max tel que décrit sur : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaction WFS : SUCCES ${response}",'commitFailed':"Transaction WFS : ECHEC ${response}",'googleWarning':"La couche Google n\'a pas été en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie Google Maps, ou alors parce que la clé de l\'API ne correspond pas à votre site.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e",'getLayerWarning':"La couche ${layerType} n\'est pas en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie ${layerLib}.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Echelle ~ 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S",'reprojectDeprecated':"Vous utilisez l\'option \'reproject\' sur la couche ${layerName}. Cette option est dépréciée : Son usage permettait d\'afficher des données au dessus de couches raster commerciales.Cette fonctionalité est maintenant supportée en utilisant le support de la projection Mercator Sphérique. Plus d\'information est disponible sur http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Cette méthode est dépréciée, et sera supprimée à la version 3.0. Merci d\'utiliser ${newMethod} à la place.",'proxyNeeded':"Vous avez très probablement besoin de renseigner OpenLayers.ProxyHost pour accéder à ${url}. Voir http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost"});OpenLayers.Lang["ksh"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}",'Permalink':"Lengk op Duuer",'Overlays':"Drövver jelaat",'Base Layer':"Jrund-Nivoh",'noFID':"En Saach, woh kein \x3ci lang=\"en\"\x3eFID\x3c/i\x3e för doh es, löht sesch nit ändere.",'browserNotSupported':"Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}",'minZoomLevelError':"De Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun \x3ccode lang=\"en\"\x3eFixedZoomLevels\x3c/code\x3e affhange don. Dat dat \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Nivvoh övverhoup de Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.",'commitSuccess':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es joot jeloufe: ${response}",'commitFailed':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es scheif jejange: ${response}",'googleWarning':"Dat Nivvoh \x3ccode lang=\"en\"\x3eGoogle\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat wiel dat \x3ci lang=\"en\"\x3eGoogle-Maps\x3c/i\x3e-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje \x3ci lang=\"en\"\x3eAPI\x3c/i\x3e-Schlößel för Ding Web-ßait scheke deiht.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/Google\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'getLayerWarning':"Dat Nivvoh \x3ccode\x3e${layerType}\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat, wiel dat Skrepp \x3ccode\x3e${layerLib}\x3c/code\x3e nit reschtesch enjebonge wood.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_Et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/${layerLib}\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'Scale = 1 : ${scaleDenom}':"Mohßshtaab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Do bruchs de Ußwahl \x3ccode\x3ereproject\x3c/code\x3e op däm Nivvoh \x3ccode\x3e${layerName}\x3c/code\x3e. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm \x3ccode\x3e${newMethod}\x3c/code\x3e doföör."});OpenLayers.Lang["fur"]=OpenLayers.Util.applyDefaults({'Permalink':"Leam Permanent",'Overlays':"Livei parsore",'Base Layer':"Livel di base",'browserNotSupported':"Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}",'Scale = 1 : ${scaleDenom}':"Scjale = 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S"});OpenLayers.Lang["ja"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"未処理の要求は ${statusText} を返します",'Permalink':"パーマリンク",'Overlays':"オーバーレイ",'Base Layer':"基底レイヤー",'noFID':"FID のない地物は更新できません。",'browserNotSupported':"あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}",'minZoomLevelError':"minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。",'commitSuccess':"WFS トランザクション: 成功 ${response}",'commitFailed':"WFS トランザクション: 失敗 ${response}",'googleWarning':"Google レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'getLayerWarning':"${layerType} レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'Scale = 1 : ${scaleDenom}':"縮尺 = 1 : ${scaleDenom}",'W':"西",'E':"東",'N':"北",'S':"南",'reprojectDeprecated':"あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。",'methodDeprecated':"このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。"});(function(){var oXMLHttpRequest=window.XMLHttpRequest;var bGecko=!!window.controllers,bIE=window.document.all&&!window.opera,bIE7=bIE&&window.navigator.userAgent.match(/MSIE 7.0/);function fXMLHttpRequest(){this._object=oXMLHttpRequest&&!bIE7?new oXMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[];};function cXMLHttpRequest(){return new fXMLHttpRequest;};cXMLHttpRequest.prototype=fXMLHttpRequest.prototype;if(bGecko&&oXMLHttpRequest.wrapped)
 cXMLHttpRequest.wrapped=oXMLHttpRequest.wrapped;cXMLHttpRequest.UNSENT=0;cXMLHttpRequest.OPENED=1;cXMLHttpRequest.HEADERS_RECEIVED=2;cXMLHttpRequest.LOADING=3;cXMLHttpRequest.DONE=4;cXMLHttpRequest.prototype.readyState=cXMLHttpRequest.UNSENT;cXMLHttpRequest.prototype.responseText='';cXMLHttpRequest.prototype.responseXML=null;cXMLHttpRequest.prototype.status=0;cXMLHttpRequest.prototype.statusText='';cXMLHttpRequest.prototype.priority="NORMAL";cXMLHttpRequest.prototype.onreadystatechange=null;cXMLHttpRequest.onreadystatechange=null;cXMLHttpRequest.onopen=null;cXMLHttpRequest.onsend=null;cXMLHttpRequest.onabort=null;cXMLHttpRequest.prototype.open=function(sMethod,sUrl,bAsync,sUser,sPassword){delete this._headers;if(arguments.length<3)
 bAsync=true;this._async=bAsync;var oRequest=this,nState=this.readyState,fOnUnload;if(bIE&&bAsync){fOnUnload=function(){if(nState!=cXMLHttpRequest.DONE){fCleanTransport(oRequest);oRequest.abort();}};window.attachEvent("onunload",fOnUnload);}
 if(cXMLHttpRequest.onopen)
@@ -1206,7 +1321,20 @@ return null;return oDocument;};function fSynchronizeValues(oRequest){try{oReques
 try{oRequest.responseXML=fGetDocument(oRequest._object);}catch(e){}
 try{oRequest.status=oRequest._object.status;}catch(e){}
 try{oRequest.statusText=oRequest._object.statusText;}catch(e){}};function fCleanTransport(oRequest){oRequest._object.onreadystatechange=new window.Function;};if(!window.Function.prototype.apply){window.Function.prototype.apply=function(oRequest,oArguments){if(!oArguments)
-oArguments=[];oRequest.__func=this;oRequest.__func(oArguments[0],oArguments[1],oArguments[2],oArguments[3],oArguments[4]);delete oRequest.__func;};};OpenLayers.Request.XMLHttpRequest=cXMLHttpRequest;})();OpenLayers.Lang["nds"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Unbehannelt Trüchmellels för de Anfraag ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Achtergrundkoort",'noFID':"En Feature, dat keen FID hett, kann nich aktuell maakt warrn.",'browserNotSupported':"Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}",'commitSuccess':"WFS-Transakschoon: hett klappt ${response}",'commitFailed':"WFS-Transakschoon: hett nich klappt ${response}",'Scale = 1 : ${scaleDenom}':"Skaal = 1 : ${scaleDenom}",'methodDeprecated':"Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för."});OpenLayers.Renderer.VML=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"urn:schemas-microsoft-com:vml",symbolCache:{},offset:null,initialize:function(containerID){if(!this.supported()){return;}
+oArguments=[];oRequest.__func=this;oRequest.__func(oArguments[0],oArguments[1],oArguments[2],oArguments[3],oArguments[4]);delete oRequest.__func;};};OpenLayers.Request.XMLHttpRequest=cXMLHttpRequest;})();OpenLayers.Lang["nds"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Unbehannelt Trüchmellels för de Anfraag ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Achtergrundkoort",'noFID':"En Feature, dat keen FID hett, kann nich aktuell maakt warrn.",'browserNotSupported':"Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}",'commitSuccess':"WFS-Transakschoon: hett klappt ${response}",'commitFailed':"WFS-Transakschoon: hett nich klappt ${response}",'Scale = 1 : ${scaleDenom}':"Skaal = 1 : ${scaleDenom}",'methodDeprecated':"Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för."});OpenLayers.Handler.RegularPolygon=OpenLayers.Class(OpenLayers.Handler.Drag,{sides:4,radius:null,snapAngle:null,snapToggle:'shiftKey',layerOptions:null,persist:false,irregular:false,citeCompliant:false,angle:null,fixedRadius:false,feature:null,layer:null,origin:null,initialize:function(control,callbacks,options){if(!(options&&options.layerOptions&&options.layerOptions.styleMap)){this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'],{});}
+OpenLayers.Handler.Drag.prototype.initialize.apply(this,[control,callbacks,options]);this.options=(options)?options:{};},setOptions:function(newOptions){OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},activate:function(){var activated=false;if(OpenLayers.Handler.Drag.prototype.activate.apply(this,arguments)){var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this,arguments)){if(this.dragging){this.cancel();}
+if(this.layer.map!=null){this.layer.destroy(false);if(this.feature){this.feature.destroy();}}
+this.layer=null;this.feature=null;deactivated=true;}
+return deactivated;},down:function(evt){this.fixedRadius=!!(this.radius);var maploc=this.layer.getLonLatFromViewPortPx(evt.xy);this.origin=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(!this.fixedRadius||this.irregular){this.radius=this.map.getResolution();}
+if(this.persist){this.clear();}
+this.feature=new OpenLayers.Feature.Vector();this.createGeometry();this.callback("create",[this.origin,this.feature]);this.layer.addFeatures([this.feature],{silent:true});this.layer.drawFeature(this.feature,this.style);},move:function(evt){var maploc=this.layer.getLonLatFromViewPortPx(evt.xy);var point=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(this.irregular){var ry=Math.sqrt(2)*Math.abs(point.y-this.origin.y)/2;this.radius=Math.max(this.map.getResolution()/2,ry);}else if(this.fixedRadius){this.origin=point;}else{this.calculateAngle(point,evt);this.radius=Math.max(this.map.getResolution()/2,point.distanceTo(this.origin));}
+this.modifyGeometry();if(this.irregular){var dx=point.x-this.origin.x;var dy=point.y-this.origin.y;var ratio;if(dy==0){ratio=dx/(this.radius*Math.sqrt(2));}else{ratio=dx/dy;}
+this.feature.geometry.resize(1,this.origin,ratio);this.feature.geometry.move(dx/2,dy/2);}
+this.layer.drawFeature(this.feature,this.style);},up:function(evt){this.finalize();if(this.start==this.last){this.callback("done",[evt.xy]);}},out:function(evt){this.finalize();},createGeometry:function(){this.angle=Math.PI*((1/this.sides)-(1/2));if(this.snapAngle){this.angle+=this.snapAngle*(Math.PI/180);}
+this.feature.geometry=OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin,this.radius,this.sides,this.snapAngle);},modifyGeometry:function(){var angle,point;var ring=this.feature.geometry.components[0];if(ring.components.length!=(this.sides+1)){this.createGeometry();ring=this.feature.geometry.components[0];}
+for(var i=0;i<this.sides;++i){point=ring.components[i];angle=this.angle+(i*2*Math.PI/this.sides);point.x=this.origin.x+(this.radius*Math.cos(angle));point.y=this.origin.y+(this.radius*Math.sin(angle));point.clearBounds();}},calculateAngle:function(point,evt){var alpha=Math.atan2(point.y-this.origin.y,point.x-this.origin.x);if(this.snapAngle&&(this.snapToggle&&!evt[this.snapToggle])){var snapAngleRad=(Math.PI/180)*this.snapAngle;this.angle=Math.round(alpha/snapAngleRad)*snapAngleRad;}else{this.angle=alpha;}},cancel:function(){this.callback("cancel",null);this.finalize();},finalize:function(){this.origin=null;this.radius=this.options.radius;},clear:function(){if(this.layer){this.layer.renderer.clear();this.layer.destroyFeatures();}},callback:function(name,args){if(this.callbacks[name]){this.callbacks[name].apply(this.control,[this.feature.geometry.clone()]);}
+if(!this.persist&&(name=="done"||name=="cancel")){this.clear();}},CLASS_NAME:"OpenLayers.Handler.RegularPolygon"});OpenLayers.Renderer.VML=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"urn:schemas-microsoft-com:vml",symbolCache:{},offset:null,initialize:function(containerID){if(!this.supported()){return;}
 if(!document.namespaces.olv){document.namespaces.add("olv",this.xmlns);var style=document.createStyleSheet();var shapes=['shape','rect','oval','fill','stroke','imagedata','group','textbox'];for(var i=0,len=shapes.length;i<len;i++){style.addRule('olv\\:'+shapes[i],"behavior: url(#default#VML); "+"position: absolute; display: inline-block;");}}
 OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);},supported:function(){return!!(document.namespaces);},setExtent:function(extent,resolutionChanged){var coordSysUnchanged=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution();var left=(extent.left/resolution)|0;var top=(extent.top/resolution-this.size.h)|0;if(resolutionChanged||!this.offset){this.offset={x:left,y:top};left=0;top=0;}else{left=left-this.offset.x;top=top-this.offset.y;}
 var org=(left-this.xOffset)+" "+top;this.root.coordorigin=org;var roots=[this.root,this.vectorRoot,this.textRoot];var root;for(var i=0,len=roots.length;i<len;++i){root=roots[i];var size=this.size.w+" "+this.size.h;root.coordsize=size;}
@@ -1270,20 +1398,7 @@ function callback(response){this.callUserCallback(response,options);success=succ
 var queue=types[OpenLayers.State.INSERT];if(queue.length>0){resp.push(this.create(queue,OpenLayers.Util.applyDefaults({callback:insertCallback,scope:this},options.create)));}
 queue=types[OpenLayers.State.UPDATE];for(var i=queue.length-1;i>=0;--i){resp.push(this.update(queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options.update)));}
 queue=types[OpenLayers.State.DELETE];for(var i=queue.length-1;i>=0;--i){resp.push(this["delete"](queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options["delete"])));}
-return resp;},abort:function(response){if(response){response.priv.abort();}},callUserCallback:function(resp,options){var opt=options[resp.requestType];if(opt&&opt.callback){opt.callback.call(opt.scope,resp);}},CLASS_NAME:"OpenLayers.Protocol.HTTP"});OpenLayers.Handler.RegularPolygon=OpenLayers.Class(OpenLayers.Handler.Drag,{sides:4,radius:null,snapAngle:null,snapToggle:'shiftKey',layerOptions:null,persist:false,irregular:false,citeCompliant:false,angle:null,fixedRadius:false,feature:null,layer:null,origin:null,initialize:function(control,callbacks,options){if(!(options&&options.layerOptions&&options.layerOptions.styleMap)){this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'],{});}
-OpenLayers.Handler.Drag.prototype.initialize.apply(this,[control,callbacks,options]);this.options=(options)?options:{};},setOptions:function(newOptions){OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},activate:function(){var activated=false;if(OpenLayers.Handler.Drag.prototype.activate.apply(this,arguments)){var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);activated=true;}
-return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this,arguments)){if(this.dragging){this.cancel();}
-if(this.layer.map!=null){this.layer.destroy(false);if(this.feature){this.feature.destroy();}}
-this.layer=null;this.feature=null;deactivated=true;}
-return deactivated;},down:function(evt){this.fixedRadius=!!(this.radius);var maploc=this.layer.getLonLatFromViewPortPx(evt.xy);this.origin=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(!this.fixedRadius||this.irregular){this.radius=this.map.getResolution();}
-if(this.persist){this.clear();}
-this.feature=new OpenLayers.Feature.Vector();this.createGeometry();this.callback("create",[this.origin,this.feature]);this.layer.addFeatures([this.feature],{silent:true});this.layer.drawFeature(this.feature,this.style);},move:function(evt){var maploc=this.layer.getLonLatFromViewPortPx(evt.xy);var point=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(this.irregular){var ry=Math.sqrt(2)*Math.abs(point.y-this.origin.y)/2;this.radius=Math.max(this.map.getResolution()/2,ry);}else if(this.fixedRadius){this.origin=point;}else{this.calculateAngle(point,evt);this.radius=Math.max(this.map.getResolution()/2,point.distanceTo(this.origin));}
-this.modifyGeometry();if(this.irregular){var dx=point.x-this.origin.x;var dy=point.y-this.origin.y;var ratio;if(dy==0){ratio=dx/(this.radius*Math.sqrt(2));}else{ratio=dx/dy;}
-this.feature.geometry.resize(1,this.origin,ratio);this.feature.geometry.move(dx/2,dy/2);}
-this.layer.drawFeature(this.feature,this.style);},up:function(evt){this.finalize();if(this.start==this.last){this.callback("done",[evt.xy]);}},out:function(evt){this.finalize();},createGeometry:function(){this.angle=Math.PI*((1/this.sides)-(1/2));if(this.snapAngle){this.angle+=this.snapAngle*(Math.PI/180);}
-this.feature.geometry=OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin,this.radius,this.sides,this.snapAngle);},modifyGeometry:function(){var angle,point;var ring=this.feature.geometry.components[0];if(ring.components.length!=(this.sides+1)){this.createGeometry();ring=this.feature.geometry.components[0];}
-for(var i=0;i<this.sides;++i){point=ring.components[i];angle=this.angle+(i*2*Math.PI/this.sides);point.x=this.origin.x+(this.radius*Math.cos(angle));point.y=this.origin.y+(this.radius*Math.sin(angle));point.clearBounds();}},calculateAngle:function(point,evt){var alpha=Math.atan2(point.y-this.origin.y,point.x-this.origin.x);if(this.snapAngle&&(this.snapToggle&&!evt[this.snapToggle])){var snapAngleRad=(Math.PI/180)*this.snapAngle;this.angle=Math.round(alpha/snapAngleRad)*snapAngleRad;}else{this.angle=alpha;}},cancel:function(){this.callback("cancel",null);this.finalize();},finalize:function(){this.origin=null;this.radius=this.options.radius;},clear:function(){if(this.layer){this.layer.renderer.clear();this.layer.destroyFeatures();}},callback:function(name,args){if(this.callbacks[name]){this.callbacks[name].apply(this.control,[this.feature.geometry.clone()]);}
-if(!this.persist&&(name=="done"||name=="cancel")){this.clear();}},CLASS_NAME:"OpenLayers.Handler.RegularPolygon"});OpenLayers.Lang["bg"]=OpenLayers.Util.applyDefaults({'Permalink':"Постоянна препратка",'Base Layer':"Основен слой",'Scale = 1 : ${scaleDenom}':"Мащаб = 1 : ${scaleDenom}",'methodDeprecated':"Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}."});OpenLayers.Lang["hr"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nepodržani zahtjev ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Osnovna karta",'noFID':"Ne mogu ažurirati značajku za koju ne postoji FID.",'browserNotSupported':"Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}",'commitSuccess':"WFS Transakcija: USPJEŠNA ${response}",'commitFailed':"WFS Transakcija: NEUSPJEŠNA ${response}",'Scale = 1 : ${scaleDenom}':"Mjerilo = 1 : ${scaleDenom}",'methodDeprecated':"Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}."});OpenLayers.Lang["be-tarask"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Неапрацаваны вынік запыту ${statusText}",'Permalink':"Сталая спасылка",'Overlays':"Слаі",'Base Layer':"Базавы слой",'noFID':"Немагчыма абнавіць магчымасьць, для якога не існуе FID.",'browserNotSupported':"Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}",'minZoomLevelError':"Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што  гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-транзакцыя: ПОСЬПЕХ ${response}",'commitFailed':"WFS-транзакцыя: ПАМЫЛКА ${response}",'googleWarning':"Не атрымалася загрузіць слой Google. \x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3e Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'getLayerWarning':"Немагчыма загрузіць слой ${layerType}.\x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3eХутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Маштаб = 1 : ${scaleDenom}",'W':"З",'E':"У",'N':"Пн",'S':"Пд",'reprojectDeprecated':"Вы выкарыстоўваеце ўстаноўку \'reproject\' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}."});OpenLayers.Lang["cs-CZ"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nezpracovaná návratová hodnota ${statusText}",'Permalink':"Trvalý odkaz",'Overlays':"Překryvné vrstvy",'Base Layer':"Podkladové vrstvy",'noFID':"Nelze aktualizovat prvek, pro který neexistuje FID.",'browserNotSupported':"Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}",'minZoomLevelError':"Vlastnost minZoomLevel by se měla používat pouze s potomky FixedZoomLevels vrstvami. To znamená, že vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti.Nelze to ovšem vyjmout bez možnosti, že bychom rozbili aplikace postavené na OL, které by na tom mohly záviset. Proto tuto vlastnost nedoporučujeme používat --  kontrola minZoomLevel bude odstraněna ve verzi 3.0. Použijte prosím raději nastavení min/max podle příkaldu popsaného na: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: ÚSPĚCH ${response}",'commitFailed':"WFS Transaction: CHYBA ${response}",'googleWarning':"Nepodařilo se správně načíst vrstvu Google.\x3cbr\x3e\x3cbr\x3eAbyste se zbavili této zprávy, zvolte jinou základní vrstvu v přepínači vrstev.\x3cbr\x3e\x3cbr\x3eTo se většinou stává, pokud nebyl načten skript, nebo neobsahuje správný klíč pro API pro tuto stránku.\x3cbr\x3e\x3cbr\x3eVývojáři: Pro pomoc, aby tohle fungovalo , \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklikněte sem\x3c/a\x3e",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.\x3cbr\x3e\x3cbr\x3eTo get rid of this message, select a new BaseLayer in the layer switcher in the upper-right corner.\x3cbr\x3e\x3cbr\x3eMost likely, this is because the ${layerLib} library script was either not correctly included.\x3cbr\x3e\x3cbr\x3eDevelopers: For help getting this working correctly, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Měřítko = 1 : ${scaleDenom}",'reprojectDeprecated':"Použil jste volbu \'reproject\' ve vrstvě ${layerName}. Tato volba není doporučená: byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, ale tato funkce je nyní zajištěna pomocí podpory Spherical Mercator. Více informací naleznete na http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Tato metoda je zavržená a bude ve verzi 3.0 odstraněna. Prosím, použijte raději ${newMethod}."});OpenLayers.Lang["br"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Distro evel reked anveret ${statusText}",'Permalink':"Peurliamm",'Overlays':"Gwiskadoù",'Base Layer':"Gwiskad diazez",'noFID':"N\'haller ket hizivaat un elfenn ma n\'eus ket a niverenn-anaout (FID) eviti.",'browserNotSupported':"N\'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}",'minZoomLevelError':"Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n\'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c\'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Treuzgread WFS : MAT EO ${response}",'commitFailed':"Treuzgread WFS Transaction: C\'HWITET ${response}",'googleWarning':"N\'eus ket bet gallet kargañ ar gwiskad Google ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het levraoueg Google Maps pe neuze ne glot ket an alc\'hwez API gant ho lec\'hienn.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'getLayerWarning':"N\'haller ket kargañ ar gwiskad ${layerType} ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het mat al levraoueg ${layerLib}.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit gouzout penaos reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Skeul = 1 : ${scaleDenom}",'W':"K",'E':"R",'N':"N",'S':"S",'reprojectDeprecated':"Emaoc\'h oc\'h implijout an dibarzh \'reproject\' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c\'horre kartennoù diazez kenwerzhel, un dra hag a c\'haller ober bremañ gant an arc\'hwel dre skor banndres boullek Mercator. Muioc\'h a ditouroù a c\'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas."});OpenLayers.Control.PinchZoom=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,containerCenter:null,pinchOrigin:null,currentCenter:null,autoActivate:true,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.handler=new OpenLayers.Handler.Pinch(this,{start:this.pinchStart,move:this.pinchMove,done:this.pinchDone},this.handlerOptions);},activate:function(){var activated=OpenLayers.Control.prototype.activate.apply(this,arguments);if(activated){this.map.events.on({moveend:this.updateContainerCenter,scope:this});this.updateContainerCenter();}
+return resp;},abort:function(response){if(response){response.priv.abort();}},callUserCallback:function(resp,options){var opt=options[resp.requestType];if(opt&&opt.callback){opt.callback.call(opt.scope,resp);}},CLASS_NAME:"OpenLayers.Protocol.HTTP"});OpenLayers.Lang["bg"]=OpenLayers.Util.applyDefaults({'Permalink':"Постоянна препратка",'Base Layer':"Основен слой",'Scale = 1 : ${scaleDenom}':"Мащаб = 1 : ${scaleDenom}",'methodDeprecated':"Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}."});OpenLayers.Lang["hr"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nepodržani zahtjev ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Osnovna karta",'noFID':"Ne mogu ažurirati značajku za koju ne postoji FID.",'browserNotSupported':"Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}",'commitSuccess':"WFS Transakcija: USPJEŠNA ${response}",'commitFailed':"WFS Transakcija: NEUSPJEŠNA ${response}",'Scale = 1 : ${scaleDenom}':"Mjerilo = 1 : ${scaleDenom}",'methodDeprecated':"Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}."});OpenLayers.Lang["be-tarask"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Неапрацаваны вынік запыту ${statusText}",'Permalink':"Сталая спасылка",'Overlays':"Слаі",'Base Layer':"Базавы слой",'noFID':"Немагчыма абнавіць магчымасьць, для якога не існуе FID.",'browserNotSupported':"Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}",'minZoomLevelError':"Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што  гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-транзакцыя: ПОСЬПЕХ ${response}",'commitFailed':"WFS-транзакцыя: ПАМЫЛКА ${response}",'googleWarning':"Не атрымалася загрузіць слой Google. \x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3e Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'getLayerWarning':"Немагчыма загрузіць слой ${layerType}.\x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3eХутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Маштаб = 1 : ${scaleDenom}",'W':"З",'E':"У",'N':"Пн",'S':"Пд",'reprojectDeprecated':"Вы выкарыстоўваеце ўстаноўку \'reproject\' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}."});OpenLayers.Lang["cs-CZ"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nezpracovaná návratová hodnota ${statusText}",'Permalink':"Trvalý odkaz",'Overlays':"Překryvné vrstvy",'Base Layer':"Podkladové vrstvy",'noFID':"Nelze aktualizovat prvek, pro který neexistuje FID.",'browserNotSupported':"Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}",'minZoomLevelError':"Vlastnost minZoomLevel by se měla používat pouze s potomky FixedZoomLevels vrstvami. To znamená, že vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti.Nelze to ovšem vyjmout bez možnosti, že bychom rozbili aplikace postavené na OL, které by na tom mohly záviset. Proto tuto vlastnost nedoporučujeme používat --  kontrola minZoomLevel bude odstraněna ve verzi 3.0. Použijte prosím raději nastavení min/max podle příkaldu popsaného na: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: ÚSPĚCH ${response}",'commitFailed':"WFS Transaction: CHYBA ${response}",'googleWarning':"Nepodařilo se správně načíst vrstvu Google.\x3cbr\x3e\x3cbr\x3eAbyste se zbavili této zprávy, zvolte jinou základní vrstvu v přepínači vrstev.\x3cbr\x3e\x3cbr\x3eTo se většinou stává, pokud nebyl načten skript, nebo neobsahuje správný klíč pro API pro tuto stránku.\x3cbr\x3e\x3cbr\x3eVývojáři: Pro pomoc, aby tohle fungovalo , \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklikněte sem\x3c/a\x3e",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.\x3cbr\x3e\x3cbr\x3eTo get rid of this message, select a new BaseLayer in the layer switcher in the upper-right corner.\x3cbr\x3e\x3cbr\x3eMost likely, this is because the ${layerLib} library script was either not correctly included.\x3cbr\x3e\x3cbr\x3eDevelopers: For help getting this working correctly, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Měřítko = 1 : ${scaleDenom}",'reprojectDeprecated':"Použil jste volbu \'reproject\' ve vrstvě ${layerName}. Tato volba není doporučená: byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, ale tato funkce je nyní zajištěna pomocí podpory Spherical Mercator. Více informací naleznete na http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Tato metoda je zavržená a bude ve verzi 3.0 odstraněna. Prosím, použijte raději ${newMethod}."});OpenLayers.Lang["br"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Distro evel reked anveret ${statusText}",'Permalink':"Peurliamm",'Overlays':"Gwiskadoù",'Base Layer':"Gwiskad diazez",'noFID':"N\'haller ket hizivaat un elfenn ma n\'eus ket a niverenn-anaout (FID) eviti.",'browserNotSupported':"N\'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}",'minZoomLevelError':"Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n\'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c\'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Treuzgread WFS : MAT EO ${response}",'commitFailed':"Treuzgread WFS Transaction: C\'HWITET ${response}",'googleWarning':"N\'eus ket bet gallet kargañ ar gwiskad Google ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het levraoueg Google Maps pe neuze ne glot ket an alc\'hwez API gant ho lec\'hienn.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'getLayerWarning':"N\'haller ket kargañ ar gwiskad ${layerType} ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het mat al levraoueg ${layerLib}.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit gouzout penaos reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Skeul = 1 : ${scaleDenom}",'W':"K",'E':"R",'N':"N",'S':"S",'reprojectDeprecated':"Emaoc\'h oc\'h implijout an dibarzh \'reproject\' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c\'horre kartennoù diazez kenwerzhel, un dra hag a c\'haller ober bremañ gant an arc\'hwel dre skor banndres boullek Mercator. Muioc\'h a ditouroù a c\'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas."});OpenLayers.Control.PinchZoom=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,containerCenter:null,pinchOrigin:null,currentCenter:null,autoActivate:true,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.handler=new OpenLayers.Handler.Pinch(this,{start:this.pinchStart,move:this.pinchMove,done:this.pinchDone},this.handlerOptions);},activate:function(){var activated=OpenLayers.Control.prototype.activate.apply(this,arguments);if(activated){this.map.events.on({moveend:this.updateContainerCenter,scope:this});this.updateContainerCenter();}
 return activated;},deactivate:function(){var deactivated=OpenLayers.Control.prototype.deactivate.apply(this,arguments);if(this.map&&this.map.events){this.map.events.un({moveend:this.updateContainerCenter,scope:this});}
 return deactivated;},updateContainerCenter:function(){var container=this.map.layerContainerDiv;this.containerCenter={x:parseInt(container.style.left,10)+50,y:parseInt(container.style.top,10)+50};},pinchStart:function(evt,pinchData){this.pinchOrigin=evt.xy;this.currentCenter=evt.xy;},pinchMove:function(evt,pinchData){var scale=pinchData.scale;var containerCenter=this.containerCenter;var pinchOrigin=this.pinchOrigin;var current=evt.xy;var dx=Math.round((current.x-pinchOrigin.x)+(scale-1)*(containerCenter.x-pinchOrigin.x));var dy=Math.round((current.y-pinchOrigin.y)+(scale-1)*(containerCenter.y-pinchOrigin.y));this.applyTransform("translate("+dx+"px, "+dy+"px) scale("+scale+")");this.currentCenter=current;},applyTransform:function(transform){var style=this.map.layerContainerDiv.style;style['-webkit-transform']=transform;style['-moz-transform']=transform;},pinchDone:function(evt,start,last){this.applyTransform("");var zoom=this.map.getZoomForResolution(this.map.getResolution()/last.scale,true);if(zoom!==this.map.getZoom()||!this.currentCenter.equals(this.pinchOrigin)){var resolution=this.map.getResolutionForZoom(zoom);var location=this.map.getLonLatFromPixel(this.pinchOrigin);var zoomPixel=this.currentCenter;var size=this.map.getSize();location.lon+=resolution*((size.w/2)-zoomPixel.x);location.lat-=resolution*((size.h/2)-zoomPixel.y);this.map.div.clientWidth=this.map.div.clientWidth;this.map.setCenter(location,zoom);}},CLASS_NAME:"OpenLayers.Control.PinchZoom"});OpenLayers.Lang["io"]=OpenLayers.Util.applyDefaults({'Scale = 1 : ${scaleDenom}':"Skalo = 1 : ${scaleDenom}"});OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{roundedCorner:false,roundedCornerColor:"darkblue",layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:true,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[];if(this.roundedCorner){OpenLayers.Console.warn('roundedCorner option is deprecated');}},destroy:function(){this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({buttonclick:this.onButtonClick,addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});if(this.outsideViewport){this.events.attachToElement(this.div);this.events.register("buttonclick",this,this.onButtonClick);}else{this.map.events.register("buttonclick",this,this.onButtonClick);}},draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();if(!this.outsideViewport){this.minimizeControl();}
 this.redraw();return this.div;},onButtonClick:function(evt){var button=evt.buttonElement;if(button===this.minimizeDiv){this.minimizeControl();}else if(button===this.maximizeDiv){this.maximizeControl();}else if(button._layerSwitcher===this.id){if(button["for"]){button=document.getElementById(button["for"]);}