From: Tom Hughes Date: Mon, 16 Oct 2017 18:08:32 +0000 (+0100) Subject: Merge remote-tracking branch 'upstream/pull/1580' X-Git-Tag: live~3947 X-Git-Url: https://git.openstreetmap.org./rails.git/commitdiff_plain/87918595da1e1fad2ddd7aa62f9fc537dff657ff?hp=c555c912047c8d0d23123093a729aa87ca642aee Merge remote-tracking branch 'upstream/pull/1580' --- diff --git a/.rubocop.yml b/.rubocop.yml index e1f1724e0..55be8141c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -27,15 +27,34 @@ Rails: Layout/ExtraSpacing: AllowForAlignment: true -Style/BracesAroundHashParameters: - EnforcedStyle: context_dependent +Lint/PercentStringArray: + Exclude: + - 'config/initializers/secure_headers.rb' + - 'app/controllers/site_controller.rb' -Style/FileName: +Naming/FileName: Exclude: - 'script/deliver-message' - 'script/locale/reload-languages' - 'script/update-spam-blocks' +Rails/ApplicationRecord: + Enabled: false + +Rails/HasManyOrHasOneDependent: + Enabled: false + +Rails/HttpPositionalArguments: + Enabled: false + +Rails/SkipsModelValidations: + Exclude: + - 'db/migrate/*.rb' + - 'app/controllers/user_controller.rb' + +Style/BracesAroundHashParameters: + EnforcedStyle: context_dependent + Style/FormatStringToken: EnforcedStyle: template @@ -60,19 +79,3 @@ Style/StringLiterals: Style/SymbolArray: EnforcedStyle: brackets - -Rails/ApplicationRecord: - Enabled: false - -Rails/HttpPositionalArguments: - Enabled: false - -Rails/SkipsModelValidations: - Exclude: - - 'db/migrate/*.rb' - - 'app/controllers/user_controller.rb' - -Lint/PercentStringArray: - Exclude: - - 'config/initializers/secure_headers.rb' - - 'app/controllers/site_controller.rb' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e89927c9d..41bd7c80a 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,11 +1,19 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-10-20 21:45:27 +0100 using RuboCop version 0.44.1. +# on 2017-10-05 10:04:24 +0100 using RuboCop version 0.50.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: aligned, indented +Layout/MultilineOperationIndentation: + Exclude: + - 'lib/bounding_box.rb' + # Offense count: 34 Lint/AmbiguousOperator: Exclude: @@ -14,11 +22,11 @@ Lint/AmbiguousOperator: - 'test/lib/bounding_box_test.rb' - 'test/lib/country_test.rb' -# Offense count: 117 +# Offense count: 124 Lint/AmbiguousRegexpLiteral: Enabled: false -# Offense count: 30 +# Offense count: 32 # Configuration parameters: AllowSafeAssignment. Lint/AssignmentInCondition: Exclude: @@ -36,52 +44,62 @@ Lint/AssignmentInCondition: - 'lib/osm.rb' - 'script/deliver-message' -# Offense count: 5 +# Offense count: 4 Lint/HandleExceptions: Exclude: - 'app/controllers/amf_controller.rb' - 'app/controllers/user_controller.rb' - - 'config/initializers/session.rb' + +# Offense count: 3 +Lint/InterpolationCheck: + Exclude: + - 'test/controllers/node_controller_test.rb' + +# Offense count: 2 +Lint/RescueWithoutErrorClass: + Exclude: + - 'app/helpers/browse_helper.rb' # Offense count: 2 Lint/ShadowingOuterLocalVariable: Exclude: - 'app/views/changeset/list.atom.builder' -# Offense count: 630 +# Offense count: 666 Metrics/AbcSize: Max: 280 -# Offense count: 35 -# Configuration parameters: CountComments. +# Offense count: 41 +# Configuration parameters: CountComments, ExcludedMethods. Metrics/BlockLength: - Max: 295 + Max: 240 # Offense count: 12 +# Configuration parameters: CountBlocks. Metrics/BlockNesting: Max: 5 -# Offense count: 62 +# Offense count: 63 # Configuration parameters: CountComments. Metrics/ClassLength: Max: 1790 -# Offense count: 69 +# Offense count: 71 Metrics/CyclomaticComplexity: Max: 20 -# Offense count: 2826 -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives. +# Offense count: 3004 +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # URISchemes: http, https Metrics/LineLength: - Max: 1072 + Max: 1073 -# Offense count: 612 +# Offense count: 675 # Configuration parameters: CountComments. Metrics/MethodLength: Max: 179 -# Offense count: 1 +# Offense count: 2 # Configuration parameters: CountComments. Metrics/ModuleLength: Max: 147 @@ -95,6 +113,30 @@ Metrics/ParameterLists: Metrics/PerceivedComplexity: Max: 23 +# Offense count: 5 +Naming/AccessorMethodName: + Exclude: + - 'app/controllers/application_controller.rb' + - 'app/helpers/title_helper.rb' + - 'app/models/old_way.rb' + - 'lib/osm.rb' + - 'lib/potlatch.rb' + +# Offense count: 8 +# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. +# NamePrefix: is_, has_, have_ +# NamePrefixBlacklist: is_, has_, have_ +# NameWhitelist: is_a? +Naming/PredicateName: + Exclude: + - 'spec/**/*' + - 'app/models/changeset.rb' + - 'app/models/old_node.rb' + - 'app/models/old_relation.rb' + - 'app/models/old_way.rb' + - 'app/models/user.rb' + - 'lib/classic_pagination/pagination.rb' + # Offense count: 2 # Configuration parameters: Include. # Include: app/**/*.rb, config/**/*.rb, lib/**/*.rb @@ -122,7 +164,7 @@ Rails/NotNullColumn: - 'db/migrate/025_add_end_time_to_changesets.rb' - 'db/migrate/20120404205604_add_user_and_description_to_redaction.rb' -# Offense count: 17 +# Offense count: 20 Rails/OutputSafety: Exclude: - 'app/controllers/user_controller.rb' @@ -136,27 +178,18 @@ Rails/OutputSafety: - 'lib/rich_text.rb' - 'test/helpers/application_helper_test.rb' -# Offense count: 74 +# Offense count: 86 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: strict, flexible Rails/TimeZone: Enabled: false -# Offense count: 5 -Style/AccessorMethodName: - Exclude: - - 'app/controllers/application_controller.rb' - - 'app/helpers/title_helper.rb' - - 'app/models/old_way.rb' - - 'lib/osm.rb' - - 'lib/potlatch.rb' - # Offense count: 1 Style/AsciiComments: Exclude: - 'test/models/message_test.rb' -# Offense count: 220 +# Offense count: 219 Style/Documentation: Enabled: false @@ -182,35 +215,15 @@ Style/LineEndConcatenation: - 'test/controllers/relation_controller_test.rb' - 'test/controllers/way_controller_test.rb' -# Offense count: 71 +# Offense count: 75 # Cop supports --auto-correct. +# Configuration parameters: Strict. Style/NumericLiterals: MinDigits: 11 -# Offense count: 8 -# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. -# NamePrefix: is_, has_, have_ -# NamePrefixBlacklist: is_, has_, have_ -# NameWhitelist: is_a? -Style/PredicateName: - Exclude: - - 'spec/**/*' - - 'app/models/changeset.rb' - - 'app/models/old_node.rb' - - 'app/models/old_relation.rb' - - 'app/models/old_way.rb' - - 'app/models/user.rb' - - 'lib/classic_pagination/pagination.rb' - -# Offense count: 97 +# Offense count: 95 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: compact, exploded Style/RaiseArgs: Enabled: false - -# Offense count: 2 -# Cop supports --auto-correct. -Style/RescueModifier: - Exclude: - - 'app/helpers/browse_helper.rb' diff --git a/.travis.yml b/.travis.yml index ad8f7e599..48ddb4a1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ rvm: - 2.3.1 cache: bundler addons: - postgresql: 9.1 + postgresql: 9.5 apt: packages: - - postgresql-server-dev-9.1 + - postgresql-server-dev-9.5 services: - memcached env: @@ -18,9 +18,10 @@ before_script: - psql -U postgres -c "CREATE DATABASE openstreetmap" - psql -U postgres -c "CREATE EXTENSION btree_gist" openstreetmap - make -C db/functions libpgosm.so - - psql -U postgres -c "CREATE FUNCTION maptile_for_point(int8, int8, int4) RETURNS int4 AS '${PWD}/db/functions/libpgosm', 'maptile_for_point' LANGUAGE C STRICT" openstreetmap - - psql -U postgres -c "CREATE FUNCTION tile_for_point(int4, int4) RETURNS int8 AS '${PWD}/db/functions/libpgosm', 'tile_for_point' LANGUAGE C STRICT" openstreetmap - - psql -U postgres -c "CREATE FUNCTION xid_to_int4(xid) RETURNS int4 AS '${PWD}/db/functions/libpgosm', 'xid_to_int4' LANGUAGE C STRICT" openstreetmap + - ln db/functions/libpgosm.so /tmp + - psql -U postgres -c "CREATE FUNCTION maptile_for_point(int8, int8, int4) RETURNS int4 AS '/tmp/libpgosm', 'maptile_for_point' LANGUAGE C STRICT" openstreetmap + - psql -U postgres -c "CREATE FUNCTION tile_for_point(int4, int4) RETURNS int8 AS '/tmp/libpgosm', 'tile_for_point' LANGUAGE C STRICT" openstreetmap + - psql -U postgres -c "CREATE FUNCTION xid_to_int4(xid) RETURNS int4 AS '/tmp/libpgosm', 'xid_to_int4' LANGUAGE C STRICT" openstreetmap - cp config/travis.database.yml config/database.yml - bundle exec rake db:migrate script: diff --git a/Gemfile b/Gemfile index baa1dcc04..ae1b472a2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source "https://rubygems.org" # Require rails -gem "rails", "5.0.4" +gem "rails", "5.0.6" # Require things which have moved to gems in ruby 1.9 gem "bigdecimal", "~> 1.1.0", :platforms => :ruby_19 @@ -32,7 +32,7 @@ gem "jquery-rails" gem "jsonify-rails" # Use R2 for RTL conversion -gem "r2" +gem "r2", "~> 0.2.7" # Use autoprefixer to generate CSS prefixes gem "autoprefixer-rails" @@ -43,11 +43,11 @@ gem "image_optim_rails" # Load rails plugins gem "actionpack-page_caching" gem "composite_primary_keys", "~> 9.0.7" -gem "deadlock_retry", ">= 1.2.0" gem "dynamic_form" gem "http_accept_language", "~> 2.0.0" gem "i18n-js", ">= 3.0.0" gem "oauth-plugin", ">= 0.5.1" +gem "openstreetmap-deadlock_retry", ">= 1.3.0", :require => "deadlock_retry" gem "paperclip", "~> 4.0" gem "rack-cors" gem "rails-i18n", "~> 4.0.0" diff --git a/Gemfile.lock b/Gemfile.lock index 9b79e9ca1..3cd36d5ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,58 +2,58 @@ GEM remote: https://rubygems.org/ specs: SystemTimer (1.2.3) - actioncable (5.0.4) - actionpack (= 5.0.4) + actioncable (5.0.6) + actionpack (= 5.0.6) nio4r (>= 1.2, < 3.0) websocket-driver (~> 0.6.1) - actionmailer (5.0.4) - actionpack (= 5.0.4) - actionview (= 5.0.4) - activejob (= 5.0.4) + actionmailer (5.0.6) + actionpack (= 5.0.6) + actionview (= 5.0.6) + activejob (= 5.0.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.4) - actionview (= 5.0.4) - activesupport (= 5.0.4) + actionpack (5.0.6) + actionview (= 5.0.6) + activesupport (= 5.0.6) rack (~> 2.0) rack-test (~> 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) actionpack-page_caching (1.1.0) actionpack (>= 4.0.0, < 6) - actionview (5.0.4) - activesupport (= 5.0.4) + actionview (5.0.6) + activesupport (= 5.0.6) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.0.4) - activesupport (= 5.0.4) + activejob (5.0.6) + activesupport (= 5.0.6) globalid (>= 0.3.6) - activemodel (5.0.4) - activesupport (= 5.0.4) - activerecord (5.0.4) - activemodel (= 5.0.4) - activesupport (= 5.0.4) + activemodel (5.0.6) + activesupport (= 5.0.6) + activerecord (5.0.6) + activemodel (= 5.0.6) + activesupport (= 5.0.6) arel (~> 7.0) - activesupport (5.0.4) + activesupport (5.0.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.5.1) - public_suffix (~> 2.0, >= 2.0.2) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) arel (7.1.4) ast (2.3.0) - autoprefixer-rails (7.1.1.2) + autoprefixer-rails (7.1.4.1) execjs bigdecimal (1.1.0) builder (3.2.3) - canonical-rails (0.2.0) + canonical-rails (0.2.1) rails (>= 4.1, < 5.2) - capybara (2.14.3) + capybara (2.15.3) addressable - mime-types (>= 1.16) + mini_mime (>= 0.1.3) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) @@ -82,39 +82,38 @@ GEM safe_yaml (~> 1.0.0) crass (1.0.2) dalli (2.7.6) - deadlock_retry (1.2.0) docile (1.1.5) dynamic_form (1.1.4) erubis (2.7.0) execjs (2.7.0) - exifr (1.2.5) - factory_girl (4.8.0) + exifr (1.3.2) + factory_girl (4.8.1) activesupport (>= 3.0.0) factory_girl_rails (4.8.0) factory_girl (~> 4.8.0) railties (>= 3.0.0) - faraday (0.12.1) + faraday (0.12.2) multipart-post (>= 1.2, < 3) ffi (1.9.18) fspath (3.1.0) geoip (1.6.3) globalid (0.4.0) activesupport (>= 4.2.0) - hashdiff (0.3.4) - hashie (3.5.5) + hashdiff (0.3.6) + hashie (3.5.6) htmlentities (4.3.4) http_accept_language (2.0.5) - i18n (0.8.4) - i18n-js (3.0.0) + i18n (0.8.6) + i18n-js (3.0.1) i18n (~> 0.6, >= 0.6.6) - image_optim (0.24.3) + image_optim (0.25.0) exifr (~> 1.2, >= 1.2.2) fspath (~> 3.0) image_size (~> 1.5) in_threads (~> 1.3) progress (~> 3.0, >= 3.0.1) - image_optim_rails (0.4.0) - image_optim (~> 0.24.0) + image_optim_rails (0.4.1) + image_optim (~> 0.24) rails sprockets image_size (1.5.0) @@ -146,23 +145,25 @@ GEM activesupport (>= 4.0) logstash-event (~> 1.2.0) request_store - loofah (2.0.3) + loofah (2.1.1) + crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.6.6) mime-types (>= 1.16, < 4) - method_source (0.8.2) + method_source (0.9.0) mime-types (3.1) mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mimemagic (0.3.0) - mini_portile2 (2.2.0) - minitest (5.10.2) - multi_json (1.12.1) + mini_mime (0.1.4) + mini_portile2 (2.3.0) + minitest (5.10.3) + multi_json (1.12.2) multi_xml (0.6.0) multipart-post (2.0.0) nio4r (2.1.0) - nokogiri (1.8.0) - mini_portile2 (~> 2.2.0) + nokogiri (1.8.1) + mini_portile2 (~> 2.3.0) nokogumbo (1.4.13) nokogiri oauth (0.4.7) @@ -177,7 +178,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (1.6.1) + omniauth (1.7.1) hashie (>= 3.4.6, < 3.6.0) rack (>= 1.6.2, < 3) omniauth-facebook (4.0.0) @@ -185,7 +186,7 @@ GEM omniauth-github (1.3.0) omniauth (~> 1.5) omniauth-oauth2 (>= 1.4.0, < 2.0) - omniauth-google-oauth2 (0.5.0) + omniauth-google-oauth2 (0.5.2) jwt (~> 1.5) multi_json (~> 1.3) omniauth (>= 1.1.1) @@ -205,44 +206,45 @@ GEM omniauth-windowslive (0.0.12) multi_json (~> 1.12) omniauth-oauth2 (~> 1.4) + openstreetmap-deadlock_retry (1.3.0) paperclip (4.3.7) activemodel (>= 3.2.0) activesupport (>= 3.2.0) cocaine (~> 0.5.5) mime-types mimemagic (= 0.3.0) - parallel (1.11.2) + parallel (1.12.0) parser (2.4.0.0) ast (~> 2.2) pg (0.21.0) - poltergeist (1.15.0) + poltergeist (1.16.0) capybara (~> 2.1) cliver (~> 0.3.1) websocket-driver (>= 0.2.0) powerpack (0.1.1) progress (3.3.1) psych (2.2.4) - public_suffix (2.0.5) - r2 (0.2.6) + public_suffix (3.0.0) + r2 (0.2.7) rack (2.0.3) - rack-cors (0.4.1) + rack-cors (1.0.1) rack-openid (1.3.1) rack (>= 1.1.0) ruby-openid (>= 2.1.8) rack-test (0.6.3) rack (>= 1.0) rack-uri_sanitizer (0.0.2) - rails (5.0.4) - actioncable (= 5.0.4) - actionmailer (= 5.0.4) - actionpack (= 5.0.4) - actionview (= 5.0.4) - activejob (= 5.0.4) - activemodel (= 5.0.4) - activerecord (= 5.0.4) - activesupport (= 5.0.4) - bundler (>= 1.3.0, < 2.0) - railties (= 5.0.4) + rails (5.0.6) + actioncable (= 5.0.6) + actionmailer (= 5.0.6) + actionpack (= 5.0.6) + actionview (= 5.0.6) + activejob (= 5.0.6) + activemodel (= 5.0.6) + activerecord (= 5.0.6) + activesupport (= 5.0.6) + bundler (>= 1.3.0) + railties (= 5.0.6) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.2) actionpack (~> 5.x, >= 5.0.1) @@ -256,16 +258,16 @@ GEM rails-i18n (4.0.2) i18n (~> 0.6) rails (>= 4.0) - railties (5.0.4) - actionpack (= 5.0.4) - activesupport (= 5.0.4) + railties (5.0.6) + actionpack (= 5.0.6) + activesupport (= 5.0.6) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.2.2) rake - rake (12.0.0) - rb-fsevent (0.9.8) + rake (12.1.0) + rb-fsevent (0.10.2) rb-inotify (0.9.10) ffi (>= 0.5.0, < 2) record_tag_helper (1.0.0) @@ -273,41 +275,45 @@ GEM redcarpet (3.4.0) ref (2.0.0) request_store (1.3.2) - rinku (2.0.2) + rinku (2.0.3) rotp (3.3.0) - rubocop (0.49.1) + rubocop (0.50.0) parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) - rainbow (>= 1.99.1, < 3.0) + rainbow (>= 2.2.2, < 3.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) ruby-openid (2.7.0) - ruby-progressbar (1.8.1) + ruby-progressbar (1.9.0) ruby_dep (1.5.0) safe_yaml (1.0.4) sanitize (4.5.0) crass (~> 1.0.2) nokogiri (>= 1.4.4) nokogumbo (~> 1.4.1) - sass (3.4.24) + sass (3.5.2) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) sass-rails (5.0.6) railties (>= 4.0.0, < 6) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - secure_headers (3.6.5) - useragent + secure_headers (4.0.1) + useragent (>= 0.15.0) simplecov (0.14.1) docile (~> 1.1.0) json (>= 1.8, < 3) simplecov-html (~> 0.10.0) - simplecov-html (0.10.1) + simplecov-html (0.10.2) sprockets (3.7.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.2.0) + sprockets-rails (3.2.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) @@ -318,8 +324,8 @@ GEM ref thor (0.19.4) thread_safe (0.3.6) - tilt (2.0.7) - tins (1.14.0) + tilt (2.0.8) + tins (1.15.0) tzinfo (1.2.3) thread_safe (~> 0.1) uglifier (3.2.0) @@ -352,7 +358,6 @@ DEPENDENCIES composite_primary_keys (~> 9.0.7) coveralls dalli - deadlock_retry (>= 1.2.0) dynamic_form factory_girl_rails faraday @@ -378,14 +383,15 @@ DEPENDENCIES omniauth-mediawiki (>= 0.0.3) omniauth-openid omniauth-windowslive + openstreetmap-deadlock_retry (>= 1.3.0) paperclip (~> 4.0) pg poltergeist psych - r2 + r2 (~> 0.2.7) rack-cors rack-uri_sanitizer - rails (= 5.0.4) + rails (= 5.0.6) rails-controller-testing rails-i18n (~> 4.0.0) record_tag_helper diff --git a/README.md b/README.md index 5b909454f..6b929fef9 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,8 @@ We're always keen to have more developers! Pull requests are very welcome. * IRC - there is the #osm-dev channel on irc.oftc.net. More details on contributing to the code are in the [CONTRIBUTING.md](CONTRIBUTING.md) file. + +# Maintainers + +* Tom Hughes [@tomhughes](https://github.com/tomhughes/) +* Andy Allan [@gravitystorm](https://github.com/gravitystorm/) diff --git a/Vendorfile b/Vendorfile index 502f8b597..d66dd80d8 100644 --- a/Vendorfile +++ b/Vendorfile @@ -11,13 +11,13 @@ folder 'vendor/assets' do end folder 'leaflet' do - file 'leaflet.js', 'https://unpkg.com/leaflet@1.1.0/dist/leaflet-src.js' - file 'leaflet.css', 'https://unpkg.com/leaflet@1.1.0/dist/leaflet.css' + file 'leaflet.js', 'https://unpkg.com/leaflet@1.2.0/dist/leaflet-src.js' + file 'leaflet.css', 'https://unpkg.com/leaflet@1.2.0/dist/leaflet.css' [ 'layers.png', 'layers-2x.png', 'marker-icon.png', 'marker-icon-2x.png', 'marker-shadow.png' ].each do |image| - file "images/#{image}", "https://unpkg.com/leaflet@1.1.0/dist/images/#{image}" + file "images/#{image}", "https://unpkg.com/leaflet@1.2.0/dist/images/#{image}" end from 'git://github.com/aratcliffe/Leaflet.contextmenu.git', :tag => 'v1.2.1' do @@ -31,7 +31,7 @@ folder 'vendor/assets' do folder 'img', 'src/img' end - from 'git://github.com/domoritz/leaflet-locatecontrol.git', :tag => 'v0.54.0' do + from 'git://github.com/domoritz/leaflet-locatecontrol.git', :tag => 'v0.62.0' do file 'leaflet.locate.js', 'src/L.Control.Locate.js' end diff --git a/app/assets/images/banners/banner-sotmus2017.png b/app/assets/images/banners/banner-sotmus2017.png new file mode 100644 index 000000000..25382bf4a Binary files /dev/null and b/app/assets/images/banners/banner-sotmus2017.png differ diff --git a/app/assets/images/banners/donate-2016.jpg b/app/assets/images/banners/donate-2016.jpg deleted file mode 100644 index 7e2e6eb93..000000000 Binary files a/app/assets/images/banners/donate-2016.jpg and /dev/null differ diff --git a/app/assets/images/banners/sotmasia-2016.jpg b/app/assets/images/banners/sotmasia-2016.jpg deleted file mode 100644 index fa5f1f033..000000000 Binary files a/app/assets/images/banners/sotmasia-2016.jpg and /dev/null differ diff --git a/app/assets/images/banners/sotmasia-2017-banner.png b/app/assets/images/banners/sotmasia-2017-banner.png new file mode 100644 index 000000000..f18f5bf72 Binary files /dev/null and b/app/assets/images/banners/sotmasia-2017-banner.png differ diff --git a/app/assets/images/banners/sotmlatam-2016.jpg b/app/assets/images/banners/sotmlatam-2016.jpg deleted file mode 100644 index 97efa75e2..000000000 Binary files a/app/assets/images/banners/sotmlatam-2016.jpg and /dev/null differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 7d5b99f60..7afbffb16 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -79,18 +79,6 @@ $(document).ready(function () { var headerWidth = 0, compactWidth = 0; - $("header").children(":visible").each(function (i,e) { - headerWidth = headerWidth + $(e).outerWidth(); - }); - - $("body").addClass("compact"); - - $("header").children(":visible").each(function (i,e) { - compactWidth = compactWidth + $(e).outerWidth(); - }); - - $("body").removeClass("compact"); - function updateHeader() { var windowWidth = $(window).width(); @@ -103,9 +91,29 @@ $(document).ready(function () { } } - updateHeader(); + /* + * Chrome 60 and later seem to fire the "ready" callback + * before the DOM is fully ready causing us to measure the + * wrong sizes for the header elements - use a 0ms timeout + * to defer the measurement slightly as a workaround. + */ + setTimeout(function () { + $("header").children(":visible").each(function (i,e) { + headerWidth = headerWidth + $(e).outerWidth(); + }); + + $("body").addClass("compact"); + + $("header").children(":visible").each(function (i,e) { + compactWidth = compactWidth + $(e).outerWidth(); + }); + + $("body").removeClass("compact"); + + updateHeader(); - $(window).resize(updateHeader); + $(window).resize(updateHeader); + }, 0); $("#menu-icon").on("click", function(e) { e.preventDefault(); diff --git a/app/assets/javascripts/edit/id.js.erb b/app/assets/javascripts/edit/id.js.erb index 6b902587e..834eeb75b 100644 --- a/app/assets/javascripts/edit/id.js.erb +++ b/app/assets/javascripts/edit/id.js.erb @@ -20,6 +20,7 @@ $(document).ready(function () { if (hashParams.background) params.background = hashParams.background; if (hashParams.comment) params.comment = hashParams.comment; + if (hashParams.hashtags) params.hashtags = hashParams.hashtags; if (hashParams.offset) params.offset = hashParams.offset; if (hashParams.walkthrough) params.walkthrough = hashParams.walkthrough; diff --git a/app/assets/javascripts/index/query.js b/app/assets/javascripts/index/query.js index 018aedf98..7ac613d71 100644 --- a/app/assets/javascripts/index/query.js +++ b/app/assets/javascripts/index/query.js @@ -146,7 +146,7 @@ OSM.Query = function(map) { if (feature.type === "node" && feature.lat && feature.lon) { geometry = L.circleMarker([feature.lat, feature.lon], featureStyle); - } else if (feature.type === "way" && feature.geometry) { + } else if (feature.type === "way" && feature.geometry && feature.geometry.length > 0) { geometry = L.polyline(feature.geometry.filter(function (point) { return point !== null; }).map(function (point) { diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 121e0c6d6..6b99662a4 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -1664,6 +1664,10 @@ tr.turn:hover { display: inline; } +.pagination { + padding-top: $lineheight; +} + /* Rules for the diary entry page */ .diary_entry { @@ -2776,12 +2780,30 @@ input.richtext_title[type="text"] { vertical-align: middle; background: 40px 40px image-url('about/sprite.png') no-repeat; - &.local { background-position: 0px 0px; } - &.community { background-position: 0px -40px; } - &.open { background-position: 0px -80px; } - &.partners { background-position: 0px -120px; } - &.infringement { background-position: 0px -160px; } - &.legal { background-position: -45px -160px; } + &.local { + /* no-r2 */ + background-position: 0px 0px; + } + &.community { + /* no-r2 */ + background-position: 0px -40px; + } + &.open { + /* no-r2 */ + background-position: 0px -80px; + } + &.partners { + /* no-r2 */ + background-position: 0px -120px; + } + &.infringement { + /* no-r2 */ + background-position: 0px -160px; + } + &.legal { + /* no-r2 */ + background-position: -45px -160px; + } } } diff --git a/app/controllers/amf_controller.rb b/app/controllers/amf_controller.rb index 51db8296d..679e137d9 100644 --- a/app/controllers/amf_controller.rb +++ b/app/controllers/amf_controller.rb @@ -151,7 +151,7 @@ class AmfController < ApplicationController cs = Changeset.find(closeid.to_i) cs.set_closed_time_now if cs.user_id != user.id - raise OSM::APIUserChangesetMismatchError.new + raise OSM::APIUserChangesetMismatchError elsif closecomment.empty? cs.save! else @@ -229,7 +229,7 @@ class AmfController < ApplicationController begin other = YAML.safe_load(File.open(Rails.root.join("config", "potlatch", "locales", "#{lang}.yml")))[lang] loaded_lang = lang - rescue + rescue StandardError other = en end @@ -907,7 +907,7 @@ class AmfController < ApplicationController # Alternative SQL queries for getway/whichways def sql_find_ways_in_area(bbox) - sql = <<-EOF + sql = <<-SQL SELECT DISTINCT current_ways.id AS wayid,current_ways.version AS version FROM current_way_nodes INNER JOIN current_nodes ON current_nodes.id=current_way_nodes.node_id @@ -915,20 +915,20 @@ class AmfController < ApplicationController WHERE current_nodes.visible=TRUE AND current_ways.visible=TRUE AND #{OSM.sql_for_area(bbox, 'current_nodes.')} - EOF + SQL ActiveRecord::Base.connection.select_all(sql).collect { |a| [a["wayid"].to_i, a["version"].to_i] } end def sql_find_pois_in_area(bbox) pois = [] - sql = <<-EOF + sql = <<-SQL SELECT current_nodes.id,current_nodes.latitude*0.0000001 AS lat,current_nodes.longitude*0.0000001 AS lon,current_nodes.version FROM current_nodes LEFT OUTER JOIN current_way_nodes cwn ON cwn.node_id=current_nodes.id WHERE current_nodes.visible=TRUE AND cwn.id IS NULL AND #{OSM.sql_for_area(bbox, 'current_nodes.')} - EOF + SQL ActiveRecord::Base.connection.select_all(sql).each do |row| poitags = {} ActiveRecord::Base.connection.select_all("SELECT k,v FROM current_node_tags WHERE id=#{row['id']}").each do |n| @@ -942,36 +942,36 @@ class AmfController < ApplicationController def sql_find_relations_in_area_and_ways(bbox, way_ids) # ** It would be more Potlatchy to get relations for nodes within ways # during 'getway', not here - sql = <<-EOF + sql = <<-SQL SELECT DISTINCT cr.id AS relid,cr.version AS version FROM current_relations cr INNER JOIN current_relation_members crm ON crm.id=cr.id INNER JOIN current_nodes cn ON crm.member_id=cn.id AND crm.member_type='Node' WHERE #{OSM.sql_for_area(bbox, 'cn.')} - EOF + SQL unless way_ids.empty? - sql += <<-EOF + sql += <<-SQL UNION SELECT DISTINCT cr.id AS relid,cr.version AS version FROM current_relations cr INNER JOIN current_relation_members crm ON crm.id=cr.id WHERE crm.member_type='Way' AND crm.member_id IN (#{way_ids.join(',')}) - EOF + SQL end ActiveRecord::Base.connection.select_all(sql).collect { |a| [a["relid"].to_i, a["version"].to_i] } end def sql_get_nodes_in_way(wayid) points = [] - sql = <<-EOF + sql = <<-SQL SELECT latitude*0.0000001 AS lat,longitude*0.0000001 AS lon,current_nodes.id,current_nodes.version FROM current_way_nodes,current_nodes WHERE current_way_nodes.id=#{wayid.to_i} AND current_way_nodes.node_id=current_nodes.id AND current_nodes.visible=TRUE ORDER BY sequence_id - EOF + SQL ActiveRecord::Base.connection.select_all(sql).each do |row| nodetags = {} ActiveRecord::Base.connection.select_all("SELECT k,v FROM current_node_tags WHERE id=#{row['id']}").each do |n| diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index c36ded1c0..9324a8ed5 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -305,7 +305,7 @@ class ApiController < ApplicationController def permissions @permissions = if current_token.present? ClientApplication.all_permissions.select { |p| current_token.read_attribute(p) } - elsif @user + elsif current_user ClientApplication.all_permissions else [] diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 534b37058..0988fcdf8 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,11 +5,14 @@ class ApplicationController < ActionController::Base before_action :fetch_body + attr_accessor :current_user + helper_method :current_user + def authorize_web if session[:user] - @user = User.where(:id => session[:user]).where("status IN ('active', 'confirmed', 'suspended')").first + self.current_user = User.where(:id => session[:user]).where("status IN ('active', 'confirmed', 'suspended')").first - if @user.status == "suspended" + if current_user.status == "suspended" session.delete(:user) session_expires_automatically @@ -17,7 +20,7 @@ class ApplicationController < ActionController::Base # don't allow access to any auth-requiring part of the site unless # the new CTs have been seen (and accept/decline chosen). - elsif !@user.terms_seen && flash[:skip_terms].nil? + elsif !current_user.terms_seen && flash[:skip_terms].nil? flash[:notice] = t "user.terms.you need to accept or decline" if params[:referer] redirect_to :controller => "user", :action => "terms", :referer => params[:referer] @@ -26,18 +29,18 @@ class ApplicationController < ActionController::Base end end elsif session[:token] - if @user = User.authenticate(:token => session[:token]) - session[:user] = @user.id + if self.current_user = User.authenticate(:token => session[:token]) + session[:user] = current_user.id end end rescue StandardError => ex logger.info("Exception authorizing user: #{ex}") reset_session - @user = nil + self.current_user = nil end def require_user - unless @user + unless current_user if request.get? redirect_to :controller => "user", :action => "login", :referer => request.fullpath else @@ -47,7 +50,7 @@ class ApplicationController < ActionController::Base end def require_oauth - @oauth = @user.access_token(OAUTH_KEY) if @user && defined? OAUTH_KEY + @oauth = current_user.access_token(OAUTH_KEY) if current_user && defined? OAUTH_KEY end ## @@ -100,7 +103,7 @@ class ApplicationController < ActionController::Base def require_allow_write_api require_capability(:allow_write_api) - if REQUIRE_TERMS_AGREED && @user.terms_agreed.nil? + if REQUIRE_TERMS_AGREED && current_user.terms_agreed.nil? report_error "You must accept the contributor terms before you can edit.", :forbidden return false end @@ -122,7 +125,7 @@ class ApplicationController < ActionController::Base # require that the user is a moderator, or fill out a helpful error message # and return them to the index for the controller this is wrapped from. def require_moderator - unless @user.moderator? + unless current_user.moderator? if request.get? flash[:error] = t("application.require_moderator.not_a_moderator") redirect_to :action => "index" @@ -133,7 +136,7 @@ class ApplicationController < ActionController::Base end ## - # sets up the @user object for use by other methods. this is mostly called + # sets up the current_user for use by other methods. this is mostly called # from the authorize method, but can be called elsewhere if authorisation # is optional. def setup_user_auth @@ -141,19 +144,19 @@ class ApplicationController < ActionController::Base unless Authenticator.new(self, [:token]).allow? username, passwd = get_auth_data # parse from headers # authenticate per-scheme - @user = if username.nil? - nil # no authentication provided - perhaps first connect (client should retry after 401) - elsif username == "token" - User.authenticate(:token => passwd) # preferred - random token for user from db, passed in basic auth - else - User.authenticate(:username => username, :password => passwd) # basic auth - end + self.current_user = if username.nil? + nil # no authentication provided - perhaps first connect (client should retry after 401) + elsif username == "token" + User.authenticate(:token => passwd) # preferred - random token for user from db, passed in basic auth + else + User.authenticate(:username => username, :password => passwd) # basic auth + end end # have we identified the user? - if @user + if current_user # check if the user has been banned - user_block = @user.blocks.active.take + user_block = current_user.blocks.active.take unless user_block.nil? set_locale if user_block.zero_hour? @@ -166,7 +169,7 @@ class ApplicationController < ActionController::Base # if the user hasn't seen the contributor terms then don't # allow editing - they have to go to the web site and see # (but can decline) the CTs to continue. - if REQUIRE_TERMS_SEEN && !@user.terms_seen && flash[:skip_terms].nil? + if REQUIRE_TERMS_SEEN && !current_user.terms_seen && flash[:skip_terms].nil? set_locale report_error t("application.setup_user_auth.need_to_see_terms"), :forbidden end @@ -178,7 +181,7 @@ class ApplicationController < ActionController::Base setup_user_auth # handle authenticate pass/fail - unless @user + unless current_user # no auth, the user does not exist or the password was wrong response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\"" render :plain => errormessage, :status => :unauthorized @@ -196,7 +199,7 @@ class ApplicationController < ActionController::Base # good idea to do that in this branch. def authorize_moderator(errormessage = "Access restricted to moderators") # check user is a moderator - unless @user.moderator? + unless current_user.moderator? render :plain => errormessage, :status => :forbidden false end @@ -266,7 +269,7 @@ class ApplicationController < ActionController::Base end def require_public_data - unless @user.data_public? + unless current_user.data_public? report_error "You must make your edits public to upload new data", :forbidden false end @@ -297,8 +300,8 @@ class ApplicationController < ActionController::Base def preferred_languages @languages ||= if params[:locale] Locale.list(params[:locale]) - elsif @user - @user.preferred_languages + elsif current_user + current_user.preferred_languages else Locale.list(http_accept_language.user_preferred_languages) end @@ -307,9 +310,9 @@ class ApplicationController < ActionController::Base helper_method :preferred_languages def set_locale - if @user && @user.languages.empty? && !http_accept_language.user_preferred_languages.empty? - @user.languages = http_accept_language.user_preferred_languages - @user.save + if current_user && current_user.languages.empty? && !http_accept_language.user_preferred_languages.empty? + current_user.languages = http_accept_language.user_preferred_languages + current_user.save end I18n.locale = Locale.available.preferred(preferred_languages) @@ -343,7 +346,7 @@ class ApplicationController < ActionController::Base # or raises a suitable error. +method+ should be a symbol, e.g: :put or :get. def assert_method(method) ok = request.send((method.to_s.downcase + "?").to_sym) - raise OSM::APIBadMethodError.new(method) unless ok + raise OSM::APIBadMethodError, method unless ok end ## @@ -427,8 +430,8 @@ class ApplicationController < ActionController::Base def preferred_editor editor = if params[:editor] params[:editor] - elsif @user && @user.preferred_editor - @user.preferred_editor + elsif current_user && current_user.preferred_editor + current_user.preferred_editor else DEFAULT_EDITOR end @@ -466,16 +469,6 @@ class ApplicationController < ActionController::Base [user, pass] end - # used by oauth plugin to get the current user - def current_user - @user - end - - # used by oauth plugin to set the current user - def current_user=(user) - @user = user - end - # override to stop oauth plugin sending errors def invalid_oauth_response; end end diff --git a/app/controllers/browse_controller.rb b/app/controllers/browse_controller.rb index a5aa52774..41fa14aae 100644 --- a/app/controllers/browse_controller.rb +++ b/app/controllers/browse_controller.rb @@ -58,7 +58,7 @@ class BrowseController < ApplicationController def changeset @type = "changeset" @changeset = Changeset.find(params[:id]) - @comments = if @user && @user.moderator? + @comments = if current_user && current_user.moderator? @changeset.comments.unscope(:where => :visible).includes(:author) else @changeset.comments.includes(:author) @@ -77,7 +77,7 @@ class BrowseController < ApplicationController def note @type = "note" - if @user && @user.moderator? + if current_user && current_user.moderator? @note = Note.find(params[:id]) @note_comments = @note.comments.unscope(:where => :visible) else diff --git a/app/controllers/changeset_controller.rb b/app/controllers/changeset_controller.rb index e80eb1610..531ec17ee 100644 --- a/app/controllers/changeset_controller.rb +++ b/app/controllers/changeset_controller.rb @@ -28,11 +28,11 @@ class ChangesetController < ApplicationController cs = Changeset.from_xml(request.raw_post, true) # Assume that Changeset.from_xml has thrown an exception if there is an error parsing the xml - cs.user_id = @user.id + cs.user_id = current_user.id cs.save_with_tags! # Subscribe user to changeset comments - cs.subscribers << @user + cs.subscribers << current_user render :plain => cs.id.to_s end @@ -53,7 +53,7 @@ class ChangesetController < ApplicationController assert_method :put changeset = Changeset.find(params[:id]) - check_changeset_consistency(changeset, @user) + check_changeset_consistency(changeset, current_user) # to close the changeset, we'll just set its closed_at time to # now. this might not be enough if there are concurrency issues, @@ -75,7 +75,7 @@ class ChangesetController < ApplicationController assert_method :post cs = Changeset.find(params[:id]) - check_changeset_consistency(cs, @user) + check_changeset_consistency(cs, current_user) # keep an array of lons and lats lon = [] @@ -127,7 +127,7 @@ class ChangesetController < ApplicationController assert_method :post changeset = Changeset.find(params[:id]) - check_changeset_consistency(changeset, @user) + check_changeset_consistency(changeset, current_user) diff_reader = DiffReader.new(request.raw_post, changeset) Changeset.transaction do @@ -242,8 +242,8 @@ class ChangesetController < ApplicationController changeset = Changeset.find(params[:id]) new_changeset = Changeset.from_xml(request.raw_post) - check_changeset_consistency(changeset, @user) - changeset.update_from(new_changeset, @user) + check_changeset_consistency(changeset, current_user) + changeset.update_from(new_changeset, current_user) render :xml => changeset.to_xml.to_s end @@ -265,7 +265,7 @@ class ChangesetController < ApplicationController end end - if (@params[:friends] || @params[:nearby]) && !@user + if (@params[:friends] || @params[:nearby]) && !current_user require_user return end @@ -277,17 +277,17 @@ class ChangesetController < ApplicationController changesets = conditions_nonempty(Changeset.all) if @params[:display_name] - changesets = if user.data_public? || user == @user + changesets = if user.data_public? || user == current_user changesets.where(:user_id => user.id) else changesets.where("false") end elsif @params[:bbox] changesets = conditions_bbox(changesets, BoundingBox.from_bbox_params(params)) - elsif @params[:friends] && @user - changesets = changesets.where(:user_id => @user.friend_users.identifiable) - elsif @params[:nearby] && @user - changesets = changesets.where(:user_id => @user.nearby) + elsif @params[:friends] && current_user + changesets = changesets.where(:user_id => current_user.friend_users.identifiable) + elsif @params[:nearby] && current_user + changesets = changesets.where(:user_id => current_user.nearby) end if @params[:max_id] @@ -310,8 +310,8 @@ class ChangesetController < ApplicationController # Add a comment to a changeset 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? + raise OSM::APIBadUserInput, "No id was given" unless params[:id] + raise OSM::APIBadUserInput, "No text was given" if params[:text].blank? # Extract the arguments id = params[:id].to_i @@ -319,22 +319,22 @@ class ChangesetController < ApplicationController # Find the changeset and check it is valid changeset = Changeset.find(id) - raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open? + raise OSM::APIChangesetNotYetClosedError, changeset if changeset.is_open? # Add a comment to the changeset comment = changeset.comments.create(:changeset => changeset, :body => body, - :author => @user) + :author => current_user) # Notify current subscribers of the new comment changeset.subscribers.visible.each do |user| - if @user != user + if current_user != user Notifier.changeset_comment_notification(comment, user).deliver_now end end # Add the commenter to the subscribers if necessary - changeset.subscribers << @user unless changeset.subscribers.exists?(@user.id) + changeset.subscribers << current_user unless changeset.subscribers.exists?(current_user.id) # Return a copy of the updated changeset render :xml => changeset.to_xml.to_s @@ -344,18 +344,18 @@ class ChangesetController < ApplicationController # Adds a subscriber to the changeset def subscribe # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Extract the arguments id = params[:id].to_i # Find the changeset and check it is valid changeset = Changeset.find(id) - raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open? - raise OSM::APIChangesetAlreadySubscribedError.new(changeset) if changeset.subscribers.exists?(@user.id) + raise OSM::APIChangesetNotYetClosedError, changeset if changeset.is_open? + raise OSM::APIChangesetAlreadySubscribedError, changeset if changeset.subscribers.exists?(current_user.id) # Add the subscriber - changeset.subscribers << @user + changeset.subscribers << current_user # Return a copy of the updated changeset render :xml => changeset.to_xml.to_s @@ -365,18 +365,18 @@ class ChangesetController < ApplicationController # Removes a subscriber from the changeset def unsubscribe # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Extract the arguments id = params[:id].to_i # Find the changeset and check it is valid changeset = Changeset.find(id) - raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open? - raise OSM::APIChangesetNotSubscribedError.new(changeset) unless changeset.subscribers.exists?(@user.id) + raise OSM::APIChangesetNotYetClosedError, changeset if changeset.is_open? + raise OSM::APIChangesetNotSubscribedError, changeset unless changeset.subscribers.exists?(current_user.id) # Remove the subscriber - changeset.subscribers.delete(@user) + changeset.subscribers.delete(current_user) # Return a copy of the updated changeset render :xml => changeset.to_xml.to_s @@ -386,7 +386,7 @@ class ChangesetController < ApplicationController # Sets visible flag on comment to false def hide_comment # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Extract the arguments id = params[:id].to_i @@ -405,7 +405,7 @@ class ChangesetController < ApplicationController # Sets visible flag on comment to true def unhide_comment # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Extract the arguments id = params[:id].to_i @@ -434,7 +434,7 @@ class ChangesetController < ApplicationController @comments = changeset.comments.includes(:author, :changeset).limit(comments_limit) else # Return comments - @comments = ChangesetComment.includes(:author, :changeset).where(:visible => :true).order("created_at DESC").limit(comments_limit).preload(:changeset) + @comments = ChangesetComment.includes(:author, :changeset).where(:visible => true).order("created_at DESC").limit(comments_limit).preload(:changeset) end # Render the result @@ -475,19 +475,19 @@ class ChangesetController < ApplicationController changesets else # shouldn't provide both name and UID - raise OSM::APIBadUserInput.new("provide either the user ID or display name, but not both") if user && name + raise OSM::APIBadUserInput, "provide either the user ID or display name, but not both" if user && name # use either the name or the UID to find the user which we're selecting on. u = if name.nil? # user input checking, we don't have any UIDs < 1 - raise OSM::APIBadUserInput.new("invalid user ID") if user.to_i < 1 + raise OSM::APIBadUserInput, "invalid user ID" if user.to_i < 1 u = User.find(user.to_i) else u = User.find_by(:display_name => name) end # make sure we found a user - raise OSM::APINotFoundError.new if u.nil? + raise OSM::APINotFoundError if u.nil? # should be able to get changesets of public users only, or # our own changesets regardless of public-ness. @@ -496,7 +496,7 @@ class ChangesetController < ApplicationController # changesets if they're non-public setup_user_auth - raise OSM::APINotFoundError if @user.nil? || @user.id != u.id + raise OSM::APINotFoundError if current_user.nil? || current_user.id != u.id end changesets.where(:user_id => u.id) @@ -514,7 +514,7 @@ class ChangesetController < ApplicationController # check that we actually have 2 elements in the array times = time.split(/,/) - raise OSM::APIBadUserInput.new("bad time range") if times.size != 2 + raise OSM::APIBadUserInput, "bad time range" if times.size != 2 from, to = times.collect { |t| DateTime.parse(t) } return changesets.where("closed_at >= ? and created_at <= ?", from, to) @@ -525,9 +525,9 @@ class ChangesetController < ApplicationController # stupid DateTime seems to throw both of these for bad parsing, so # we have to catch both and ensure the correct code path is taken. rescue ArgumentError => ex - raise OSM::APIBadUserInput.new(ex.message.to_s) + raise OSM::APIBadUserInput, ex.message.to_s rescue RuntimeError => ex - raise OSM::APIBadUserInput.new(ex.message.to_s) + raise OSM::APIBadUserInput, ex.message.to_s end ## @@ -563,7 +563,7 @@ class ChangesetController < ApplicationController if ids.nil? changesets elsif ids.empty? - raise OSM::APIBadUserInput.new("No changesets were given to search for") + raise OSM::APIBadUserInput, "No changesets were given to search for" else ids = ids.split(",").collect(&:to_i) changesets.where(:id => ids) @@ -584,7 +584,7 @@ class ChangesetController < ApplicationController if params[:limit].to_i > 0 && params[:limit].to_i <= 10000 params[:limit].to_i else - raise OSM::APIBadUserInput.new("Comments limit must be between 1 and 10000") + raise OSM::APIBadUserInput, "Comments limit must be between 1 and 10000" end else 100 diff --git a/app/controllers/diary_entry_controller.rb b/app/controllers/diary_entry_controller.rb index 1635dc0d0..b3518872c 100644 --- a/app/controllers/diary_entry_controller.rb +++ b/app/controllers/diary_entry_controller.rb @@ -14,27 +14,27 @@ class DiaryEntryController < ApplicationController if request.post? @diary_entry = DiaryEntry.new(entry_params) - @diary_entry.user = @user + @diary_entry.user = current_user if @diary_entry.save - default_lang = @user.preferences.where(:k => "diary.default_language").first + default_lang = current_user.preferences.where(:k => "diary.default_language").first if default_lang default_lang.v = @diary_entry.language_code default_lang.save! else - @user.preferences.create(:k => "diary.default_language", :v => @diary_entry.language_code) + current_user.preferences.create(:k => "diary.default_language", :v => @diary_entry.language_code) end # Subscribe user to diary comments - @diary_entry.subscriptions.create(:user => @user) + @diary_entry.subscriptions.create(:user => current_user) - redirect_to :action => "list", :display_name => @user.display_name + redirect_to :action => "list", :display_name => current_user.display_name else render :action => "edit" end else - default_lang = @user.preferences.where(:k => "diary.default_language").first - lang_code = default_lang ? default_lang.v : @user.preferred_language + default_lang = current_user.preferences.where(:k => "diary.default_language").first + lang_code = default_lang ? default_lang.v : current_user.preferred_language @diary_entry = DiaryEntry.new(entry_params.merge(:language_code => lang_code)) set_map_location render :action => "edit" @@ -45,7 +45,7 @@ class DiaryEntryController < ApplicationController @title = t "diary_entry.edit.title" @diary_entry = DiaryEntry.find(params[:id]) - if @user != @diary_entry.user + if current_user != @diary_entry.user redirect_to :action => "view", :id => params[:id] elsif params[:diary_entry] && @diary_entry.update_attributes(entry_params) redirect_to :action => "view", :id => params[:id] @@ -59,18 +59,18 @@ class DiaryEntryController < ApplicationController def comment @entry = DiaryEntry.find(params[:id]) @diary_comment = @entry.comments.build(comment_params) - @diary_comment.user = @user + @diary_comment.user = current_user if @diary_comment.save # Notify current subscribers of the new comment @entry.subscribers.visible.each do |user| - if @user != user + if current_user != user Notifier.diary_comment_notification(@diary_comment, user).deliver_now end end # Add the commenter to the subscribers if necessary - @entry.subscriptions.create(:user => @user) unless @entry.subscribers.exists?(@user.id) + @entry.subscriptions.create(:user => current_user) unless @entry.subscribers.exists?(current_user.id) redirect_to :action => "view", :display_name => @entry.user.display_name, :id => @entry.id else @@ -83,7 +83,7 @@ class DiaryEntryController < ApplicationController def subscribe diary_entry = DiaryEntry.find(params[:id]) - diary_entry.subscriptions.create(:user => @user) unless diary_entry.subscribers.exists?(@user.id) + diary_entry.subscriptions.create(:user => current_user) unless diary_entry.subscribers.exists?(current_user.id) redirect_to :action => "view", :display_name => diary_entry.user.display_name, :id => diary_entry.id rescue ActiveRecord::RecordNotFound @@ -93,7 +93,7 @@ class DiaryEntryController < ApplicationController def unsubscribe diary_entry = DiaryEntry.find(params[:id]) - diary_entry.subscriptions.where(:user => @user).delete_all if diary_entry.subscribers.exists?(@user.id) + diary_entry.subscriptions.where(:user => current_user).delete_all if diary_entry.subscribers.exists?(current_user.id) redirect_to :action => "view", :display_name => diary_entry.user.display_name, :id => diary_entry.id rescue ActiveRecord::RecordNotFound @@ -112,17 +112,17 @@ class DiaryEntryController < ApplicationController return end elsif params[:friends] - if @user + if current_user @title = t "diary_entry.list.title_friends" - @entries = DiaryEntry.where(:user_id => @user.friend_users) + @entries = DiaryEntry.where(:user_id => current_user.friend_users) else require_user return end elsif params[:nearby] - if @user + if current_user @title = t "diary_entry.list.title_nearby" - @entries = DiaryEntry.where(:user_id => @user.nearby) + @entries = DiaryEntry.where(:user_id => current_user.nearby) else require_user return @@ -234,7 +234,7 @@ class DiaryEntryController < ApplicationController # require that the user is a administrator, or fill out a helpful error message # and return them to the user page. def require_administrator - unless @user.administrator? + unless current_user.administrator? flash[:error] = t("user.filter.not_an_administrator") redirect_to :action => "view" end @@ -247,13 +247,13 @@ class DiaryEntryController < ApplicationController @lon = @diary_entry.longitude @lat = @diary_entry.latitude @zoom = 12 - elsif @user.home_lat.nil? || @user.home_lon.nil? + elsif current_user.home_lat.nil? || current_user.home_lon.nil? @lon = params[:lon] || -0.1 @lat = params[:lat] || 51.5 @zoom = params[:zoom] || 4 else - @lon = @user.home_lon - @lat = @user.home_lat + @lon = current_user.home_lon + @lat = current_user.home_lat @zoom = 12 end end diff --git a/app/controllers/geocoder_controller.rb b/app/controllers/geocoder_controller.rb index 6ec2d46f8..6110baead 100644 --- a/app/controllers/geocoder_controller.rb +++ b/app/controllers/geocoder_controller.rb @@ -1,5 +1,3 @@ -# coding: utf-8 - class GeocoderController < ApplicationController require "cgi" require "uri" @@ -19,7 +17,6 @@ class GeocoderController < ApplicationController @sources.push "geonames_reverse" if defined?(GEONAMES_USERNAME) elsif @params[:query] if @params[:query] =~ /^\d{5}(-\d{4})?$/ - @sources.push "us_postcode" @sources.push "osm_nominatim" elsif @params[:query] =~ /^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s*[0-9][ABD-HJLNP-UW-Z]{2})$/i @sources.push "uk_postcode" @@ -58,31 +55,6 @@ class GeocoderController < ApplicationController end end - def search_us_postcode - # get query parameters - query = params[:query] - - # create result array - @results = [] - - # ask geocoder.us (they have a non-commercial use api) - response = fetch_text("http://rpc.geocoder.us/service/csv?zip=#{escape_query(query)}") - - # parse the response - unless response =~ /couldn't find this zip/ - data = response.split(/\s*,\s+/) # lat,long,town,state,zip - @results.push(:lat => data[0], :lon => data[1], - :zoom => POSTCODE_ZOOM, - :prefix => "#{data[2]}, #{data[3]},", - :name => data[4]) - end - - render :action => "results" - rescue StandardError => ex - @error = "Error contacting rpc.geocoder.us: #{ex}" - render :action => "error" - end - def search_uk_postcode # get query parameters query = params[:query] @@ -313,7 +285,7 @@ class GeocoderController < ApplicationController end def escape_query(query) - URI.escape(query, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]", false, "N")) + CGI.escape(query) end def normalize_params @@ -348,7 +320,7 @@ class GeocoderController < ApplicationController Float(captures[0]) lat = !captures[2].casecmp("s").zero? ? captures[0].to_f : -captures[0].to_f lon = !captures[5].casecmp("w").zero? ? captures[3].to_f : -captures[3].to_f - rescue + rescue StandardError lat = !captures[0].casecmp("s").zero? ? captures[1].to_f : -captures[1].to_f lon = !captures[3].casecmp("w").zero? ? captures[4].to_f : -captures[4].to_f end @@ -360,7 +332,7 @@ class GeocoderController < ApplicationController Float(captures[0]) lat = !captures[3].casecmp("s").zero? ? captures[0].to_f + captures[1].to_f / 60 : -(captures[0].to_f + captures[1].to_f / 60) lon = !captures[7].casecmp("w").zero? ? captures[4].to_f + captures[5].to_f / 60 : -(captures[4].to_f + captures[5].to_f / 60) - rescue + rescue StandardError lat = !captures[0].casecmp("s").zero? ? captures[1].to_f + captures[2].to_f / 60 : -(captures[1].to_f + captures[2].to_f / 60) lon = !captures[4].casecmp("w").zero? ? captures[5].to_f + captures[6].to_f / 60 : -(captures[5].to_f + captures[6].to_f / 60) end @@ -372,7 +344,7 @@ class GeocoderController < ApplicationController Float(captures[0]) lat = !captures[4].casecmp("s").zero? ? captures[0].to_f + (captures[1].to_f + captures[2].to_f / 60) / 60 : -(captures[0].to_f + (captures[1].to_f + captures[2].to_f / 60) / 60) lon = !captures[9].casecmp("w").zero? ? captures[5].to_f + (captures[6].to_f + captures[7].to_f / 60) / 60 : -(captures[5].to_f + (captures[6].to_f + captures[7].to_f / 60) / 60) - rescue + rescue StandardError lat = !captures[0].casecmp("s").zero? ? captures[1].to_f + (captures[2].to_f + captures[3].to_f / 60) / 60 : -(captures[1].to_f + (captures[2].to_f + captures[3].to_f / 60) / 60) lon = !captures[5].casecmp("w").zero? ? captures[6].to_f + (captures[7].to_f + captures[8].to_f / 60) / 60 : -(captures[6].to_f + (captures[7].to_f + captures[8].to_f / 60) / 60) end diff --git a/app/controllers/message_controller.rb b/app/controllers/message_controller.rb index 450313e62..9b39f1c05 100644 --- a/app/controllers/message_controller.rb +++ b/app/controllers/message_controller.rb @@ -14,18 +14,18 @@ class MessageController < ApplicationController # The display_name param is the display name of the user that the message is being sent to. def new if request.post? - if @user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= MAX_MESSAGES_PER_HOUR + if current_user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= MAX_MESSAGES_PER_HOUR flash[:error] = t "message.new.limit_exceeded" else @message = Message.new(message_params) @message.to_user_id = @this_user.id - @message.from_user_id = @user.id + @message.from_user_id = current_user.id @message.sent_on = Time.now.getutc if @message.save flash[:notice] = t "message.new.message_sent" Notifier.message_notification(@message).deliver_now - redirect_to :action => "inbox", :display_name => @user.display_name + redirect_to :action => "inbox", :display_name => current_user.display_name end end end @@ -38,7 +38,7 @@ class MessageController < ApplicationController def reply message = Message.find(params[:message_id]) - if message.to_user_id == @user.id + if message.to_user_id == current_user.id message.update(:message_read => true) @message = Message.new( @@ -51,7 +51,7 @@ class MessageController < ApplicationController render :action => "new" else - flash[:notice] = t "message.reply.wrong_user", :user => @user.display_name + flash[:notice] = t "message.reply.wrong_user", :user => current_user.display_name redirect_to :controller => "user", :action => "login", :referer => request.fullpath end rescue ActiveRecord::RecordNotFound @@ -64,11 +64,11 @@ class MessageController < ApplicationController @title = t "message.read.title" @message = Message.find(params[:message_id]) - if @message.to_user_id == @user.id || @message.from_user_id == @user.id - @message.message_read = true if @message.to_user_id == @user.id + if @message.to_user_id == current_user.id || @message.from_user_id == current_user.id + @message.message_read = true if @message.to_user_id == current_user.id @message.save else - flash[:notice] = t "message.read.wrong_user", :user => @user.display_name + flash[:notice] = t "message.read.wrong_user", :user => current_user.display_name redirect_to :controller => "user", :action => "login", :referer => request.fullpath end rescue ActiveRecord::RecordNotFound @@ -79,24 +79,24 @@ class MessageController < ApplicationController # Display the list of messages that have been sent to the user. def inbox @title = t "message.inbox.title" - if @user && params[:display_name] == @user.display_name + if current_user && params[:display_name] == current_user.display_name else - redirect_to :action => "inbox", :display_name => @user.display_name + redirect_to :action => "inbox", :display_name => current_user.display_name end end # Display the list of messages that the user has sent to other users. def outbox @title = t "message.outbox.title" - if @user && params[:display_name] == @user.display_name + if current_user && params[:display_name] == current_user.display_name else - redirect_to :action => "outbox", :display_name => @user.display_name + redirect_to :action => "outbox", :display_name => current_user.display_name end end # Set the message as being read or unread. def mark - @message = Message.where("to_user_id = ? OR from_user_id = ?", @user.id, @user.id).find(params[:message_id]) + @message = Message.where("to_user_id = ? OR from_user_id = ?", current_user.id, current_user.id).find(params[:message_id]) if params[:mark] == "unread" message_read = false notice = t "message.mark.as_unread" @@ -107,7 +107,7 @@ class MessageController < ApplicationController @message.message_read = message_read if @message.save && !request.xhr? flash[:notice] = notice - redirect_to :action => "inbox", :display_name => @user.display_name + redirect_to :action => "inbox", :display_name => current_user.display_name end rescue ActiveRecord::RecordNotFound @title = t "message.no_such_message.title" @@ -116,16 +116,16 @@ class MessageController < ApplicationController # Delete the message. def delete - @message = Message.where("to_user_id = ? OR from_user_id = ?", @user.id, @user.id).find(params[:message_id]) - @message.from_user_visible = false if @message.sender == @user - @message.to_user_visible = false if @message.recipient == @user + @message = Message.where("to_user_id = ? OR from_user_id = ?", current_user.id, current_user.id).find(params[:message_id]) + @message.from_user_visible = false if @message.sender == current_user + @message.to_user_visible = false if @message.recipient == current_user if @message.save && !request.xhr? flash[:notice] = t "message.delete.deleted" if params[:referer] redirect_to params[:referer] else - redirect_to :action => "inbox", :display_name => @user.display_name + redirect_to :action => "inbox", :display_name => current_user.display_name end end rescue ActiveRecord::RecordNotFound diff --git a/app/controllers/node_controller.rb b/app/controllers/node_controller.rb index 9f6703b07..29651bceb 100644 --- a/app/controllers/node_controller.rb +++ b/app/controllers/node_controller.rb @@ -18,7 +18,7 @@ class NodeController < ApplicationController node = Node.from_xml(request.raw_post, true) # Assume that Node.from_xml has thrown an exception if there is an error parsing the xml - node.create_with_history @user + node.create_with_history current_user render :plain => node.id.to_s end @@ -41,10 +41,10 @@ class NodeController < ApplicationController new_node = Node.from_xml(request.raw_post) unless new_node && new_node.id == node.id - raise OSM::APIBadUserInput.new("The id in the url (#{node.id}) is not the same as provided in the xml (#{new_node.id})") + raise OSM::APIBadUserInput, "The id in the url (#{node.id}) is not the same as provided in the xml (#{new_node.id})" end - node.update_from(new_node, @user) + node.update_from(new_node, current_user) render :plain => node.version.to_s end @@ -56,22 +56,22 @@ class NodeController < ApplicationController new_node = Node.from_xml(request.raw_post) unless new_node && new_node.id == node.id - raise OSM::APIBadUserInput.new("The id in the url (#{node.id}) is not the same as provided in the xml (#{new_node.id})") + raise OSM::APIBadUserInput, "The id in the url (#{node.id}) is not the same as provided in the xml (#{new_node.id})" end - node.delete_with_history!(new_node, @user) + node.delete_with_history!(new_node, current_user) render :plain => node.version.to_s end # Dump the details on many nodes whose ids are given in the "nodes" parameter. def nodes unless params["nodes"] - raise OSM::APIBadUserInput.new("The parameter nodes is required, and must be of the form nodes=id[,id[,id...]]") + raise OSM::APIBadUserInput, "The parameter nodes is required, and must be of the form nodes=id[,id[,id...]]" end ids = params["nodes"].split(",").collect(&:to_i) if ids.empty? - raise OSM::APIBadUserInput.new("No nodes were given to search for") + raise OSM::APIBadUserInput, "No nodes were given to search for" end doc = OSM::API.new.get_xml_doc diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index 20894c4e8..92f63e304 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -20,10 +20,10 @@ class NotesController < ApplicationController 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] + raise OSM::APIBadUserInput, "No l was given" unless params[:l] + raise OSM::APIBadUserInput, "No r was given" unless params[:r] + raise OSM::APIBadUserInput, "No b was given" unless params[:b] + raise OSM::APIBadUserInput, "No t was given" unless params[:t] bbox = BoundingBox.from_lrbt_params(params) end @@ -56,9 +56,9 @@ class NotesController < ApplicationController raise OSM::APIAccessDenied if Acl.no_note_comment(request.remote_ip) # 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? + raise OSM::APIBadUserInput, "No lat was given" unless params[:lat] + raise OSM::APIBadUserInput, "No lon was given" unless params[:lon] + raise OSM::APIBadUserInput, "No text was given" if params[:text].blank? # Extract the arguments lon = OSM.parse_float(params[:lon], OSM::APIBadUserInput, "lon was not a number") @@ -69,7 +69,7 @@ class NotesController < ApplicationController 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? + raise OSM::APIBadUserInput, "The note is outside this world" unless @note.in_world? # Save the note @note.save! @@ -92,8 +92,8 @@ class NotesController < ApplicationController raise OSM::APIAccessDenied if Acl.no_note_comment(request.remote_ip) # 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? + raise OSM::APIBadUserInput, "No id was given" unless params[:id] + raise OSM::APIBadUserInput, "No text was given" if params[:text].blank? # Extract the arguments id = params[:id].to_i @@ -103,7 +103,7 @@ class NotesController < ApplicationController @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? + raise OSM::APINoteAlreadyClosedError, @note if @note.closed? # Add a comment to the note Note.transaction do @@ -121,7 +121,7 @@ class NotesController < ApplicationController # Close a note def close # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Extract the arguments id = params[:id].to_i @@ -131,7 +131,7 @@ class NotesController < ApplicationController @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? + raise OSM::APINoteAlreadyClosedError, @note if @note.closed? # Close the note and add a comment Note.transaction do @@ -151,7 +151,7 @@ class NotesController < ApplicationController # Reopen a note def reopen # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Extract the arguments id = params[:id].to_i @@ -160,8 +160,8 @@ class NotesController < ApplicationController # 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? || @user.moderator? - raise OSM::APINoteAlreadyOpenError.new(@note) unless @note.closed? || !@note.visible? + raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? || current_user.moderator? + raise OSM::APINoteAlreadyOpenError, @note unless @note.closed? || !@note.visible? # Reopen the note and add a comment Note.transaction do @@ -206,7 +206,7 @@ class NotesController < ApplicationController # Read a note def show # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Find the note and check it is valid @note = Note.find(params[:id]) @@ -226,7 +226,7 @@ class NotesController < ApplicationController # Delete (hide) a note def destroy # Check the arguments are sane - raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput, "No id was given" unless params[:id] # Extract the arguments id = params[:id].to_i @@ -256,7 +256,7 @@ class NotesController < ApplicationController # 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] + raise OSM::APIBadUserInput, "No query string was given" unless params[:q] # Get any conditions that need to be applied @notes = closed_condition(Note.all) @@ -286,7 +286,7 @@ class NotesController < ApplicationController @page = (params[:page] || 1).to_i @page_size = 10 @notes = @this_user.notes - @notes = @notes.visible unless @user && @user.moderator? + @notes = @notes.visible unless current_user && current_user.moderator? @notes = @notes.order("updated_at DESC, id").distinct.offset((@page - 1) * @page_size).limit(@page_size).preload(:comments => :author).to_a else @title = t "user.no_such_user.title" @@ -310,7 +310,7 @@ class NotesController < ApplicationController if params[:limit].to_i > 0 && params[:limit].to_i <= 10000 params[:limit].to_i else - raise OSM::APIBadUserInput.new("Note limit must be between 1 and 10000") + raise OSM::APIBadUserInput, "Note limit must be between 1 and 10000" end else 100 @@ -341,8 +341,8 @@ class NotesController < ApplicationController def add_comment(note, text, event, notify = true) attributes = { :visible => true, :event => event, :body => text } - if @user - attributes[:author_id] = @user.id + if current_user + attributes[:author_id] = current_user.id else attributes[:author_ip] = request.remote_ip end @@ -350,7 +350,7 @@ class NotesController < ApplicationController comment = note.comments.create!(attributes) note.comments.map(&:author).uniq.each do |user| - if notify && user && user != @user && user.visible? + if notify && user && user != current_user && user.visible? Notifier.note_comment_notification(comment, user).deliver_now end end diff --git a/app/controllers/oauth_clients_controller.rb b/app/controllers/oauth_clients_controller.rb index 1c1877ad4..76fdd6421 100644 --- a/app/controllers/oauth_clients_controller.rb +++ b/app/controllers/oauth_clients_controller.rb @@ -6,8 +6,8 @@ class OauthClientsController < ApplicationController before_action :require_user def index - @client_applications = @user.client_applications - @tokens = @user.oauth_tokens.authorized + @client_applications = current_user.client_applications + @tokens = current_user.oauth_tokens.authorized end def new @@ -15,7 +15,7 @@ class OauthClientsController < ApplicationController end def create - @client_application = @user.client_applications.build(application_params) + @client_application = current_user.client_applications.build(application_params) if @client_application.save flash[:notice] = t "oauth_clients.create.flash" redirect_to :action => "show", :id => @client_application.id @@ -25,21 +25,21 @@ class OauthClientsController < ApplicationController end def show - @client_application = @user.client_applications.find(params[:id]) + @client_application = current_user.client_applications.find(params[:id]) rescue ActiveRecord::RecordNotFound @type = "client application" render :action => "not_found", :status => :not_found end def edit - @client_application = @user.client_applications.find(params[:id]) + @client_application = current_user.client_applications.find(params[:id]) rescue ActiveRecord::RecordNotFound @type = "client application" render :action => "not_found", :status => :not_found end def update - @client_application = @user.client_applications.find(params[:id]) + @client_application = current_user.client_applications.find(params[:id]) if @client_application.update_attributes(application_params) flash[:notice] = t "oauth_clients.update.flash" redirect_to :action => "show", :id => @client_application.id @@ -52,7 +52,7 @@ class OauthClientsController < ApplicationController end def destroy - @client_application = @user.client_applications.find(params[:id]) + @client_application = current_user.client_applications.find(params[:id]) @client_application.destroy flash[:notice] = t "oauth_clients.destroy.flash" redirect_to :action => "index" diff --git a/app/controllers/old_controller.rb b/app/controllers/old_controller.rb index 16f1083de..9adf141d9 100644 --- a/app/controllers/old_controller.rb +++ b/app/controllers/old_controller.rb @@ -19,7 +19,7 @@ class OldController < ApplicationController # the .where() method used in the lookup_old_element_versions # call won't throw an error if no records are found, so we have # to do that ourselves. - raise OSM::APINotFoundError.new if @elements.empty? + raise OSM::APINotFoundError if @elements.empty? doc = OSM::API.new.get_xml_doc @@ -70,6 +70,6 @@ class OldController < ApplicationController private def show_redactions? - @user && @user.moderator? && params[:show_redactions] == "true" + current_user && current_user.moderator? && params[:show_redactions] == "true" end end diff --git a/app/controllers/redactions_controller.rb b/app/controllers/redactions_controller.rb index 129318191..f15060d5b 100644 --- a/app/controllers/redactions_controller.rb +++ b/app/controllers/redactions_controller.rb @@ -19,7 +19,7 @@ class RedactionsController < ApplicationController def create @redaction = Redaction.new - @redaction.user = @user + @redaction.user = current_user @redaction.title = params[:redaction][:title] @redaction.description = params[:redaction][:description] # note that the description format will default to 'markdown' diff --git a/app/controllers/relation_controller.rb b/app/controllers/relation_controller.rb index 846d623f2..80fd51997 100644 --- a/app/controllers/relation_controller.rb +++ b/app/controllers/relation_controller.rb @@ -15,7 +15,7 @@ class RelationController < ApplicationController relation = Relation.from_xml(request.raw_post, true) # Assume that Relation.from_xml has thrown an exception if there is an error parsing the xml - relation.create_with_history @user + relation.create_with_history current_user render :plain => relation.id.to_s end @@ -36,10 +36,10 @@ class RelationController < ApplicationController new_relation = Relation.from_xml(request.raw_post) unless new_relation && new_relation.id == relation.id - raise OSM::APIBadUserInput.new("The id in the url (#{relation.id}) is not the same as provided in the xml (#{new_relation.id})") + raise OSM::APIBadUserInput, "The id in the url (#{relation.id}) is not the same as provided in the xml (#{new_relation.id})" end - relation.update_from new_relation, @user + relation.update_from new_relation, current_user render :plain => relation.version.to_s end @@ -47,7 +47,7 @@ class RelationController < ApplicationController relation = Relation.find(params[:id]) new_relation = Relation.from_xml(request.raw_post) if new_relation && new_relation.id == relation.id - relation.delete_with_history!(new_relation, @user) + relation.delete_with_history!(new_relation, current_user) render :plain => relation.version.to_s else head :bad_request @@ -128,13 +128,13 @@ class RelationController < ApplicationController def relations unless params["relations"] - raise OSM::APIBadUserInput.new("The parameter relations is required, and must be of the form relations=id[,id[,id...]]") + raise OSM::APIBadUserInput, "The parameter relations is required, and must be of the form relations=id[,id[,id...]]" end ids = params["relations"].split(",").collect(&:to_i) if ids.empty? - raise OSM::APIBadUserInput.new("No relations were given to search for") + raise OSM::APIBadUserInput, "No relations were given to search for" end doc = OSM::API.new.get_xml_doc diff --git a/app/controllers/site_controller.rb b/app/controllers/site_controller.rb index 5ca5c0aab..c727f86d9 100644 --- a/app/controllers/site_controller.rb +++ b/app/controllers/site_controller.rb @@ -92,8 +92,8 @@ class SiteController < ApplicationController @lat = note.lat @lon = note.lon @zoom = 17 - elsif params[:gpx] && @user - trace = Trace.visible_to(@user).find(params[:gpx]) + elsif params[:gpx] && current_user + trace = Trace.visible_to(current_user).find(params[:gpx]) @lat = trace.latitude @lon = trace.longitude @zoom = 16 diff --git a/app/controllers/trace_controller.rb b/app/controllers/trace_controller.rb index 916a47024..105405ccf 100644 --- a/app/controllers/trace_controller.rb +++ b/app/controllers/trace_controller.rb @@ -32,7 +32,7 @@ class TraceController < ApplicationController # set title @title = if target_user.nil? t "trace.list.public_traces" - elsif @user && @user == target_user + elsif current_user && current_user == target_user t "trace.list.your_traces" else t "trace.list.public_traces_from", :user => target_user.display_name @@ -46,13 +46,13 @@ class TraceController < ApplicationController # 3 - user's traces, logged in as same user = all user's traces # 4 - user's traces, not logged in as that user = all user's public traces @traces = if target_user.nil? # all traces - if @user - Trace.visible_to(@user) # 1 + if current_user + Trace.visible_to(current_user) # 1 else Trace.visible_to_all # 2 end - elsif @user && @user == target_user - @user.traces # 3 (check vs user id, so no join + can't pick up non-public traces by changing name) + elsif current_user && current_user == target_user + current_user.traces # 3 (check vs user id, so no join + can't pick up non-public traces by changing name) else target_user.traces.visible_to_all # 4 end @@ -86,14 +86,14 @@ class TraceController < ApplicationController end def mine - redirect_to :action => :list, :display_name => @user.display_name + redirect_to :action => :list, :display_name => current_user.display_name end def view @trace = Trace.find(params[:id]) if @trace && @trace.visible? && - (@trace.public? || @trace.user == @user) + (@trace.public? || @trace.user == current_user) @title = t "trace.view.title", :name => @trace.name else flash[:error] = t "trace.view.trace_not_found" @@ -112,25 +112,25 @@ class TraceController < ApplicationController begin do_create(params[:trace][:gpx_file], params[:trace][:tagstring], params[:trace][:description], params[:trace][:visibility]) - rescue => ex + rescue StandardError => ex logger.debug ex end if @trace.id flash[:notice] = t "trace.create.trace_uploaded" - if @user.traces.where(:inserted => false).count > 4 - flash[:warning] = t "trace.trace_header.traces_waiting", :count => @user.traces.where(:inserted => false).count + if current_user.traces.where(:inserted => false).count > 4 + flash[:warning] = t "trace.trace_header.traces_waiting", :count => current_user.traces.where(:inserted => false).count end - redirect_to :action => :list, :display_name => @user.display_name + redirect_to :action => :list, :display_name => current_user.display_name end else @trace = Trace.new(:name => "Dummy", :tagstring => params[:trace][:tagstring], :description => params[:trace][:description], :visibility => params[:trace][:visibility], - :inserted => false, :user => @user, + :inserted => false, :user => current_user, :timestamp => Time.now.getutc) @trace.valid? @trace.errors.add(:gpx_file, "can't be blank") @@ -145,13 +145,13 @@ class TraceController < ApplicationController def data trace = Trace.find(params[:id]) - if trace.visible? && (trace.public? || (@user && @user == trace.user)) + if trace.visible? && (trace.public? || (current_user && current_user == trace.user)) if Acl.no_trace_download(request.remote_ip) head :forbidden elsif request.format == Mime[:xml] - send_file(trace.xml_file, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment") + send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment") elsif request.format == Mime[:gpx] - send_file(trace.xml_file, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment") + send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment") else send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment") end @@ -167,7 +167,7 @@ class TraceController < ApplicationController if !@trace.visible? head :not_found - elsif @user.nil? || @trace.user != @user + elsif current_user.nil? || @trace.user != current_user head :forbidden else @title = t "trace.edit.title", :name => @trace.name @@ -177,7 +177,7 @@ class TraceController < ApplicationController @trace.tagstring = params[:trace][:tagstring] @trace.visibility = params[:trace][:visibility] if @trace.save - redirect_to :action => "view", :display_name => @user.display_name + redirect_to :action => "view", :display_name => current_user.display_name end end end @@ -190,13 +190,13 @@ class TraceController < ApplicationController if !trace.visible? head :not_found - elsif @user.nil? || trace.user != @user + elsif current_user.nil? || trace.user != current_user head :forbidden else trace.visible = false trace.save flash[:notice] = t "trace.delete.scheduled_for_deletion" - redirect_to :action => :list, :display_name => @user.display_name + redirect_to :action => :list, :display_name => current_user.display_name end rescue ActiveRecord::RecordNotFound head :not_found @@ -219,7 +219,7 @@ class TraceController < ApplicationController trace = Trace.find(params[:id]) if trace.visible? && trace.inserted? - if trace.public? || (@user && @user == trace.user) + if trace.public? || (current_user && current_user == trace.user) expires_in 7.days, :private => !trace.public?, :public => trace.public? send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => "image/gif", :disposition => "inline") else @@ -236,7 +236,7 @@ class TraceController < ApplicationController trace = Trace.find(params[:id]) if trace.visible? && trace.inserted? - if trace.public? || (@user && @user == trace.user) + if trace.public? || (current_user && current_user == trace.user) expires_in 7.days, :private => !trace.public?, :public => trace.public? send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => "image/gif", :disposition => "inline") else @@ -252,7 +252,7 @@ class TraceController < ApplicationController def api_read trace = Trace.visible.find(params[:id]) - if trace.public? || trace.user == @user + if trace.public? || trace.user == current_user render :xml => trace.to_xml.to_s else head :forbidden @@ -262,16 +262,8 @@ class TraceController < ApplicationController def api_update trace = Trace.visible.find(params[:id]) - if trace.user == @user - new_trace = Trace.from_xml(request.raw_post) - - unless new_trace && new_trace.id == trace.id - raise OSM::APIBadUserInput.new("The id in the url (#{trace.id}) is not the same as provided in the xml (#{new_trace.id})") - end - - trace.description = new_trace.description - trace.tags = new_trace.tags - trace.visibility = new_trace.visibility + if trace.user == current_user + trace.update_from_xml(request.raw_post) trace.save! head :ok @@ -283,7 +275,7 @@ class TraceController < ApplicationController def api_delete trace = Trace.visible.find(params[:id]) - if trace.user == @user + if trace.user == current_user trace.visible = false trace.save! @@ -296,11 +288,11 @@ class TraceController < ApplicationController def api_data trace = Trace.visible.find(params[:id]) - if trace.public? || trace.user == @user + if trace.public? || trace.user == current_user if request.format == Mime[:xml] - send_file(trace.xml_file, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment") + send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment") elsif request.format == Mime[:gpx] - send_file(trace.xml_file, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment") + send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment") else send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment") end @@ -357,7 +349,7 @@ class TraceController < ApplicationController :description => description, :visibility => visibility, :inserted => true, - :user => @user, + :user => current_user, :timestamp => Time.now.getutc ) @@ -390,11 +382,11 @@ class TraceController < ApplicationController end # Finally save the user's preferred privacy level - if pref = @user.preferences.where(:k => "gps.trace.visibility").first + if pref = current_user.preferences.where(:k => "gps.trace.visibility").first pref.v = visibility pref.save else - @user.preferences.create(:k => "gps.trace.visibility", :v => visibility) + current_user.preferences.create(:k => "gps.trace.visibility", :v => visibility) end end @@ -407,11 +399,11 @@ class TraceController < ApplicationController end def default_visibility - visibility = @user.preferences.where(:k => "gps.trace.visibility").first + visibility = current_user.preferences.where(:k => "gps.trace.visibility").first if visibility visibility.v - elsif @user.preferences.where(:k => "gps.trace.public", :v => "default").first.nil? + elsif current_user.preferences.where(:k => "gps.trace.public", :v => "default").first.nil? "private" else "public" diff --git a/app/controllers/user_blocks_controller.rb b/app/controllers/user_blocks_controller.rb index ea5cdab10..45cd53728 100644 --- a/app/controllers/user_blocks_controller.rb +++ b/app/controllers/user_blocks_controller.rb @@ -20,7 +20,7 @@ class UserBlocksController < ApplicationController end def show - if @user && @user.id == @user_block.user_id + if current_user && current_user.id == @user_block.user_id @user_block.needs_view = false @user_block.save! end @@ -38,7 +38,7 @@ class UserBlocksController < ApplicationController if @valid_params @user_block = UserBlock.new( :user_id => @this_user.id, - :creator_id => @user.id, + :creator_id => current_user.id, :reason => params[:user_block][:reason], :ends_at => Time.now.getutc + @block_period.hours, :needs_view => params[:user_block][:needs_view] @@ -57,7 +57,7 @@ class UserBlocksController < ApplicationController def update if @valid_params - if @user_block.creator_id != @user.id + if @user_block.creator_id != current_user.id flash[:error] = t("user_block.update.only_creator_can_edit") redirect_to :action => "edit" elsif @user_block.update_attributes( @@ -79,7 +79,7 @@ class UserBlocksController < ApplicationController # revokes the block, setting the end_time to now def revoke if params[:confirm] - if @user_block.revoke! @user + if @user_block.revoke! current_user flash[:notice] = t "user_block.revoke.flash" redirect_to(@user_block) end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 82373c90a..e418e103f 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -28,10 +28,10 @@ class UserController < ApplicationController else @title = t "user.terms.title" - if @user && @user.terms_agreed? + if current_user && current_user.terms_agreed? # Already agreed to terms, so just show settings - redirect_to :action => :account, :display_name => @user.display_name - elsif @user.nil? && session[:new_user].nil? + redirect_to :action => :account, :display_name => current_user.display_name + elsif current_user.nil? && session[:new_user].nil? redirect_to :action => :login, :referer => request.fullpath end end @@ -41,52 +41,52 @@ class UserController < ApplicationController @title = t "user.new.title" if params[:decline] - if @user - @user.terms_seen = true + if current_user + current_user.terms_seen = true - if @user.save + if current_user.save flash[:notice] = t("user.new.terms declined", :url => t("user.new.terms declined url")).html_safe end if params[:referer] redirect_to params[:referer] else - redirect_to :action => :account, :display_name => @user.display_name + redirect_to :action => :account, :display_name => current_user.display_name end else redirect_to t("user.terms.declined") end - elsif @user - unless @user.terms_agreed? - @user.consider_pd = params[:user][:consider_pd] - @user.terms_agreed = Time.now.getutc - @user.terms_seen = true + elsif current_user + unless current_user.terms_agreed? + current_user.consider_pd = params[:user][:consider_pd] + current_user.terms_agreed = Time.now.getutc + current_user.terms_seen = true - flash[:notice] = t "user.new.terms accepted" if @user.save + flash[:notice] = t "user.new.terms accepted" if current_user.save end if params[:referer] redirect_to params[:referer] else - redirect_to :action => :account, :display_name => @user.display_name + redirect_to :action => :account, :display_name => current_user.display_name end else - @user = session.delete(:new_user) - - if check_signup_allowed(@user.email) - @user.data_public = true - @user.description = "" if @user.description.nil? - @user.creation_ip = request.remote_ip - @user.languages = http_accept_language.user_preferred_languages - @user.terms_agreed = Time.now.getutc - @user.terms_seen = true - - if @user.auth_uid.blank? - @user.auth_provider = nil - @user.auth_uid = nil + self.current_user = session.delete(:new_user) + + if check_signup_allowed(current_user.email) + current_user.data_public = true + current_user.description = "" if current_user.description.nil? + current_user.creation_ip = request.remote_ip + current_user.languages = http_accept_language.user_preferred_languages + current_user.terms_agreed = Time.now.getutc + current_user.terms_seen = true + + if current_user.auth_uid.blank? + current_user.auth_provider = nil + current_user.auth_uid = nil end - if @user.save + if current_user.save flash[:piwik_goal] = PIWIK["goals"]["signup"] if defined?(PIWIK) referer = welcome_path @@ -99,17 +99,17 @@ class UserController < ApplicationController "lat" => m[2], "lon" => m[3] }.merge(editor)) end - rescue + rescue StandardError # Use default end - if @user.status == "active" + if current_user.status == "active" session[:referer] = referer - successful_login(@user) + successful_login(current_user) else - session[:token] = @user.tokens.create.token - Notifier.signup_confirm(@user, @user.tokens.create(:referer => referer)).deliver_now - redirect_to :action => "confirm", :display_name => @user.display_name + session[:token] = current_user.tokens.create.token + Notifier.signup_confirm(current_user, current_user.tokens.create(:referer => referer)).deliver_now + redirect_to :action => "confirm", :display_name => current_user.display_name end else render :action => "new", :referer => params[:referer] @@ -120,29 +120,29 @@ class UserController < ApplicationController def account @title = t "user.account.title" - @tokens = @user.oauth_tokens.authorized + @tokens = current_user.oauth_tokens.authorized if params[:user] && params[:user][:display_name] && params[:user][:description] if params[:user][:auth_provider].blank? || - (params[:user][:auth_provider] == @user.auth_provider && - params[:user][:auth_uid] == @user.auth_uid) - update_user(@user, params) + (params[:user][:auth_provider] == current_user.auth_provider && + params[:user][:auth_uid] == current_user.auth_uid) + update_user(current_user, params) else session[:new_user_settings] = params redirect_to auth_url(params[:user][:auth_provider], params[:user][:auth_uid]) end elsif errors = session.delete(:user_errors) errors.each do |attribute, error| - @user.errors.add(attribute, error) + current_user.errors.add(attribute, error) end end end def go_public - @user.data_public = true - @user.save + current_user.data_public = true + current_user.save flash[:notice] = t "user.go_public.flash success" - redirect_to :action => "account", :display_name => @user.display_name + redirect_to :action => "account", :display_name => current_user.display_name end def lost_password @@ -175,18 +175,18 @@ class UserController < ApplicationController token = UserToken.find_by(:token => params[:token]) if token - @user = token.user + self.current_user = token.user if params[:user] - @user.pass_crypt = params[:user][:pass_crypt] - @user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation] - @user.status = "active" if @user.status == "pending" - @user.email_valid = true + current_user.pass_crypt = params[:user][:pass_crypt] + current_user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation] + current_user.status = "active" if current_user.status == "pending" + current_user.email_valid = true - if @user.save + if current_user.save token.destroy flash[:notice] = t "user.reset_password.flash changed" - successful_login(@user) + successful_login(current_user) end end else @@ -202,7 +202,7 @@ class UserController < ApplicationController @title = t "user.new.title" @referer = params[:referer] || session[:referer] - if @user + if current_user # The user is logged in already, so don't show them the signup # page, instead send them to the home page if @referer @@ -211,43 +211,45 @@ class UserController < ApplicationController redirect_to :controller => "site", :action => "index" end elsif params.key?(:auth_provider) && params.key?(:auth_uid) - @user = User.new(:email => params[:email], - :email_confirmation => params[:email], - :display_name => params[:nickname], - :auth_provider => params[:auth_provider], - :auth_uid => params[:auth_uid]) + self.current_user = User.new(:email => params[:email], + :email_confirmation => params[:email], + :display_name => params[:nickname], + :auth_provider => params[:auth_provider], + :auth_uid => params[:auth_uid]) flash.now[:notice] = render_to_string :partial => "auth_association" else check_signup_allowed + + self.current_user = User.new end end def create - @user = User.new(user_params) + self.current_user = User.new(user_params) - if check_signup_allowed(@user.email) + if check_signup_allowed(current_user.email) session[:referer] = params[:referer] - @user.status = "pending" + current_user.status = "pending" - if @user.auth_provider.present? && @user.pass_crypt.empty? + if current_user.auth_provider.present? && current_user.pass_crypt.empty? # We are creating an account with external authentication and # no password was specified so create a random one - @user.pass_crypt = SecureRandom.base64(16) - @user.pass_crypt_confirmation = @user.pass_crypt + current_user.pass_crypt = SecureRandom.base64(16) + current_user.pass_crypt_confirmation = current_user.pass_crypt end - if @user.invalid? + if current_user.invalid? # Something is wrong with a new user, so rerender the form render :action => "new" - elsif @user.auth_provider.present? + elsif current_user.auth_provider.present? # Verify external authenticator before moving on - session[:new_user] = @user - redirect_to auth_url(@user.auth_provider, @user.auth_uid) + session[:new_user] = current_user + redirect_to auth_url(current_user.auth_provider, current_user.auth_uid) else # Save the user record - session[:new_user] = @user + session[:new_user] = current_user redirect_to :action => :terms end end @@ -345,23 +347,23 @@ class UserController < ApplicationController if request.post? token = UserToken.find_by(:token => params[:confirm_string]) if token && token.user.new_email? - @user = token.user - @user.email = @user.new_email - @user.new_email = nil - @user.email_valid = true - gravatar_enabled = gravatar_enable(@user) - if @user.save + self.current_user = token.user + current_user.email = current_user.new_email + current_user.new_email = nil + current_user.email_valid = true + gravatar_enabled = gravatar_enable(current_user) + if current_user.save flash[:notice] = if gravatar_enabled - t("user.confirm_email.success") + " " + gravatar_status_message(@user) + t("user.confirm_email.success") + " " + gravatar_status_message(current_user) else t("user.confirm_email.success") end else - flash[:errors] = @user.errors + flash[:errors] = current_user.errors end token.destroy - session[:user] = @user.id - redirect_to :action => "account", :display_name => @user.display_name + session[:user] = current_user.id + redirect_to :action => "account", :display_name => current_user.display_name elsif token flash[:error] = t "user.confirm_email.failure" redirect_to :action => "account", :display_name => token.user.display_name @@ -380,13 +382,13 @@ class UserController < ApplicationController end def api_details - @this_user = @user + @this_user = current_user render :action => :api_read, :content_type => "text/xml" end def api_gpx_files doc = OSM::API.new.get_xml_doc - @user.traces.reload.each do |trace| + current_user.traces.reload.each do |trace| doc.root << trace.to_xml_node end render :xml => doc.to_s @@ -396,7 +398,7 @@ class UserController < ApplicationController @this_user = User.find_by(:display_name => params[:display_name]) if @this_user && - (@this_user.visible? || (@user && @user.administrator?)) + (@this_user.visible? || (current_user && current_user.administrator?)) @title = @this_user.display_name else render_unknown_user params[:display_name] @@ -409,9 +411,9 @@ class UserController < ApplicationController if @new_friend if request.post? friend = Friend.new - friend.user_id = @user.id + friend.user_id = current_user.id friend.friend_user_id = @new_friend.id - if @user.is_friends_with?(@new_friend) + if current_user.is_friends_with?(@new_friend) flash[:warning] = t "user.make_friend.already_a_friend", :name => @new_friend.display_name elsif friend.save flash[:notice] = t "user.make_friend.success", :name => @new_friend.display_name @@ -436,8 +438,8 @@ class UserController < ApplicationController if @friend if request.post? - if @user.is_friends_with?(@friend) - Friend.where(:user_id => @user.id, :friend_user_id => @friend.id).delete_all + if current_user.is_friends_with?(@friend) + Friend.where(:user_id => current_user.id, :friend_user_id => @friend.id).delete_all flash[:notice] = t "user.remove_friend.success", :name => @friend.display_name else flash[:error] = t "user.remove_friend.not_a_friend", :name => @friend.display_name @@ -514,14 +516,14 @@ class UserController < ApplicationController end if settings = session.delete(:new_user_settings) - @user.auth_provider = provider - @user.auth_uid = uid + current_user.auth_provider = provider + current_user.auth_uid = uid - update_user(@user, settings) + update_user(current_user, settings) - session[:user_errors] = @user.errors.as_json + session[:user_errors] = current_user.errors.as_json - redirect_to :action => "account", :display_name => @user.display_name + redirect_to :action => "account", :display_name => current_user.display_name elsif session[:new_user] session[:new_user].auth_provider = provider session[:new_user].auth_uid = uid @@ -547,7 +549,7 @@ class UserController < ApplicationController when "active", "confirmed" then successful_login(user, request.env["omniauth.params"]["referer"]) when "suspended" then - failed_login t("user.login.account is suspended", :webmaster => "mailto:#{SUPPORT_EMAIL}") + failed_login t("user.login.account is suspended", :webmaster => "mailto:#{SUPPORT_EMAIL}").html_safe else failed_login t("user.login.auth failure") end @@ -575,7 +577,7 @@ class UserController < ApplicationController elsif user = User.authenticate(:username => username, :password => password, :pending => true) unconfirmed_login(user) elsif User.authenticate(:username => username, :password => password, :suspended => true) - failed_login t("user.login.account is suspended", :webmaster => "mailto:#{SUPPORT_EMAIL}"), username + failed_login t("user.login.account is suspended", :webmaster => "mailto:#{SUPPORT_EMAIL}").html_safe, username else failed_login t("user.login.auth failure"), username end @@ -721,12 +723,12 @@ class UserController < ApplicationController begin Notifier.email_confirm(user, user.tokens.create).deliver_now - rescue + rescue StandardError # Ignore errors sending email end else - @user.errors.add(:new_email, @user.errors[:email]) - @user.errors.add(:email, []) + current_user.errors.add(:new_email, current_user.errors[:email]) + current_user.errors.add(:email, []) end user.restore_email! @@ -738,7 +740,7 @@ class UserController < ApplicationController # require that the user is a administrator, or fill out a helpful error message # and return them to the user page. def require_administrator - if @user && !@user.administrator? + if current_user && !current_user.administrator? flash[:error] = t("user.filter.not_an_administrator") if params[:display_name] @@ -746,7 +748,7 @@ class UserController < ApplicationController else redirect_to :action => "login", :referer => request.fullpath end - elsif !@user + elsif !current_user redirect_to :action => "login", :referer => request.fullpath end end @@ -754,7 +756,7 @@ class UserController < ApplicationController ## # require that the user in the URL is the logged in user def require_self - head :forbidden if params[:display_name] != @user.display_name + head :forbidden if params[:display_name] != current_user.display_name end ## diff --git a/app/controllers/user_preference_controller.rb b/app/controllers/user_preference_controller.rb index dd4ea8bb1..16165513a 100644 --- a/app/controllers/user_preference_controller.rb +++ b/app/controllers/user_preference_controller.rb @@ -11,7 +11,7 @@ class UserPreferenceController < ApplicationController def read doc = OSM::API.new.get_xml_doc - prefs = @user.preferences + prefs = current_user.preferences el1 = XML::Node.new "preferences" @@ -26,14 +26,14 @@ class UserPreferenceController < ApplicationController ## # return the value for a single preference def read_one - pref = UserPreference.find([@user.id, params[:preference_key]]) + pref = UserPreference.find([current_user.id, params[:preference_key]]) render :plain => pref.v.to_s end # update the entire set of preferences def update - old_preferences = @user.preferences.each_with_object({}) do |preference, preferences| + old_preferences = current_user.preferences.each_with_object({}) do |preference, preferences| preferences[preference.k] = preference end @@ -45,9 +45,9 @@ class UserPreferenceController < ApplicationController if preference = old_preferences.delete(pt["k"]) preference.v = pt["v"] elsif new_preferences.include?(pt["k"]) - raise OSM::APIDuplicatePreferenceError.new(pt["k"]) + raise OSM::APIDuplicatePreferenceError, pt["k"] else - preference = @user.preferences.build(:k => pt["k"], :v => pt["v"]) + preference = current_user.preferences.build(:k => pt["k"], :v => pt["v"]) end new_preferences[preference.k] = preference @@ -64,10 +64,10 @@ class UserPreferenceController < ApplicationController # update the value of a single preference def update_one begin - pref = UserPreference.find([@user.id, params[:preference_key]]) + pref = UserPreference.find([current_user.id, params[:preference_key]]) rescue ActiveRecord::RecordNotFound pref = UserPreference.new - pref.user = @user + pref.user = current_user pref.k = params[:preference_key] end @@ -80,7 +80,7 @@ class UserPreferenceController < ApplicationController ## # delete a single preference def delete_one - UserPreference.find([@user.id, params[:preference_key]]).delete + UserPreference.find([current_user.id, params[:preference_key]]).delete render :plain => "" end diff --git a/app/controllers/user_roles_controller.rb b/app/controllers/user_roles_controller.rb index 9c0339c7a..2f5b5a84c 100644 --- a/app/controllers/user_roles_controller.rb +++ b/app/controllers/user_roles_controller.rb @@ -10,7 +10,7 @@ class UserRolesController < ApplicationController before_action :in_role, :only => [:revoke] def grant - @this_user.roles.create(:role => @role, :granter_id => @user.id) + @this_user.roles.create(:role => @role, :granter_id => current_user.id) redirect_to :controller => "user", :action => "view", :display_name => @this_user.display_name end @@ -25,7 +25,7 @@ class UserRolesController < ApplicationController # require that the user is an administrator, or fill out a helpful error message # and return them to theuser page. def require_administrator - unless @user.administrator? + unless current_user.administrator? flash[:error] = t "user_role.filter.not_an_administrator" redirect_to :controller => "user", :action => "view", :display_name => @this_user.display_name end diff --git a/app/controllers/way_controller.rb b/app/controllers/way_controller.rb index f7f270575..e48073e10 100644 --- a/app/controllers/way_controller.rb +++ b/app/controllers/way_controller.rb @@ -15,7 +15,7 @@ class WayController < ApplicationController way = Way.from_xml(request.raw_post, true) # Assume that Way.from_xml has thrown an exception if there is an error parsing the xml - way.create_with_history @user + way.create_with_history current_user render :plain => way.id.to_s end @@ -36,10 +36,10 @@ class WayController < ApplicationController new_way = Way.from_xml(request.raw_post) unless new_way && new_way.id == way.id - raise OSM::APIBadUserInput.new("The id in the url (#{way.id}) is not the same as provided in the xml (#{new_way.id})") + raise OSM::APIBadUserInput, "The id in the url (#{way.id}) is not the same as provided in the xml (#{new_way.id})" end - way.update_from(new_way, @user) + way.update_from(new_way, current_user) render :plain => way.version.to_s end @@ -49,7 +49,7 @@ class WayController < ApplicationController new_way = Way.from_xml(request.raw_post) if new_way && new_way.id == way.id - way.delete_with_history!(new_way, @user) + way.delete_with_history!(new_way, current_user) render :plain => way.version.to_s else head :bad_request @@ -81,14 +81,12 @@ class WayController < ApplicationController def ways unless params["ways"] - raise OSM::APIBadUserInput.new("The parameter ways is required, and must be of the form ways=id[,id[,id...]]") + raise OSM::APIBadUserInput, "The parameter ways is required, and must be of the form ways=id[,id[,id...]]" end ids = params["ways"].split(",").collect(&:to_i) - if ids.empty? - raise OSM::APIBadUserInput.new("No ways were given to search for") - end + raise OSM::APIBadUserInput, "No ways were given to search for" if ids.empty? doc = OSM::API.new.get_xml_doc diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c5b08e515..d27b47f27 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -21,12 +21,12 @@ module ApplicationHelper css = "" css << ".hidden { display: none !important }" - css << ".hide_unless_logged_in { display: none !important }" unless @user - css << ".hide_if_logged_in { display: none !important }" if @user - 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 && @user.administrator? - css << ".hide_unless_moderator { display: none !important }" unless @user && @user.moderator? + css << ".hide_unless_logged_in { display: none !important }" unless current_user + css << ".hide_if_logged_in { display: none !important }" if current_user + css << ".hide_if_user_#{current_user.id} { display: none !important }" if current_user + css << ".show_if_user_#{current_user.id} { display: inline !important }" if current_user + css << ".hide_unless_administrator { display: none !important }" unless current_user && current_user.administrator? + css << ".hide_unless_moderator { display: none !important }" unless current_user && current_user.moderator? content_tag(:style, css, :type => "text/css") end @@ -107,11 +107,11 @@ module ApplicationHelper :preferred_editor => preferred_editor } - if @user - data[:user] = @user.id.to_json + if current_user + data[:user] = current_user.id.to_json - unless @user.home_lon.nil? || @user.home_lat.nil? - data[:user_home] = { :lat => @user.home_lat, :lon => @user.home_lon } + unless current_user.home_lon.nil? || current_user.home_lat.nil? + data[:user_home] = { :lat => current_user.home_lat, :lon => current_user.home_lon } end end diff --git a/app/helpers/banner_helper.rb b/app/helpers/banner_helper.rb index 4e888173b..661369454 100644 --- a/app/helpers/banner_helper.rb +++ b/app/helpers/banner_helper.rb @@ -4,7 +4,7 @@ module BannerHelper enddate = v[:enddate] begin parsed = enddate && Date.parse(enddate) - rescue + rescue StandardError parsed = nil end !parsed.is_a?(Date) || (parsed.is_a?(Date) && parsed.past?) diff --git a/app/helpers/browse_helper.rb b/app/helpers/browse_helper.rb index 998ea405f..c4ce41b06 100644 --- a/app/helpers/browse_helper.rb +++ b/app/helpers/browse_helper.rb @@ -1,4 +1,4 @@ -require "uri" +require "cgi" module BrowseHelper def printable_name(object, version = false) @@ -114,9 +114,9 @@ module BrowseHelper # the correct page. lookup_us = lookup.tr(" ", "_") - if page = WIKI_PAGES[locale][type][lookup_us] rescue nil + if page = WIKI_PAGES.dig(locale, type, lookup_us) url = "http://wiki.openstreetmap.org/wiki/#{page}?uselang=#{locale}" - elsif page = WIKI_PAGES["en"][type][lookup_us] rescue nil + elsif page = WIKI_PAGES.dig("en", type, lookup_us) url = "http://wiki.openstreetmap.org/wiki/#{page}?uselang=#{locale}" end @@ -151,7 +151,7 @@ module BrowseHelper # Must break it up to correctly build the url value = Regexp.last_match(1) section = "#" + Regexp.last_match(2) - encoded_section = "#" + URI.encode(Regexp.last_match(2).gsub(/ +/, "_"), /[^A-Za-z0-9:_]/).tr("%", ".") + encoded_section = "#" + CGI.escape(Regexp.last_match(2).gsub(/ +/, "_")).tr("%", ".") else section = "" encoded_section = "" diff --git a/app/helpers/title_helper.rb b/app/helpers/title_helper.rb index 8b1eb53b6..ebe5c3a26 100644 --- a/app/helpers/title_helper.rb +++ b/app/helpers/title_helper.rb @@ -8,10 +8,10 @@ module TitleHelper def set_title(title = nil) if title @title = TitleHelper.coder.decode(title.gsub("", "\u202a").gsub("", "\u202c")) - response.headers["X-Page-Title"] = URI.escape(t("layouts.project_name.title") + " | " + @title) + response.headers["X-Page-Title"] = ERB::Util.u(t("layouts.project_name.title") + " | " + @title) else @title = title - response.headers["X-Page-Title"] = URI.escape(t("layouts.project_name.title")) + response.headers["X-Page-Title"] = ERB::Util.u(t("layouts.project_name.title")) end end end diff --git a/app/helpers/user_roles_helper.rb b/app/helpers/user_roles_helper.rb index 7093a96b2..805abb58f 100644 --- a/app/helpers/user_roles_helper.rb +++ b/app/helpers/user_roles_helper.rb @@ -6,7 +6,7 @@ module UserRolesHelper end def role_icon(user, role) - if @user && @user.administrator? + if current_user && current_user.administrator? if user.has_role?(role) image = "roles/#{role}" alt = t("user.view.role.revoke.#{role}") diff --git a/app/models/changeset.rb b/app/models/changeset.rb index f41ad9955..a4daab801 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -133,7 +133,7 @@ class Changeset < ActiveRecord::Base attr_writer :tags def add_tag_keyval(k, v) - @tags = {} unless @tags + @tags ||= {} # duplicate tags are now forbidden, so we can't allow values # in the hash to be overwritten. @@ -241,10 +241,10 @@ class Changeset < ActiveRecord::Base # bounding box, only the tags of the changeset. def update_from(other, user) # ensure that only the user who opened the changeset may modify it. - raise OSM::APIUserChangesetMismatchError.new unless user.id == user_id + raise OSM::APIUserChangesetMismatchError unless user.id == user_id # can't change a closed changeset - raise OSM::APIChangesetAlreadyClosedError.new(self) unless is_open? + raise OSM::APIChangesetAlreadyClosedError, self unless is_open? # copy the other's tags self.tags = other.tags diff --git a/app/models/node.rb b/app/models/node.rb index f4367e459..edbbbc251 100644 --- a/app/models/node.rb +++ b/app/models/node.rb @@ -70,7 +70,7 @@ class Node < ActiveRecord::Base raise OSM::APIBadXMLError.new("node", pt, "Changeset id is missing") if pt["changeset"].nil? node.changeset_id = pt["changeset"].to_i - raise OSM::APIBadUserInput.new("The node is outside this world") unless node.in_world? + raise OSM::APIBadUserInput, "The node is outside this world" unless node.in_world? # version must be present unless creating raise OSM::APIBadXMLError.new("node", pt, "Version is required when updating") unless create || !pt["version"].nil? @@ -81,7 +81,7 @@ class Node < ActiveRecord::Base node.id = pt["id"].to_i # .to_i will return 0 if there is no number that can be parsed. # We want to make sure that there is no id with zero anyway - raise OSM::APIBadUserInput.new("ID of node cannot be zero when updating.") if node.id.zero? + raise OSM::APIBadUserInput, "ID of node cannot be zero when updating." if node.id.zero? end # We don't care about the time, as it is explicitly set on create/update/delete @@ -120,10 +120,10 @@ class Node < ActiveRecord::Base lock! check_consistency(self, new_node, user) ways = Way.joins(:way_nodes).where(:visible => true, :current_way_nodes => { :node_id => id }).order(:id) - raise OSM::APIPreconditionFailedError.new("Node #{id} is still used by ways #{ways.collect(&:id).join(',')}.") unless ways.empty? + raise OSM::APIPreconditionFailedError, "Node #{id} is still used by ways #{ways.collect(&:id).join(',')}." unless ways.empty? rels = Relation.joins(:relation_members).where(:visible => true, :current_relation_members => { :member_type => "Node", :member_id => id }).order(:id) - raise OSM::APIPreconditionFailedError.new("Node #{id} is still used by relations #{rels.collect(&:id).join(',')}.") unless rels.empty? + raise OSM::APIPreconditionFailedError, "Node #{id} is still used by relations #{rels.collect(&:id).join(',')}." unless rels.empty? self.changeset_id = new_node.changeset_id self.tags = {} @@ -205,7 +205,7 @@ class Node < ActiveRecord::Base attr_writer :tags def add_tag_key_val(k, v) - @tags = {} unless @tags + @tags ||= {} # duplicate tags are now forbidden, so we can't allow values # in the hash to be overwritten. diff --git a/app/models/oauth2_token.rb b/app/models/oauth2_token.rb index 1e67194fe..2c0b1f508 100644 --- a/app/models/oauth2_token.rb +++ b/app/models/oauth2_token.rb @@ -9,9 +9,9 @@ class Oauth2Token < AccessToken def to_query q = "access_token=#{token}&token_type=bearer" - q << "&state=#{URI.escape(state)}" if @state + q << "&state=#{CGI.escape(state)}" if @state q << "&expires_in=#{expires_in}" if expires_at - q << "&scope=#{URI.escape(scope)}" if scope + q << "&scope=#{CGI.escape(scope)}" if scope q end diff --git a/app/models/oauth2_verifier.rb b/app/models/oauth2_verifier.rb index a404d0c7a..1568cac99 100644 --- a/app/models/oauth2_verifier.rb +++ b/app/models/oauth2_verifier.rb @@ -21,7 +21,7 @@ class Oauth2Verifier < OauthToken def to_query q = "code=#{token}" - q << "&state=#{URI.escape(state)}" if @state + q << "&state=#{CGI.escape(state)}" if @state q end diff --git a/app/models/relation.rb b/app/models/relation.rb index d2490dbae..545336793 100644 --- a/app/models/relation.rb +++ b/app/models/relation.rb @@ -60,7 +60,7 @@ class Relation < ActiveRecord::Base relation.id = pt["id"].to_i # .to_i will return 0 if there is no number that can be parsed. # We want to make sure that there is no id with zero anyway - raise OSM::APIBadUserInput.new("ID of relation cannot be zero when updating.") if relation.id.zero? + raise OSM::APIBadUserInput, "ID of relation cannot be zero when updating." if relation.id.zero? end # We don't care about the timestamp nor the visibility as these are either @@ -92,7 +92,7 @@ class Relation < ActiveRecord::Base member["role"] ||= "" # Allow the upload to not include this, in which case we default to an empty string. relation.add_member(member["type"].classify, member["ref"], member["role"]) end - raise OSM::APIBadUserInput.new("Some bad xml in relation") if relation.nil? + raise OSM::APIBadUserInput, "Some bad xml in relation" if relation.nil? relation end @@ -155,7 +155,7 @@ class Relation < ActiveRecord::Base end def add_tag_keyval(k, v) - @tags = {} unless @tags + @tags ||= {} # duplicate tags are now forbidden, so we can't allow values # in the hash to be overwritten. @@ -187,7 +187,7 @@ class Relation < ActiveRecord::Base check_consistency(self, new_relation, user) # This will check to see if this relation is used by another relation rel = RelationMember.joins(:relation).find_by("visible = ? AND member_type = 'Relation' and member_id = ? ", true, id) - raise OSM::APIPreconditionFailedError.new("The relation #{new_relation.id} is used in relation #{rel.relation.id}.") unless rel.nil? + raise OSM::APIPreconditionFailedError, "The relation #{new_relation.id} is used in relation #{rel.relation.id}." unless rel.nil? self.changeset_id = new_relation.changeset_id self.tags = {} @@ -202,7 +202,7 @@ class Relation < ActiveRecord::Base lock! check_consistency(self, new_relation, user) unless new_relation.preconditions_ok?(members) - raise OSM::APIPreconditionFailedError.new("Cannot update relation #{id}: data or member data is invalid.") + raise OSM::APIPreconditionFailedError, "Cannot update relation #{id}: data or member data is invalid." end self.changeset_id = new_relation.changeset_id self.changeset = new_relation.changeset @@ -216,7 +216,7 @@ class Relation < ActiveRecord::Base def create_with_history(user) check_create_consistency(self, user) unless preconditions_ok? - raise OSM::APIPreconditionFailedError.new("Cannot create relation: data or member data is invalid.") + raise OSM::APIPreconditionFailedError, "Cannot create relation: data or member data is invalid." end self.version = 0 self.visible = true @@ -253,7 +253,7 @@ class Relation < ActiveRecord::Base # and check that it is OK to use. unless element && element.visible? && element.preconditions_ok? - raise OSM::APIPreconditionFailedError.new("Relation with id #{id} cannot be saved due to #{m[0]} with id #{m[1]}") + raise OSM::APIPreconditionFailedError, "Relation with id #{id} cannot be saved due to #{m[0]} with id #{m[1]}" end hash[m[1]] = true end @@ -270,7 +270,7 @@ class Relation < ActiveRecord::Base old_id = id.to_i if old_id < 0 new_id = id_map[type.downcase.to_sym][old_id] - raise OSM::APIBadUserInput.new("Placeholder #{type} not found for reference #{old_id} in relation #{self.id.nil? ? placeholder_id : self.id}.") if new_id.nil? + raise OSM::APIBadUserInput, "Placeholder #{type} not found for reference #{old_id} in relation #{self.id.nil? ? placeholder_id : self.id}." if new_id.nil? [type, new_id, role] else [type, id, role] diff --git a/app/models/trace.rb b/app/models/trace.rb index eed09dbe5..a2c1b79a7 100644 --- a/app/models/trace.rb +++ b/app/models/trace.rb @@ -172,13 +172,12 @@ class Trace < ActiveRecord::Base el1 end - # Read in xml as text and return it's Node object representation - def self.from_xml(xml, create = false) + def update_from_xml(xml, create = false) p = XML::Parser.string(xml, :options => XML::Parser::Options::NOERROR) doc = p.parse doc.find("//osm/gpx_file").each do |pt| - return Trace.from_xml_node(pt, create) + return update_from_xml_node(pt, create) end raise OSM::APIBadXMLError.new("trace", xml, "XML doesn't contain an osm/gpx_file element.") @@ -186,34 +185,31 @@ class Trace < ActiveRecord::Base raise OSM::APIBadXMLError.new("trace", xml, ex.message) end - def self.from_xml_node(pt, create = false) - trace = Trace.new - + def update_from_xml_node(pt, create = false) raise OSM::APIBadXMLError.new("trace", pt, "visibility missing") if pt["visibility"].nil? - trace.visibility = pt["visibility"] + self.visibility = pt["visibility"] unless create raise OSM::APIBadXMLError.new("trace", pt, "ID is required when updating.") if pt["id"].nil? - trace.id = pt["id"].to_i + id = pt["id"].to_i # .to_i will return 0 if there is no number that can be parsed. # We want to make sure that there is no id with zero anyway - raise OSM::APIBadUserInput.new("ID of trace cannot be zero when updating.") if trace.id.zero? + raise OSM::APIBadUserInput, "ID of trace cannot be zero when updating." if id.zero? + raise OSM::APIBadUserInput, "The id in the url (#{self.id}) is not the same as provided in the xml (#{id})" unless self.id == id end # We don't care about the time, as it is explicitly set on create/update/delete # We don't care about the visibility as it is implicit based on the action # and set manually before the actual delete - trace.visible = true + self.visible = true description = pt.find("description").first raise OSM::APIBadXMLError.new("trace", pt, "description missing") if description.nil? - trace.description = description.content + self.description = description.content - pt.find("tag").each do |tag| - trace.tags.build(:tag => tag.content) + self.tags = pt.find("tag").collect do |tag| + Tracetag.new(:tag => tag.content) end - - trace end def xml_file diff --git a/app/models/way.rb b/app/models/way.rb index 9586094ff..212998ccc 100644 --- a/app/models/way.rb +++ b/app/models/way.rb @@ -58,7 +58,7 @@ class Way < ActiveRecord::Base way.id = pt["id"].to_i # .to_i will return 0 if there is no number that can be parsed. # We want to make sure that there is no id with zero anyway - raise OSM::APIBadUserInput.new("ID of way cannot be zero when updating.") if way.id.zero? + raise OSM::APIBadUserInput, "ID of way cannot be zero when updating." if way.id.zero? end # We don't care about the timestamp nor the visibility as these are either @@ -138,12 +138,12 @@ class Way < ActiveRecord::Base attr_writer :tags def add_nd_num(n) - @nds = [] unless @nds + @nds ||= [] @nds << n.to_i end def add_tag_keyval(k, v) - @tags = {} unless @tags + @tags ||= {} # duplicate tags are now forbidden, so we can't allow values # in the hash to be overwritten. @@ -166,7 +166,7 @@ class Way < ActiveRecord::Base lock! check_consistency(self, new_way, user) unless new_way.preconditions_ok?(nds) - raise OSM::APIPreconditionFailedError.new("Cannot update way #{id}: data is invalid.") + raise OSM::APIPreconditionFailedError, "Cannot update way #{id}: data is invalid." end self.changeset_id = new_way.changeset_id @@ -181,7 +181,7 @@ class Way < ActiveRecord::Base def create_with_history(user) check_create_consistency(self, user) unless preconditions_ok? - raise OSM::APIPreconditionFailedError.new("Cannot create way: data is invalid.") + raise OSM::APIPreconditionFailedError, "Cannot create way: data is invalid." end self.version = 0 self.visible = true @@ -205,7 +205,7 @@ class Way < ActiveRecord::Base if db_nds.length < new_nds.length missing = new_nds - db_nds.collect(&:id) - raise OSM::APIPreconditionFailedError.new("Way #{id} requires the nodes with id in (#{missing.join(',')}), which either do not exist, or are not visible.") + raise OSM::APIPreconditionFailedError, "Way #{id} requires the nodes with id in (#{missing.join(',')}), which either do not exist, or are not visible." end end @@ -222,7 +222,7 @@ class Way < ActiveRecord::Base lock! check_consistency(self, new_way, user) rels = Relation.joins(:relation_members).where(:visible => true, :current_relation_members => { :member_type => "Way", :member_id => id }).order(:id) - raise OSM::APIPreconditionFailedError.new("Way #{id} is still used by relations #{rels.collect(&:id).join(',')}.") unless rels.empty? + raise OSM::APIPreconditionFailedError, "Way #{id} is still used by relations #{rels.collect(&:id).join(',')}." unless rels.empty? self.changeset_id = new_way.changeset_id self.changeset = new_way.changeset @@ -242,7 +242,7 @@ class Way < ActiveRecord::Base nds.map! do |node_id| if node_id < 0 new_id = id_map[:node][node_id] - raise OSM::APIBadUserInput.new("Placeholder node not found for reference #{node_id} in way #{id.nil? ? placeholder_id : id}") if new_id.nil? + raise OSM::APIBadUserInput, "Placeholder node not found for reference #{node_id} in way #{id.nil? ? placeholder_id : id}" if new_id.nil? new_id else node_id diff --git a/app/views/browse/changeset.html.erb b/app/views/browse/changeset.html.erb index a33214a70..86d190680 100644 --- a/app/views/browse/changeset.html.erb +++ b/app/views/browse/changeset.html.erb @@ -12,10 +12,10 @@ <%= render :partial => "tag_details", :object => @changeset.tags.except('comment') %>

<%= t('browse.changeset.discussion') %>

- +
- <% if @user and @changeset.subscribers.exists?(@user.id) %> + <% if current_user and @changeset.subscribers.exists?(current_user.id) %> <% else %> @@ -37,13 +37,13 @@ :when => friendly_date(comment.created_at), :exact_time => l(comment.created_at), :user => link_to(h(comment.author.display_name), {:controller => "user", :action => "view", :display_name => comment.author.display_name})).html_safe %> - <% if @user and @user.moderator? %> + <% if current_user and current_user.moderator? %> — <%= t('javascripts.changesets.show.hide_comment') %> <% end %> <%= comment.body.to_html %> - <% elsif @user and @user.moderator? %> + <% elsif current_user and current_user.moderator? %>
  • <%= t("browse.changeset.hidden_commented_by", diff --git a/app/views/changeset/history.html.erb b/app/views/changeset/history.html.erb index 1516118eb..17faf7f8d 100644 --- a/app/views/changeset/history.html.erb +++ b/app/views/changeset/history.html.erb @@ -5,7 +5,7 @@ <% end -%> <% - set_title(changeset_list_title(params, @user)) + set_title(changeset_list_title(params, current_user)) if params[:display_name] @heading = t('changeset.list.title_user', :user => link_to(params[:display_name], :controller => "user", :action => "view", :display_name => params[:display_name])).html_safe else diff --git a/app/views/changeset/list.atom.builder b/app/views/changeset/list.atom.builder index 0235d182a..ace586ae5 100644 --- a/app/views/changeset/list.atom.builder +++ b/app/views/changeset/list.atom.builder @@ -2,7 +2,7 @@ atom_feed(:language => I18n.locale, :schema_date => 2009, :id => url_for(@params.merge(:only_path => false)), :root_url => url_for(@params.merge(:action => :list, :format => nil, :only_path => false)), "xmlns:georss" => "http://www.georss.org/georss") do |feed| - feed.title changeset_list_title(params, @user) + feed.title changeset_list_title(params, current_user) feed.updated @edits.map { |e| [e.created_at, e.closed_at].max }.max feed.icon image_url("favicon.ico") diff --git a/app/views/diary_entry/list.html.erb b/app/views/diary_entry/list.html.erb index 756464aa2..d6af432fb 100644 --- a/app/views/diary_entry/list.html.erb +++ b/app/views/diary_entry/list.html.erb @@ -34,19 +34,21 @@ <%= render :partial => 'diary_list_entry', :collection => @entries %> <% end %> - <% if @entries.size < @page_size -%> - <%= t('diary_entry.list.older_entries') %> - <% else -%> - <%= link_to t('diary_entry.list.older_entries'), @params.merge(:page => @page + 1 ) %> - <% end -%> - - | - - <% if @page > 1 -%> - <%= link_to t('diary_entry.list.newer_entries'), @params.merge(:page => @page - 1) %> - <% else -%> - <%= t('diary_entry.list.newer_entries') %> - <% end -%> + <% end %> <% unless params[:friends] or params[:nearby] -%> diff --git a/app/views/diary_entry/view.html.erb b/app/views/diary_entry/view.html.erb index 6a2a21abc..3c2264d3e 100644 --- a/app/views/diary_entry/view.html.erb +++ b/app/views/diary_entry/view.html.erb @@ -21,9 +21,9 @@ <%= richtext_area :diary_comment, :body, :cols => 80, :rows => 15 %> <%= submit_tag t('diary_entry.view.save_button') %> <% end %> - <% if @user and @entry.subscribers.exists?(@user.id) %> + <% if current_user and @entry.subscribers.exists?(current_user.id) %>
    <%= link_to t('javascripts.changesets.show.unsubscribe'), diary_entry_unsubscribe_path(:display_name => @entry.user.display_name, :id => @entry.id), :method => :post, :class => :button %>
    - <% elsif @user %> + <% elsif current_user %>
    <%= link_to t('javascripts.changesets.show.subscribe'), diary_entry_subscribe_path(:display_name => @entry.user.display_name, :id => @entry.id), :method => :post, :class => :button %>
    <% end %> <% end %> diff --git a/app/views/layouts/_head.html.erb b/app/views/layouts/_head.html.erb index 377d55e9d..6fce3f01f 100644 --- a/app/views/layouts/_head.html.erb +++ b/app/views/layouts/_head.html.erb @@ -7,7 +7,6 @@ <%= stylesheet_link_tag "print-#{dir}", :media => "print" %> <%= stylesheet_link_tag "leaflet-all", :media => "screen, print" %> <% [57, 60, 72, 76, 114, 120, 144, 152, 180].each do |size| -%> @@ -18,7 +17,7 @@ <%= favicon_link_tag "favicon-96x96.png", :rel => "icon", :sizes => "96x96", :type => "image/png" %> <%= favicon_link_tag "android-chrome-192x192.png", :rel => "icon", :sizes => "192x192", :type => "image/png" %> <%= favicon_link_tag "favicon-16x16.png", :rel => "icon", :sizes => "16x16", :type => "image/png" %> - <%= tag("link", { :rel => "mask-icon", :href => asset_path("tag-icon.svg"), :color => "#7ebc6f" }) %> + <%= tag("link", { :rel => "mask-icon", :href => asset_path("tab-icon.svg"), :color => "#7ebc6f" }) %> <%= tag("link", { :rel => "manifest", :href => asset_path("manifest.json") }) %> <%= tag("meta", { :name => "msapplication-config", :content => asset_path("browserconfig.xml") }) %> <%= tag("meta", { :name => "msapplication-TileColor", :content => "#00a300" }) %> diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb index 262989752..a5ab460ce 100644 --- a/app/views/layouts/_header.html.erb +++ b/app/views/layouts/_header.html.erb @@ -54,26 +54,26 @@
  • - <% if @user && @user.id %> + <% if current_user && current_user.id %> - <% unless @user %> + <% unless current_user %>

    <%= t 'layouts.intro_header' %>

    diff --git a/app/views/message/_message_count.html.erb b/app/views/message/_message_count.html.erb index 9b5edd26c..3a995c171 100644 --- a/app/views/message/_message_count.html.erb +++ b/app/views/message/_message_count.html.erb @@ -1,8 +1,8 @@

    <%= t "message.inbox.messages", - :new_messages => t("message.inbox.new_messages", - :count => @user.new_messages.size), - :old_messages => t("message.inbox.old_messages", - :count => @user.messages.size - @user.new_messages.size) + :new_messages => t("message.inbox.new_messages", + :count => current_user.new_messages.size), + :old_messages => t("message.inbox.old_messages", + :count => current_user.messages.size - current_user.new_messages.size) %> -

    +

    diff --git a/app/views/message/inbox.html.erb b/app/views/message/inbox.html.erb index 4a898c085..919a3e402 100644 --- a/app/views/message/inbox.html.erb +++ b/app/views/message/inbox.html.erb @@ -1,10 +1,10 @@ <% content_for :heading do %> -

    <%= t'message.inbox.my_inbox'%>/<%= link_to t('message.inbox.outbox'), outbox_path(@user.display_name) %>

    +

    <%= t'message.inbox.my_inbox'%>/<%= link_to t('message.inbox.outbox'), outbox_path(current_user.display_name) %>

    <% end %>

    <%= render :partial => "message_count" %>

    -<% if @user.messages.size > 0 %> +<% if current_user.messages.size > 0 %> @@ -16,9 +16,9 @@ - <%= render :partial => "message_summary", :collection => @user.messages %> + <%= render :partial => "message_summary", :collection => current_user.messages %>
    <% else %> -
    <%= raw(t'message.inbox.no_messages_yet', :people_mapping_nearby_link => link_to(t('message.inbox.people_mapping_nearby'), :controller => 'user', :action => 'view', :display_name => @user.display_name)) %>
    +
    <%= raw(t'message.inbox.no_messages_yet', :people_mapping_nearby_link => link_to(t('message.inbox.people_mapping_nearby'), :controller => 'user', :action => 'view', :display_name => current_user.display_name)) %>
    <% end %> diff --git a/app/views/message/new.html.erb b/app/views/message/new.html.erb index f7c26aea1..b2534e47b 100644 --- a/app/views/message/new.html.erb +++ b/app/views/message/new.html.erb @@ -16,7 +16,7 @@
    <%= submit_tag t('message.new.send_button') %> - <%= link_to t('message.new.back_to_inbox'), { :controller => 'message', :action => 'inbox', :display_name => @user.display_name }, :class => 'deemphasize button' %> + <%= link_to t('message.new.back_to_inbox'), { :controller => 'message', :action => 'inbox', :display_name => current_user.display_name }, :class => 'deemphasize button' %>
    <% end %> diff --git a/app/views/message/outbox.html.erb b/app/views/message/outbox.html.erb index ebf04c9fb..288c235eb 100644 --- a/app/views/message/outbox.html.erb +++ b/app/views/message/outbox.html.erb @@ -1,10 +1,10 @@ <% content_for :heading do %> -

    <%= raw(t'message.outbox.my_inbox', :inbox_link => link_to(t('message.outbox.inbox'), inbox_path(@user.display_name))) %>/<%= t'message.outbox.outbox' %>

    +

    <%= raw(t'message.outbox.my_inbox', :inbox_link => link_to(t('message.outbox.inbox'), inbox_path(current_user.display_name))) %>/<%= t'message.outbox.outbox' %>

    <% end %> -

    <%= t'message.outbox.messages', :count => @user.sent_messages.size %>

    +

    <%= t'message.outbox.messages', :count => current_user.sent_messages.size %>

    -<% if @user.sent_messages.size > 0 %> +<% if current_user.sent_messages.size > 0 %> @@ -15,9 +15,9 @@ - <%= render :partial => "sent_message_summary", :collection => @user.sent_messages %> + <%= render :partial => "sent_message_summary", :collection => current_user.sent_messages %>
    <% else %> -
    <%= raw(t'message.outbox.no_sent_messages', :people_mapping_nearby_link => link_to(t('message.outbox.people_mapping_nearby'), :controller => 'user', :action => 'view', :display_name => @user.display_name)) %>
    +
    <%= raw(t'message.outbox.no_sent_messages', :people_mapping_nearby_link => link_to(t('message.outbox.people_mapping_nearby'), :controller => 'user', :action => 'view', :display_name => current_user.display_name)) %>
    <% end %> diff --git a/app/views/message/read.html.erb b/app/views/message/read.html.erb index 8e175ef67..6621c3e8e 100644 --- a/app/views/message/read.html.erb +++ b/app/views/message/read.html.erb @@ -1,4 +1,4 @@ -<% if @user == @message.recipient %> +<% if current_user == @message.recipient %> <% content_for :heading do %>

    <%= h(@message.title) %>

    <% end %> @@ -36,5 +36,5 @@ <% end %> - <%= link_to t('message.read.back'), {:controller => 'message', :action => 'outbox', :display_name => @user.display_name }, :class => "button deemphasize" %> + <%= link_to t('message.read.back'), {:controller => 'message', :action => 'outbox', :display_name => current_user.display_name }, :class => "button deemphasize" %>
    diff --git a/app/views/oauth/authorize.html.erb b/app/views/oauth/authorize.html.erb index c0271350d..6c8bc3a9e 100644 --- a/app/views/oauth/authorize.html.erb +++ b/app/views/oauth/authorize.html.erb @@ -2,7 +2,7 @@

    <%= t "oauth.oauthorize.title" %>

    <% end %> -

    <%= raw t("oauth.oauthorize.request_access", :app_name => link_to(@token.client_application.name, @token.client_application.url), :user => link_to(@user.display_name, :controller => :user, :action => :view, :display_name => @user.display_name)) %>

    +

    <%= raw t("oauth.oauthorize.request_access", :app_name => link_to(@token.client_application.name, @token.client_application.url), :user => link_to(current_user.display_name, :controller => :user, :action => :view, :display_name => current_user.display_name)) %>

    <%= form_tag authorize_url do %> <%= hidden_field_tag "oauth_token", @token.token %> diff --git a/app/views/redactions/show.html.erb b/app/views/redactions/show.html.erb index 174fe97e4..b9786992c 100644 --- a/app/views/redactions/show.html.erb +++ b/app/views/redactions/show.html.erb @@ -12,8 +12,8 @@ <%= @redaction.description.to_html %>

    -<% if @user and @user.moderator? %> -
    +<% if current_user and current_user.moderator? %> +
    <%= button_to t('redaction.show.edit'), edit_redaction_path(@redaction), :method => :get %> <%= button_to t('redaction.show.destroy'), @redaction, :method => "delete", :remote => true, :data => { :confirm => t('redaction.show.confirm') } %>
    diff --git a/app/views/site/_potlatch.html.erb b/app/views/site/_potlatch.html.erb index b0d20a9ae..5b59f5f24 100644 --- a/app/views/site/_potlatch.html.erb +++ b/app/views/site/_potlatch.html.erb @@ -1,7 +1,7 @@ <%= javascript_include_tag "edit/potlatch" %>
    - <% session[:token] = @user.tokens.create.token unless session[:token] and UserToken.find_by_token(session[:token]) -%> + <% session[:token] = current_user.tokens.create.token unless session[:token] and UserToken.find_by_token(session[:token]) -%> <% data = { :token => session[:token] } -%> <% data[:lat] = @lat if @lat -%> <% data[:lon] = @lon if @lon -%> diff --git a/app/views/site/_potlatch2.html.erb b/app/views/site/_potlatch2.html.erb index 2cc4ab2d5..9e01eef30 100644 --- a/app/views/site/_potlatch2.html.erb +++ b/app/views/site/_potlatch2.html.erb @@ -1,13 +1,13 @@ <%= javascript_include_tag "edit/potlatch2" %>
    - <% session[:token] = @user.tokens.create.token unless session[:token] and UserToken.find_by_token(session[:token]) -%> + <% session[:token] = current_user.tokens.create.token unless session[:token] and UserToken.find_by_token(session[:token]) -%> <% data = { :token => session[:token] } -%> <% data[:lat] = @lat if @lat -%> <% data[:lon] = @lon if @lon -%> <% data[:zoom] = @zoom if @zoom -%> <% if defined? POTLATCH2_KEY %> - <% token = @user.access_token(POTLATCH2_KEY) %> + <% token = current_user.access_token(POTLATCH2_KEY) %> <% data[:token] = token.token -%> <% data[:token_secret] = token.secret -%> <% data[:consumer_key] = token.client_application.key -%> diff --git a/app/views/site/edit.html.erb b/app/views/site/edit.html.erb index ae313e1f2..81095140e 100644 --- a/app/views/site/edit.html.erb +++ b/app/views/site/edit.html.erb @@ -3,9 +3,9 @@

    <%= t 'layouts.osm_offline' %>

    <% elsif STATUS == :database_readonly or STATUS == :api_readonly %>

    <%= t 'layouts.osm_read_only' %>

    - <% elsif !@user.data_public? %> + <% elsif !current_user.data_public? %>

    <%= t 'site.edit.not_public' %>

    -

    <%= raw t 'site.edit.not_public_description', :user_page => (link_to t('site.edit.user_page_link'), {:controller => 'user', :action => 'account', :display_name => @user.display_name, :anchor => 'public'}) %>

    +

    <%= raw t 'site.edit.not_public_description', :user_page => (link_to t('site.edit.user_page_link'), {:controller => 'user', :action => 'account', :display_name => current_user.display_name, :anchor => 'public'}) %>

    <%= raw t 'site.edit.anon_edits', :link => link_to(t('site.edit.anon_edits_link_text'), t('site.edit.anon_edits_link')) %>

    <% else %> <%= render :partial => preferred_editor %> diff --git a/app/views/site/help.html.erb b/app/views/site/help.html.erb index 5097dd340..dff2108ca 100644 --- a/app/views/site/help.html.erb +++ b/app/views/site/help.html.erb @@ -5,7 +5,7 @@

    <%= t "help_page.introduction" %>

    <% ['welcome', 'beginners_guide', 'help', 'mailing_lists', 'forums', 'irc', 'switch2osm', 'wiki'].each do |site| %> - <% unless site == 'welcome' && !@user %> + <% unless site == 'welcome' && !current_user %>

    diff --git a/app/views/site/id.html.erb b/app/views/site/id.html.erb index a38a81534..c115ea59f 100644 --- a/app/views/site/id.html.erb +++ b/app/views/site/id.html.erb @@ -10,7 +10,7 @@ <% data = {} -%> <% if defined? ID_KEY %> -<% token = @user.access_token(ID_KEY) %> +<% token = current_user.access_token(ID_KEY) %> <% data[:token] = token.token -%> <% data[:token_secret] = token.secret -%> <% data[:consumer_key] = token.client_application.key -%> diff --git a/app/views/user/_contact.html.erb b/app/views/user/_contact.html.erb index 4811389f1..08b982cd7 100644 --- a/app/views/user/_contact.html.erb +++ b/app/views/user/_contact.html.erb @@ -37,7 +37,7 @@
    • <%= link_to t('user.view.send message'), :controller => 'message', :action => 'new', :display_name => contact.display_name %>
    • - <% if @user.is_friends_with?(contact) %> + <% if current_user.is_friends_with?(contact) %> <%= link_to t('user.view.remove as friend'), remove_friend_path(:display_name => contact.display_name, :referer => request.fullpath), :method => :post %> <% else %> <%= link_to t('user.view.add as friend'), make_friend_path(:display_name => contact.display_name, :referer => request.fullpath), :method => :post %> diff --git a/app/views/user/account.html.erb b/app/views/user/account.html.erb index 47a84e99b..92b3407bf 100644 --- a/app/views/user/account.html.erb +++ b/app/views/user/account.html.erb @@ -5,13 +5,13 @@ <% content_for :heading do %>

      <%= t 'user.account.my settings' %>

        -
      • <%= link_to t('user.account.return to profile'), :controller => 'user', :action => 'view', :display_name => @user.display_name %>
      • +
      • <%= link_to t('user.account.return to profile'), :controller => 'user', :action => 'view', :display_name => current_user.display_name %>
      • <%= link_to t('user.view.oauth settings'), :controller => 'oauth_clients', :action => 'index' %>
      <% end %> -<%= error_messages_for 'user' %> -<%= form_for :user, :html => { :multipart => true, :id => 'accountForm', :class => 'standard-form', :autocomplete => :off } do |f| %> +<%= error_messages_for current_user %> +<%= form_for current_user, :url => { :action => :account }, :method => :post, :html => { :multipart => true, :id => 'accountForm', :class => 'standard-form', :autocomplete => :off } do |f| %>
      @@ -22,7 +22,7 @@
      - + <%= t 'user.account.email never displayed publicly' %>
      @@ -58,7 +58,7 @@
      - <% if @user.data_public? %> + <% if current_user.data_public? %> <%= t 'user.account.public editing.enabled' %> (<%= t 'user.account.public editing.enabled link text' %>) <% else %> @@ -71,10 +71,10 @@
      - <% if @user.terms_agreed? %> + <% if current_user.terms_agreed? %> <%= t 'user.account.contributor terms.agreed' %> (<%= t 'user.account.contributor terms.link text' %>) - <% if @user.consider_pd? %> + <% if current_user.consider_pd? %> <%= t 'user.account.contributor terms.agreed_with_pd' %> <% end %> <% else %> @@ -92,7 +92,7 @@
      - <%= richtext_area :user, :description, :cols => 80, :rows => 20 %> + <%= richtext_area :user, :description, :object => current_user, :cols => 80, :rows => 20 %>
      @@ -102,21 +102,21 @@
      - <%= user_image @user %> + <%= user_image current_user %>
        - <% if @user.image.file? %> + <% if current_user.image.file? %>
      • - <%= radio_button_tag "image_action", "keep", !@user.image_use_gravatar %> + <%= radio_button_tag "image_action", "keep", !current_user.image_use_gravatar %>
      • <% end %> - <% if @user.image.file? || @user.image_use_gravatar? %> + <% if current_user.image.file? || current_user.image_use_gravatar? %>
      • <%= radio_button_tag "image_action", "delete" %>
      • <% end %> - <% if @user.image.file? %> + <% if current_user.image.file? %>
      • <%= radio_button_tag "image_action", "new" %>
      • <% end %>
      • - <%= radio_button_tag "image_action", "gravatar", @user.image_use_gravatar %> + <%= radio_button_tag "image_action", "gravatar", current_user.image_use_gravatar %>
      <%= t 'user.new.display name description' %>
      @@ -45,9 +45,9 @@ - <%= select(:user, :auth_provider, Auth::PROVIDERS, { :default => "", :tabindex => 4 }) %> - <%= text_field(:user, :auth_uid, { :tabindex => 5 }) %> - <%= error_message_on(:user, :auth_uid) %> + <%= f.select(:auth_provider, Auth::PROVIDERS, { :default => "", :tabindex => 4 }) %> + <%= f.text_field(:auth_uid, { :tabindex => 5 }) %> + <%= f.error_message_on(:auth_uid) %>
      <%= t 'user.new.auth no password' %>
      @@ -57,15 +57,15 @@ - <%= password_field(:user, :pass_crypt, { :tabindex => 6 }) %> - <%= error_message_on(:user, :pass_crypt) %> + <%= f.password_field(:pass_crypt, { :tabindex => 6 }) %> + <%= f.error_message_on(:pass_crypt) %>
      - <%= password_field(:user, :pass_crypt_confirmation, { :tabindex => 7 }) %> - <%= error_message_on(:user, :pass_crypt_confirmation) %> + <%= f.password_field(:pass_crypt_confirmation, { :tabindex => 7 }) %> + <%= f.error_message_on(:pass_crypt_confirmation) %>
      diff --git a/app/views/user/reset_password.html.erb b/app/views/user/reset_password.html.erb index d1718a5e4..895bd98b6 100644 --- a/app/views/user/reset_password.html.erb +++ b/app/views/user/reset_password.html.erb @@ -1,8 +1,8 @@ <% content_for :heading do %> -

      <%= t 'user.reset_password.heading', :user => @user.display_name %>

      +

      <%= t 'user.reset_password.heading', :user => current_user.display_name %>

      <% end %> -<%= error_messages_for :user %> +<%= error_messages_for current_user %> <%= form_tag do %> <%= hidden_field_tag(:token, params[:token]) %> diff --git a/app/views/user/save.html.erb b/app/views/user/save.html.erb deleted file mode 100644 index f8a80b26c..000000000 --- a/app/views/user/save.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= @user.email %> diff --git a/app/views/user/view.html.erb b/app/views/user/view.html.erb index 91f85f305..137a390ba 100644 --- a/app/views/user/view.html.erb +++ b/app/views/user/view.html.erb @@ -3,42 +3,42 @@ <%= user_image @this_user %>

      <%= @this_user.display_name %><%= role_icons(@this_user) %>

      - <% if @user and @this_user.id == @user.id %> + <% if current_user and @this_user.id == current_user.id %>
      • - <%= link_to t('user.view.my edits'), :controller => 'changeset', :action => 'list', :display_name => @user.display_name %> - <%= number_with_delimiter(@user.changesets.size) %> + <%= link_to t('user.view.my edits'), :controller => 'changeset', :action => 'list', :display_name => current_user.display_name %> + <%= number_with_delimiter(current_user.changesets.size) %>
      • <%= link_to t('user.view.my notes'), :controller => 'notes', :action=> 'mine' %>
      • <%= link_to t('user.view.my traces'), :controller => 'trace', :action=>'mine' %> - <%= number_with_delimiter(@user.traces.size) %> + <%= number_with_delimiter(current_user.traces.size) %>
      • - <%= link_to t('user.view.my diary'), :controller => 'diary_entry', :action => 'list', :display_name => @user.display_name %> - <%= number_with_delimiter(@user.diary_entries.size) %> + <%= link_to t('user.view.my diary'), :controller => 'diary_entry', :action => 'list', :display_name => current_user.display_name %> + <%= number_with_delimiter(current_user.diary_entries.size) %>
      • - <%= link_to t('user.view.my comments' ), :controller => 'diary_entry', :action => 'comments', :display_name => @user.display_name %> + <%= link_to t('user.view.my comments' ), :controller => 'diary_entry', :action => 'comments', :display_name => current_user.display_name %>
      • - <%= link_to t('user.view.my settings'), :controller => 'user', :action => 'account', :display_name => @user.display_name %> + <%= link_to t('user.view.my settings'), :controller => 'user', :action => 'account', :display_name => current_user.display_name %>
      • - <% if @user.blocks.exists? %> + <% if current_user.blocks.exists? %>
      • - <%= link_to t('user.view.blocks on me'), :controller => 'user_blocks', :action => 'blocks_on', :display_name => @user.display_name %> - <%= number_with_delimiter(@user.blocks.active.size) %> + <%= link_to t('user.view.blocks on me'), :controller => 'user_blocks', :action => 'blocks_on', :display_name => current_user.display_name %> + <%= number_with_delimiter(current_user.blocks.active.size) %>
      • <% end %> - <% if @user and @user.moderator? and @user.blocks_created.exists? %> + <% if current_user and current_user.moderator? and current_user.blocks_created.exists? %>
      • - <%= link_to t('user.view.blocks by me'), :controller => 'user_blocks', :action => 'blocks_by', :display_name => @user.display_name %> - <%= number_with_delimiter(@user.blocks_created.active.size) %> + <%= link_to t('user.view.blocks by me'), :controller => 'user_blocks', :action => 'blocks_by', :display_name => current_user.display_name %> + <%= number_with_delimiter(current_user.blocks_created.active.size) %>
      • <% end %> @@ -73,9 +73,9 @@ <%= link_to t('user.view.comments'), :controller => 'diary_entry', :action => 'comments', :display_name => @this_user.display_name %>
      • - <% if @user and @user.is_friends_with?(@this_user) %> + <% if current_user and current_user.is_friends_with?(@this_user) %> <%= link_to t('user.view.remove as friend'), remove_friend_path(:display_name => @this_user.display_name), :method => :post %> - <% elsif @user %> + <% elsif current_user %> <%= link_to t('user.view.add as friend'), make_friend_path(:display_name => @this_user.display_name), :method => :post %> <% else %> <%= link_to t('user.view.add as friend'), make_friend_path(:display_name => @this_user.display_name) %> @@ -96,7 +96,7 @@
      • <% end %> - <% if @user and @user.moderator? %> + <% if current_user and current_user.moderator? %>
      • <%= link_to t('user.view.create_block'), :controller => 'user_blocks', :action => 'new', :display_name => @this_user.display_name %>
      • @@ -106,7 +106,7 @@ <% end %> - <% if @user and @user.administrator? %> + <% if current_user and current_user.administrator? %>
          <% if ["active", "confirmed"].include? @this_user.status %> @@ -158,7 +158,7 @@
      - <% if @user and @user.administrator? -%> + <% if current_user and current_user.administrator? -%>

      <% if @user_block.ends_at > Time.now.getutc %> - <% if @user and @user.id == @user_block.creator_id %> + <% if current_user and current_user.id == @user_block.creator_id %>
    • <%= link_to t('user_block.show.edit'), edit_user_block_path(@user_block) %>
    • <% end %> - <% if @user and @user.moderator? %> + <% if current_user and current_user.moderator? %>
    • <%= link_to(t('user_block.show.revoke'),{:controller => 'user_blocks', :action => 'revoke', :id => @user_block.id}) %>
    • <% end %> <% end %> diff --git a/config/banners.yml b/config/banners.yml index 3b151afba..f8a320053 100644 --- a/config/banners.yml +++ b/config/banners.yml @@ -1,20 +1,12 @@ -sotmasia2016: - id: sotmasia2016 - alt: State of the Map Asia 2016 +sotmasia2017: + id: sotmasia2017 + alt: State of the Map Asia 2017 link: http://stateofthemap.asia/ - img: banners/sotmasia-2016.jpg - enddate: 2016-oct-01 - -donate2016: - id: donate2016 - alt: OpenStreetMap Funding Drive 2016 - link: https://donate.openstreetmap.org/ - img: banners/donate-2016.jpg - enddate: 2016-oct-31 - -sotmlatam2016: - id: sotmlatam2016 - alt: State of the Map Latam 2016 - link: http://state.osmlatam.org/ - img: banners/sotmlatam-2016.jpg - enddate: 2016-nov-25 + img: banners/sotmasia-2017-banner.png + enddate: 2017-sep-25 +sotmus2017: + id: sotmus2017 + alt: State of the Map US 2017 + link: https://2017.stateofthemap.us/ + img: banners/banner-sotmus2017.png + enddate: 2017-oct-20 diff --git a/config/example.application.yml b/config/example.application.yml index 9c5c7a180..5c60ccd16 100644 --- a/config/example.application.yml +++ b/config/example.application.yml @@ -50,9 +50,8 @@ defaults: &defaults #messages_domain: "messages.openstreetmap.org" # Geonames authentication details #geonames_username: "" - # Quova authentication details - #quova_username: "" - #quova_password: "" + # GeoIP database + #geoip_database: "" # Users to show as being nearby nearby_users: 30 # Max radius, in km, for nearby users diff --git a/config/initializers/banners.rb b/config/initializers/banners.rb index 5c83c045d..8eda290c5 100644 --- a/config/initializers/banners.rb +++ b/config/initializers/banners.rb @@ -1,5 +1,5 @@ begin BANNERS = YAML.load_file(Rails.root.join("config", "banners.yml")).deep_symbolize_keys -rescue +rescue StandardError BANNERS = {}.freeze end diff --git a/config/initializers/secure_headers.rb b/config/initializers/secure_headers.rb index 59fe4225d..361fb3283 100644 --- a/config/initializers/secure_headers.rb +++ b/config/initializers/secure_headers.rb @@ -9,7 +9,7 @@ if defined?(CSP_REPORT_URL) :img_src => %w['self' data: www.gravatar.com *.wp.com *.tile.openstreetmap.org *.tile.thunderforest.com *.openstreetmap.fr], :media_src => %w['none'], :object_src => %w['self'], - :plugin_types => %w['none'], + :plugin_types => %w[], :script_src => %w['self'], :style_src => %w['self' 'unsafe-inline'], :report_uri => [CSP_REPORT_URL] diff --git a/config/initializers/streaming.rb b/config/initializers/streaming.rb deleted file mode 100644 index 0c27ba2e7..000000000 --- a/config/initializers/streaming.rb +++ /dev/null @@ -1,23 +0,0 @@ -# Hack ActionController::DataStreaming to allow streaming from a file handle -module ActionController - module DataStreaming - alias old_send_file send_file - - def send_file(file, options = {}) - if file.is_a?(File) || file.is_a?(Tempfile) - headers["Content-Length"] ||= file.size.to_s - - options[:filename] ||= File.basename(file.path) unless options[:url_based_filename] - send_file_headers! options - - self.status = options[:status] || 200 - self.content_type = options[:content_type] if options.key?(:content_type) - self.response_body = file - else - headers["Content-Length"] ||= File.size(file).to_s - - old_send_file(file, options) - end - end - end -end diff --git a/config/locales/af.yml b/config/locales/af.yml index e66a0cdf8..c0989fcfc 100644 --- a/config/locales/af.yml +++ b/config/locales/af.yml @@ -2,6 +2,7 @@ # Exported from translatewiki.net # Export driver: phpyaml # Author: Arnobarnard +# Author: Biggs ZA # Author: Firefishy # Author: Fwolff # Author: Naudefj @@ -15,20 +16,37 @@ af: models: acl: Toegangsbeheerlys changeset: Wysigingstel + changeset_tag: Wysigingstel-merker country: Land diary_comment: Dagboekopmerking diary_entry: Dagboekinskrywing friend: Vriend language: Taal message: Boodskap - node: Node + node: Knooppunt + node_tag: Knooppuntmerker notifier: Kennisgewer - old_node: Ou Node + old_node: Ou Knooppunt + old_node_tag: Ou knooppuntmerker + old_relation: Ou Verband + old_relation_member: Ou Verbandslid + old_relation_tag: Ou Verbandsmerker + old_way: Ou pad + old_way_node: Ou weg-knooppunt + old_way_tag: Ou weg-merker + relation: Verband + relation_member: Verbandslid + relation_tag: Verbandsmerker session: Sessie trace: Spoor + tracepoint: Natrekpunt + tracetag: Natrekmerker user: Gebruiker user_preference: Gebruikersvoorkeure + user_token: Gebruikerskoepon way: Weg + way_node: Weg-knooppunt + way_tag: Weg-merker attributes: diary_comment: body: Teks @@ -48,57 +66,147 @@ af: size: Grootte latitude: Breedtegraad longitude: Lengtegraad - public: Openbaar + public: Publiek description: Beskrywing message: - sender: Afsender + sender: Sender title: Onderwerp body: Teks recipient: Ontvanger user: email: E-pos - active: Aktief - display_name: Vertoon Naam + active: Bedrywig + display_name: Skermnaam description: Beskrywing languages: Tale pass_crypt: Wagwoord editor: + default: Verstek (tans %{name}) + potlatch: + name: Potknip 1 + description: Potknip 1 (aanlynredigeerder) id: name: iD + description: iD (aanlynredigeerder) + potlatch2: + name: Potknip 2 + description: Potknip 2 (aanlynredigeerder) + remote: + name: Afstandsbeheer + description: Afstandsbeheer (JOSM of Merkaartor) browse: + created: Geskep + closed: Gesluit + created_html: Geskep %{time} gelede + closed_html: Geslote %{time} gelede + created_by_html: Geskep %{time} gelede deur %{user} + deleted_by_html: Geskrap %{time} gelede deur %{user} + edited_by_html: Geredigeer %{time} gelede deur %{user} + closed_by_html: Gesluit %{time} gelede deur %{user} version: Weergawe + in_changeset: Wysigingsstel + anonymous: anoniem + no_comment: (geen kommentaar) + part_of: Deel van download_xml: Laai XML af - view_history: Sien geskiedenis - view_details: Sien detail + view_history: Beskou Geskiedenis + view_details: Bekyk Detail location: 'Ligging:' changeset: + title: 'Wysigingsstel: %{id}' + belongs_to: Skrywer + node: Knooppunte (%{count}) + node_paginated: Knooppunte (%{x}-%{y} van %{count}) + way: Weë (%{count}) + way_paginated: Weë (%{x}-%{y} van %{count}) + relation: Verwantskappe (%{count}) + relation_paginated: Verwantskappe (%{x}-%{y} of %{count}) + comment: Kommentaar (%{count}) + hidden_commented_by: Verskuilde kommentaar deur %{user} %{when} + ago + commented_by: Kommentaar deur %{user} %{when} ago + changesetxml: Wysigingsstel XML + osmchangexml: osmWysiging XML + feed: + title: Wysigingsstel %{id} + title_comment: Wysigingstel %{id} - %{comment} + join_discussion: Meld aan en gesels saam discussion: Bespreking + node: + title: 'Knooppunt: %{name}' + history_title: 'Knooppuntgeskiedenis: %{name}' + way: + title: 'Weg: %{name}' + history_title: 'Weggeskiedenis: %{name}' + nodes: Knooppunte + also_part_of: + one: gedeelte van weg %{related_ways} + other: gedeelte van weë %{related_ways} + relation: + title: 'Verwantskap: %{name}' + history_title: 'Verwantskapgeskiedenis: %{name}' + members: Lede relation_member: entry_role: '%{type} %{name} as %{role}' type: - node: Node + node: Knooppunt way: Weg relation: Verwantskap containing_relation: entry: Verwantskap %{relation_name} entry_role: Verwantskap %{relation_name} (as %{relation_role}) not_found: - sorry: 'Jammer, %{type} #%{id} kan nie gevind word nie.' + sorry: 'Jammer, %{type} #%{id} blyk onverkrygbaar.' type: - node: node + node: knooppunt way: weg relation: verwantskap - changeset: veranderingstel + changeset: wysigingstel + note: nota timeout: - sorry: Jammer, dit het te lank geneem om data vir die %{type} met die id %{id} + sorry: Jammer, die gegewens vir die %{type} met die id %{id} neem te lank om op te soek. type: - node: node + node: knooppunt + way: weg + relation: verband + changeset: wysigingstel + note: nota + redacted: + redaction: Redigering %{id} + message_html: Weergawe %{version} van hierdie %{type} kan nie vertoon word nie, + synde dit geredigeer is. Raadpleeg asseblief %{redaction_link} vir besonderhede. + type: + node: knooppunt + way: weg + relation: verband start_rjs: + feature_warning: Laai tans %{num_features} kenmerke wat u internetblaaier kan + vertraag of laat hang. Is u seker u wil hierdie data vertoon? load_data: Laai data - loading: Laai... + loading: Laai tans… tag_details: - tags: Oortjies + tags: Merkers + wiki_link: + key: Die wiki-beskrywingsblad vir %{key} tag + tag: Die wikibeskrywingsblad vir die %{key}=%{value} merker + wikidata_link: Die %{page} item op Wikidata + wikipedia_link: Die bladsy %{page} op Wikipedia + telephone_link: Skakel %{phone_number} + note: + title: 'Nota: %{id}' + new_note: Nuwe Nota + description: Beskrywing + open_by_anonymous: Anoniem het %{when} ago + geskep + commented_by: Kommentaar deur %{user} %{when} ago + commented_by_anonymous: Kommentaar deur anoniem %{when} + ago + query: + title: Bevraagteken Gidsbakens + introduction: Klik op die kaart om nabye bakens te ontdek. + nearby: Nabye kenmerke + enclosing: Omsluitende kenmerke changeset: changeset_paging_nav: showing_page: Bladsy %{page} @@ -106,26 +214,47 @@ af: previous: « Vorige changeset: anonymous: Anoniem - no_edits: (geen wysigings) + no_edits: (geen redigerings) + view_changeset_details: Bekyk die wysigingsstel se besonderhede changesets: id: ID - saved_at: Gestoor op + saved_at: Gebêre op user: Gebruiker comment: Opmerking area: Gebied + list: + title: Wysigingsstel + empty: Geen wysigingstelle gevind nie. + empty_area: Geen wysigingstelle in hierdie gebied. + empty_user: Geen wysigingstelle deur hierdie gebruiker. + no_more: Geen meer wysigingstelle gevind nie. + no_more_area: Geen wysigingstelle in hierdie gebied nie. + no_more_user: Geen ander wysigingstelle deur hierdie gebruiker nie. + load_more: Laai nog + timeout: + sorry: Jammer, die lys wysigingstelle wat u versoek het, neem lank om uit te + haal. + rss: + title_all: OpenStreetMap bespreking oor wysigingstelle + commented_at_html: '%{when} gelede bygewerk' + commented_at_by_html: '%{when} gelede deur %{user} bygewerk' + full: Volledige bespreking diary_entry: new: title: Nuwe dagboekinskrywing + publish_button: Publiseer list: title: Gebruikersdagboeke - user_title: Dagboek van %{user} + title_friends: Dagboeke van vriende + title_nearby: Gebruikers in die omgewing se dagboeke + user_title: '%{user} se dagboek' in_language_title: Dagboekinkrywings in %{language} new: Nuwe dagboekinskrywing - new_title: Plaas nuwe artikel in u dagboek + new_title: Maak 'n nuwe inskrywing in jou dagboek no_entries: Geen dagboekinskrywings nie recent_entries: Onlangse dagboekinskrywings - older_entries: Ouer inskrywings - newer_entries: Nuwer inskrywings + older_entries: Vorige Inskrywings + newer_entries: Jonger inskrywings edit: title: Wysig dagboekinskrywing subject: 'Onderwerp:' @@ -134,111 +263,139 @@ af: location: 'Ligging:' latitude: 'Breedtegraad:' longitude: 'Lengtegraad:' - use_map_link: gebruik kaart + use_map_link: benut kaart save_button: Stoor marker_text: Ligging van dagboekinskrywing view: title: '%{user} se dagboek | %{title}' - user_title: Dagboek van %{user} - leave_a_comment: Los 'n opmerking - login_to_leave_a_comment: U moet eers %{login_link} alvorens u kommentaar kan - lewer + user_title: '%{user} se dagboek' + leave_a_comment: Lewer kommentaar + login_to_leave_a_comment: '%{login_link} om kommentaar te lewer' login: Meld aan save_button: Stoor no_such_entry: - title: Die opgevraagde dagboekinskrywing bestaan nie - heading: Die inskrywing met id %{id} bestaan nie - body: Jammer, daar is geen dagboekinskrywing of kommentaar met die id %{id} - nie. Kontroleer u spelling, of miskien is die skakel waarop u gekliek het - verkeerd. + title: Geen só 'n dagboekinskrywing + heading: 'Geen inskrywing met die id: %{id}' + body: Jammer, geen dagboekinskrywing of kommentaar met die id %{id} bestaan + nie. Gaan u spelling na, of u het moontlik op 'n foutiewe skakel geklik. diary_entry: - posted_by: Gepos deur %{link_user} op %{created} in %{language_link} - comment_link: Lewer kommentaar op hierdie bydrae - reply_link: Antwoord op hierdie bydrae + posted_by: Plasing deur %{link_user} op %{created} in %{language_link} + comment_link: Lewer hierop kommentaar + reply_link: Antwoord hierop comment_count: - one: 1 reaksie - other: '%{count} reaksies' - edit_link: Wysig hierdie inskrywing - hide_link: Versteek die inskrywing - confirm: Bevestig + zero: Geen opmerkings + one: '%{count} opmerking' + other: '%{count} opmerkings' + edit_link: Redigeer hierdie inskrywing + hide_link: Steek dié inskrywing weg + confirm: Bekragtig diary_comment: comment_from: Kommentaar van %{link_user} op %{comment_created_at} - hide_link: Versteek die opmerking - confirm: Bevestig + hide_link: Steek die opmerking weg + confirm: Bekragtig location: location: 'Ligging:' view: Wys - edit: Wysig + edit: Redigeer feed: user: - title: OpenStreetMap dagboekinskrywings van %{user} - description: Onlangse OpenStreetMap dagboekinskrywings van %{user} + title: OpenStreetMap-dagboekinskrywings deur %{user} + description: Onlangse OpenStreetMap-dagboekinskrywings deur %{user} language: title: OpenStreetMap dagboekinskrywings in %{language_name} - description: Onlangse dagboekinskrywings van OpenStreetMap-gebruikers in %{language_name} + description: Onlangse dagboekinskrywings deur OpenStreetMap-gebruikers in + %{language_name} all: - title: OpenStreetMap dagboekinskrywings - description: Onlangse dagboekinskrywings van OpenStreetMap-gebruikers + title: OpenStreetMap-dagboekinskrywings + description: Onlangse dagboekinskrywings deur OpenStreetMap-gebruikers comments: + post: Plasing when: Wanneer + comment: Kommentaar + ago: '%{ago} gelede' + newer_comments: Jongste Kommentaar + older_comments: Ouer Kommentaar export: + title: Voer Uit start: - area_to_export: Area om te eksporteer - manually_select: Kies 'n ander gebied handmatig - format_to_export: Lêerformaat + area_to_export: Area om uit te voer + manually_select: Kies self 'n ander area + format_to_export: Formaat om uit te voer osm_xml_data: OpenStreetMap XML-data - embeddable_html: HTML-kode + map_image: Kaartbeeld (wys standaardlaag) + embeddable_html: Versteekbare HTML-kode licence: Lisensie - export_details: OpenStreetMap se data is gelisensieer onder die Creative - Commons Erkenning-Insgelyks Deel 2.0 lisensie. + export_details: OpenStreetMap se data word ingevolge die + (ODbL) gelisensieer. + too_large: + advice: 'Ingeval die uitvoering hierbo misluk, oorweeg asseblief een van die + volgende bronne:' + body: Hierdie gebied is te groot om as OpenStreenMap XML Data uitgevoer te + word. Verdiep asseblief die kamerablik of kies 'n kleiner gebied. Wend andersins + een van die bronne hieronder aan om massadata af te laai. + planet: + title: Planeet OSM options: Voorkeure format: Formaat scale: Skaal max: maksimum - image_size: 'Prentgrootte:' - zoom: Zoom + image_size: Beeldgrootte + zoom: Vergroot add_marker: Plaas 'n merker op die kaart latitude: 'Breedte:' longitude: 'Lengte:' - output: Afvoer - export_button: Eksporteer + output: Uitset + paste_html: Plak HTML om in die webblad te versteek + export_button: Uitvoer geocoder: search: title: - latlon: Resultate vanaf intern - us_postcode: Resultate vanaf Geocoder.us - uk_postcode: Resultate vanaf NPEMap / - FreeThe Postcode - ca_postcode: Resultate vanaf Geocoder.CA - osm_nominatim: Resultate vanaf OpenStreetMap + latlon: Uitslae vooruitspruitend intern + uk_postcode: Uitslae vanaf NPEMap / FreeThe + Postcode + ca_postcode: Uitslae vanaf Geocoder.CA + osm_nominatim: Uitslae vanaf OpenStreetMap Nominatim - geonames: Resultate vanaf GeoNames - geonames_reverse: Resultate vanaf GeoNames + geonames: Uitslae vanaf GeoNames + geonames_reverse: Uitslae vanaf GeoNames search_osm_nominatim: prefix: aerialway: - cable_car: Kabelkar + cable_car: Sweefspoor aeroway: + aerodrome: Vliegveld gate: Hek + helipad: Helikopterplatform + runway: Aanloopbaan + taxiway: Rybaan + terminal: Terminaal amenity: + animal_shelter: Dierebeskermingsvereniging arts_centre: Kunssentrum atm: OTM bank: Bank bar: Kroeg - bench: Bank + bbq: Braai + bench: Bankie bicycle_parking: Fietsparkering - bicycle_rental: Fietsverhuring + bicycle_rental: Fietshuur + biergarten: Biertuin + boat_rental: Boothuur brothel: Bordeel bureau_de_change: Wisselkantoor bus_station: Bushalte cafe: Kafee - car_rental: Motorverhuring + car_rental: Motorverhuurder + car_sharing: Saam-ry car_wash: Karwas - casino: Casino - cinema: Bioskoop + casino: Dobbelhuis + charging_station: Herlaaistasie + childcare: Kindersorg + cinema: Rolprentteater clinic: Kliniek + clock: Klok college: Kollege - community_centre: Gemeenskap-sentrum + community_centre: Gemeenskapsentrum courthouse: Hof crematorium: Krematorium dentist: Tandarts @@ -249,12 +406,15 @@ af: embassy: Ambassade emergency_phone: Noodtelefoon fast_food: Wegneemetes - ferry_terminal: Veerterminaal + ferry_terminal: Pontterminaal fire_hydrant: Brandkraan fire_station: Brandweerstasie + food_court: Kosarea fountain: Fontein fuel: Brandstof + gambling: Dobbelary grave_yard: Begraafplaas + gym: Fiksheidsentrum / Gim health_centre: Gesondheidsentrum hospital: Hospitaal hunting_stand: Jagtoring @@ -263,20 +423,23 @@ af: library: Biblioteek market: Mark marketplace: Markplein + monastery: Monnikeklooster + motorcycle_parking: Motorfietsparkering nightclub: Nagklub nursery: Kleuterskool - nursing_home: Verpleeghuis + nursing_home: Verpleging- en versorgingshuis office: Kantoor - parking: Parkade + parking: Parkering + parking_entrance: Parkeeringang pharmacy: Apteek - place_of_worship: Plek van aanbidding + place_of_worship: Plek van Aanbidding police: Polisie post_box: Posbus post_office: Poskantoor preschool: Kleuterskool prison: Tronk pub: Kroeg - public_building: Openbare gebou + public_building: Openbare Gebou reception_area: Ontvangsarea recycling: Herwinningspunt restaurant: Restaurant @@ -285,22 +448,30 @@ af: school: Skool shelter: Skuiling shop: Winkel + shower: Stort + social_centre: Maatskaplike Sentrum social_club: Sosiale klub - studio: Studio + studio: Ateljee swimming_pool: Swembad taxi: Taxi - telephone: Openbare telefoon + telephone: Openbare Telefoon theatre: Teater toilets: Toilette townhall: Stadsaal university: Universiteit veterinary: Veearts - waste_basket: Asblik + village_hall: Dorpsaal + waste_basket: Snippermandjie + waste_disposal: Stortingsterrein youth_centre: Jeugsentrum boundary: administrative: Administratiewe grens - national_park: Nasionale park + national_park: Nasionale Park + protected_area: Beskermingsgebied bridge: + aqueduct: Waterbrug + suspension: Hangbrug + viaduct: Viaduk "yes": Brug building: "yes": Gebou @@ -309,36 +480,52 @@ af: carpenter: Skrynwerker electrician: Elektrisiën gardener: Tuinier + painter: Verwer photographer: Fotograaf plumber: Loodgieter shoemaker: Skoenmaker + tailor: Snyer + "yes": Handwerkwinkel + emergency: + ambulance_station: Ambulansstasie + defibrillator: Defibrillator + landing_site: Noodlandingsarea + phone: Noodtelefoon highway: + abandoned: Verlate Snelweg bridleway: Ruiterpad + bus_guideway: Toegewyde busbaan bus_stop: Bushalte construction: Snelweg in aanbou cycleway: Fietspad + elevator: Hysbak emergency_access_point: Noodtoeganspunt footway: Voetpad ford: Drif + milestone: Mylpaal motorway: Snelweg motorway_junction: Snelwegknooppunt path: Pad - pedestrian: Voetpad + pedestrian: Voetgangerspad platform: Platform - primary: Primêre pad - primary_link: Primêre pad + primary: Primêre Pad + primary_link: Primêre Pad + proposed: Voorgestelde pad raceway: Renbaan residential: Residensiële straat + rest_area: Rusarea road: Pad - secondary: Sekondêre pad - secondary_link: Sekondêre pad + secondary: Sekondêre Pad + secondary_link: Sekondêre Pad service: Dienspad - services: Snelweg Dienste - speed_camera: Spoedkamera + services: Snelwegdienste + speed_camera: Snelheidskamera steps: Trappe - street_lamp: Straatlamp - tertiary: Tersiêre pad + street_lamp: Straatlig + tertiary: Tersiêre Pad + tertiary_link: Tersiêre pad track: Spoor + traffic_signals: Verkeerstekens trail: Wandelpad trunk: Hoofroete trunk_link: Hoofroete @@ -348,102 +535,165 @@ af: historic: archaeological_site: Argeologiese werf battlefield: Slagveld + boundary_stone: Grenspaal building: Historiese gebou + bunker: Bomskuiling castle: Kasteel church: Kerk + city_gate: Stadspoort + citywalls: Stadsmure + fort: Fort + heritage: Erfenisterrein house: Huis icon: Ikoon manor: Landgoed memorial: Gedenkteken mine: Myn monument: Monument + roman_road: Romeinse pad ruins: Ruïnes + stone: Steen + tomb: Graf tower: Toring - wayside_cross: Kruis langs die pad - wayside_shrine: Altaar langs die pad + wayside_cross: Padkruis + wayside_shrine: Padaltaar wreck: Wrak + junction: + "yes": Verkeersaansluiting landuse: allotments: Volkstuine + basin: Kom cemetery: Begraafplaas - commercial: Kommersiële gebied + commercial: Handelsarea + conservation: Natuurbewaring construction: Konstruksie farm: Plaas farmland: Plaasgrond farmyard: Plaaswerf forest: Woud + garages: Vulstasies grass: Gras - industrial: Industriële gebied + industrial: Nywerheidsgebied landfill: Stortingsterrein + meadow: Vleiweiding military: Militêre gebied mine: Myn - quarry: Steengroewe + orchard: Vrugteboord + quarry: Steengroef railway: Spoorweg + recreation_ground: Ontspanningsterrein reservoir: Reservoir residential: Woongebied retail: Kleinhandel vineyard: Wingerd + "yes": Landgebruik leisure: - beach_resort: Strandoort - fishing: Visvangarea + beach_resort: Strandoord + bird_hide: Voëlkykhuisie + club: Klub + dog_park: Hondepark + fishing: Visvanggebied + fitness_centre: Fiksheidsentrum garden: Tuin golf_course: Gholfbaan - ice_rink: Ysbaan + horse_riding: Perdry + ice_rink: Ysskaatsbaan marina: Marina - miniature_golf: Minigolf + miniature_golf: Mini-gholf nature_reserve: Natuurreservaat park: Park pitch: Sportveld playground: Speelgrond - sports_centre: Sport-sentrum + recreation_ground: Ontspanningsterrein + resort: Oord + sauna: Sauna + slipway: Glybaan + sports_centre: Sportsentrum stadium: Stadion swimming_pool: Swembad track: Atletiekbaan water_park: Waterspeelpark + "yes": Vrye tyd + man_made: + lighthouse: Vuurtoring + pipeline: Pypleiding + tower: Toring + works: Fabriek + "yes": Mensgemaak + military: + airfield: Miliêre vliegveld + barracks: Barakke + bunker: Bomskuiling + mountain_pass: + "yes": Bergpas natural: bay: Baai beach: Strand cape: Kaap cave_entrance: Grotingang - cliff: Kloof + cliff: Krans crater: Krater + dune: Duin + fell: Heuwel fjord: Fjord forest: Woud geyser: Geiser glacier: Gletser + grassland: Grasveld heath: Heide hill: Heuwel island: Eiland land: Land marsh: Moeras + moor: Vleiland mud: Modder peak: Piek point: Punt reef: Rif - ridge: Bergkam - rock: Rotse - scree: Puin + ridge: Bergrif + rock: Rots + saddle: Saal + sand: Sand + scree: Berghellingspuin scrub: Struikgewas spring: Bron + stone: Steen strait: Seestraat tree: Boom valley: Vallei - volcano: Vulkaan + volcano: Vuurspuwende Berg water: Water - wetland: Moeras + wetland: Vleiland wood: Bos + office: + accountant: Boekhouer + administrative: Administrasie + architect: Argitek + company: Maatskappy + estate_agent: Eiendomsagent + insurance: Versekeringskantoor + lawyer: Prokureur + telecommunication: Telekommunikasiekantoor + travel_agent: Reisagent + "yes": Kantoor place: + allotments: Toekennings + block: Blokkeer airport: Lughawe city: Stad country: Land county: Distrik farm: Plaas - hamlet: Dorpie + hamlet: Gehuggie house: Huis houses: Huise island: Eiland islet: Eilandjie + isolated_dwelling: Geïsoleerde woning locality: Ligging + moor: Vleiland municipality: Munisipaliteit + neighbourhood: Woonbuurt postcode: Poskode region: Streek sea: See @@ -451,33 +701,43 @@ af: subdivision: Onderverdeling suburb: Voorstad town: Dorp - unincorporated_area: Uitgesluite Ruimte - village: Dorp + unincorporated_area: Uitgeslote Ruimte + village: Gehug + "yes": Plek railway: + abandoned: Verlate Spoorweg construction: Spoor in aanbou - disused_station: Ongebruikte spoorwegstasie + disused: Spoorweg in onbruik + disused_station: Spoorwegstasie in onbruik funicular: Kabelspoorweg halt: Treinhalte historic_station: Historiese spoorwegstasie junction: Spoorwegkruising level_crossing: Spooroorgang + light_rail: Ligte spoor + miniature: Miniatuur spoorweg monorail: Monospoor narrow_gauge: Smalspoorweg - platform: Spoorweg-platform + platform: Spoorwegperron preserved: Historiese spoorweg + proposed: Voorgestelde spoorlyn station: Spoorwegstasie - subway: Metrostasie + subway: Duikwegspoor subway_entrance: Ondergrondse spoorwegingang switch: Spoogwegpunte + tram: Tremspoor tram_stop: Tremhalte shop: + antiques: Antiek / Oudhede art: Kunswinkel bakery: Bakkery beauty: Skoonheidssalon + beverages: Drankwinkel bicycle: Fietswinkel books: Boekwinkel + boutique: Boutique butcher: Slagter - car: Motorwinkel + car: Motorhandelaar car_parts: Motoronderdele car_repair: Motorherstel carpet: Mat-/tapytwinkel @@ -485,13 +745,17 @@ af: chemist: Apteek clothes: Klerewinkel computer: Rekenaarwinkel - convenience: Gemakswinkel - copyshop: Fotokopie-winkel - cosmetics: Kosmetiesewinkel + confectionery: Banketbakkery + convenience: Geriefswinkel + copyshop: Fotostaatwinkel + cosmetics: Kosmetiekwinkel + deli: Deli + department_store: Afdelingswinkel discount: Afslagwinkel - doityourself: Doen-dit-self-winkel + doityourself: Doen-Dit-Self-winkel dry_cleaning: Droogskoonmaker electronics: Elektronikawinkel + estate_agent: Eiendomsagent farm: Plaaswinkel fashion: Modewinkel fish: Viswinkel @@ -501,15 +765,16 @@ af: furniture: Meubels gallery: Galery garden_centre: Kwekery/Tuinsentrum - general: Algemene winkel - gift: Geskenkwinkel - grocery: Kruideniersware-winkel + general: Algemene Handelaar + gift: Geskenkewinkel + greengrocer: Groentehandelaar + grocery: Kruidenierswinkel hairdresser: Haarkapper - hardware: Hardwarewinkel - hifi: Hi-Fi + hardware: Hardewarewinkel + hifi: Hoëtrou insurance: Versekering jewelry: Juwelierswinkel - kiosk: Kioskwinkel + kiosk: Kiosk laundry: Wassery mall: Winkelsentrum market: Mark @@ -519,27 +784,33 @@ af: newsagent: Nuusagent optician: Oogkundige organic: Organiese koswinkel - outdoor: Buitelug-winkel + outdoor: Buitelugwinkel pet: Troeteldierwinkel + pharmacy: Apteek photo: Fotowinkel salon: Skoonheidssalon + second_hand: Tweedehandswinkel shoes: Skoenwinkel shopping_centre: Winkelsentrum sports: Sportwinkel - stationery: Skryfbehoeftes-winkel + stationery: Skryfbehoeftewinkel supermarket: Supermark + tailor: Snyer toys: Speelgoedwinkel - travel_agency: Reisburo - video: Video-winkel + travel_agency: Reisagentskap + video: Videowinkel + "yes": Winkel tourism: alpine_hut: Berghut + apartment: Woonstel artwork: Kunswerk - attraction: Attraksie + attraction: Trekpleister bed_and_breakfast: Bed en Ontbyt cabin: Hut camp_site: Kampterrein caravan_site: Karavaanpark chalet: Chalet + gallery: Galery guest_house: Gastehuis hostel: Jeugherberg hotel: Hotel @@ -551,20 +822,32 @@ af: viewpoint: Uitkykpunt zoo: Dieretuin tunnel: + culvert: Duiksloot "yes": Tonnel waterway: + artificial: Kunstmatige waterweg boatyard: Skeepswerf canal: Kanaal dam: Dam + derelict_canal: Verlate Kanaal ditch: Sloot dock: Dokke drain: Afvoerkanaal lock: Sluis lock_gate: Sluisdeur + mooring: Kaai rapids: Stroomversnelling river: Rivier stream: Stroom + wadi: Droë woestynrivierbedding waterfall: Waterval + weir: Stuwal + "yes": Waterweg + admin_levels: + level4: Staatsgrens + level5: Streekgrens + level8: Stadsgrens + level9: Dorpsgrens description: title: geonames: Ligging vanaf GeoNames @@ -574,101 +857,167 @@ af: places: Plekke results: no_results: Geen resultate gevind nie - more_results: Meer resultate + more_results: Nog resultate layouts: logo: alt_text: OpenStreetMap-logo - home: tuis + home: Keer terug na tuisoord logout: Meld af log_in: Meld aan - log_in_tooltip: Teken aan met 'n bestaande rekening + log_in_tooltip: Teken met 'n bestaande rekening aan sign_up: Registreer - sign_up_tooltip: Skep 'n rekening vir wysigings - edit: Wysig + start_mapping: Begin Karteer + sign_up_tooltip: Skep 'n rekening vir redigeerregte + edit: Redigeer history: Geskiedenis - export: Eksporteer + export: Voer uit data: Data + export_data: Voer data uit gps_traces: GPS-spore - gps_traces_tooltip: Beheer GPS-spore + gps_traces_tooltip: Bestuur GPS-spore user_diaries: Gebruikersdagboeke user_diaries_tooltip: Wys gebruikersdagboeke - tag_line: Die vrye wiki-wêreldkaart + edit_with: Redigeer met %{editor} + tag_line: Die Vrye Wiki-Wêreldkaart intro_header: Welkom by OpenStreetMap! - intro_text: OpenStreetMap is 'n kaart van die wêreld, geskep deur gewone mense. - Dis gratis om te gebruik onder 'n oop lisensie. - intro_2_create_account: Skep gebruikerrekening - osm_read_only: Die OpenStreetMap-databasis kan op die oomblik slegs gelees word - aangesien noodsaaklik onderhoud tans uitgevoer word. + intro_text: OpenStreetMap is wêreldkaart deur gewone mense geskep. Die gebruik + daarvan is gratis en val onder 'n oop-lisensie. + intro_2_create_account: Skep 'n gebruikerrekening + partners_partners: vennote + osm_offline: Instandhouding word tans op die OpenStreetMap-databasis uitgevoer; + derhalwe is dit tans vanlyn tot en met die instandhouding afgehandel is. + osm_read_only: Aangesien noodsaaklik onderhoud tans op die OpenStreetMap-databasis + uitgevoer word, bied dit tans slegs leesregte. donate: Ondersteun OpenStreetMap deur aan die Hardeware Opgradeer-fonds te %{link}. help: Hulp about: Aangaande copyright: Kopiereg community: Gemeenskap + community_blogs: Gemeenskapblogs + foundation: Stigting foundation_title: Die OpenStreetMap-stigting make_a_donation: - title: Ondersteun OpenStreetMap met 'n geldelike donasie - text: Maak 'n donasie - learn_more: Meer inligting + title: Ondersteun OpenStreetMap met 'n geldelike skenking + text: Skenk aan die projek + learn_more: Kom meer te wete more: Meer license_page: foreign: - title: Oor hierdie vertaling + title: Aangaande dié vertaling + native: + title: Aangaande dié blad + mapping_link: begin karteer + legal_babble: + title_html: Kopiereg en Lisensie + intro_2_html: |- + Dit staan u vry om ons data te kopieer, versprei, versend of aan te maps, mits u erkenning aan OpenStreetMap en die bydraers gee. Indien u ons data wysig of daarop voortbou, mag u dit slegs in terme van dieselfde lisensie versprei. Die volledige legal + code verduidelik u regte en verantwoordelikhede. + credit_title_html: Hoe om na OpenStreetMap te verwys + contributors_title_html: Ons bydraers + infringement_title_html: Kopieregoortreding welcome_page: title: Welkom! + basic_terms: + title: Grondliggende begrippe vir kartering + paragraph_1_html: OpenStreetMap bevat 'n gedeelte van ons eie vakbegrippe. Hier + is 'n paar wat handig te pas sal kom. + rules: + title: Reëls! + questions: + title: Enige vrae? + start_mapping: Begin Karteer + add_a_note: + title: Geen tyd om te redigeer? Voeg 'n opmerking by! + fixthemap: + how_to_help: + title: Hoe om te help + join_the_community: + title: Sluit by die gemeenskap aan + other_concerns: + title: Andere aangeleenthede help_page: + welcome: + url: /welkom mailing_lists: title: Poslyste + forums: + title: Forums + wiki: + url: http://wiki.openstreetmap.org/ + title: wiki.openstreetmap.org + about_page: + next: Volgende + local_knowledge_title: Plaaslike Kennis + community_driven_title: Gemeenskapsgedrewe + legal_title: Wetlik + partners_title: Vennote notifier: diary_comment_notification: - subject: '[OpenStreetMap] %{user} het kommentaar op u dagboekinskrywing gelewer' + subject: '[OpenStreetMap] %{user} het ''n kommentaar oor ''n dagboekinskrywing + gemaak.' hi: Hallo %{to_user}, + header: '%{from_user} het kommentaar oor die OpenStreetMap dagboekinskrywing + met die tema %{subject} gelewer:' message_notification: hi: Hallo %{to_user}, friend_notification: + hi: Hallo %{to_user}, subject: '[OpenStreetMap] %{user} het u as ''n vriend bygevoeg' gpx_notification: greeting: Hallo, your_gpx_file: Dit lyk soos jou GPX-lêer with_description: met die beskrywing - and_the_tags: 'en die volgende etikette:' - and_no_tags: en geen etikette. + and_the_tags: 'en die volgende merkers:' + and_no_tags: en geen merkers nie. failure: - more_info_2: 'hulle kan gevind word by:' + more_info_2: 'hulle kan gevind word te:' signup_confirm: subject: '[OpenStreetMap] Welkom by OpenStreetMap' + greeting: Hallo! + created: Iemand (hopelik u) het pas 'n rekening op %{site_url} geskep. + confirm: 'Voordat ons iets doen, verlang ons ''n bevestiging dat dié versoek + inderdaad van u afkomstig is. As dit so is, klik op die onderstaande skakel + om u rekening te bevestig:' + welcome: Nadat u u rekening bevestig het, bied ons u graag addisionele inligting + sodat u kan wegtrek. email_confirm: subject: '[OpenStreetMap] Bevestig u e-posadres' email_confirm_plain: greeting: Hallo, email_confirm_html: greeting: Hallo, - hopefully_you: Iemand (hopelik u) wil graag sy e-posadres op %{server_url} verander - na %{new_address}. - click_the_link: As dit u is, kliek op die onderstaande skakel om die verandering + hopefully_you: Iemand (hopelik u) wil graag hul e-posadres op %{server_url} + verander na %{new_address}. + click_the_link: As dit u is, klik die onderstaande skakel om die verandering te bevestig. lost_password: - subject: '[OpenStreetMap] Versoek herstel van wagwoord' + subject: '[OpenStreetMap] Rig wagwoordherstel versoek' lost_password_plain: greeting: Hallo, - click_the_link: As dit u is, kliek op die onderstaande skakel om die wagwoord - te herstel. + click_the_link: As dit u is, klik die onderstaande skakel om u wagwoord te herstel. lost_password_html: greeting: Hallo, + note_comment_notification: + anonymous: '''n Anonieme gebruiker' + greeting: Hallo, + changeset_comment_notification: + hi: Hallo %{to_user}, + greeting: Hallo, message: inbox: - title: Inboks - my_inbox: My inboks - outbox: uitboks - from: Vanaf + title: In-vakkie + my_inbox: My in-vakkie + outbox: uit-vakkie + from: Van subject: Onderwerp date: Datum - no_messages_yet: U het nog geen boodskappe nie. Hoekom kontak u nie sommige - van die %{people_mapping_nearby_link} nie? + no_messages_yet: U het nog geen boodskappe nie. Waarom tree u nie met sommige + van die %{people_mapping_nearby_link} in verbinding nie? people_mapping_nearby: nabygeleë karteerders message_summary: unread_button: Merk as ongelees read_button: Merk as gelees - reply_button: Antwoord + reply_button: Beantwoord delete_button: Verwyder new: title: Stuur boodskap @@ -676,56 +1025,62 @@ af: subject: Onderwerp body: Teks send_button: Stuur - back_to_inbox: Terug na inboks + back_to_inbox: Terug na in-vakkie message_sent: Boodskap is gestuur no_such_message: - title: Die boodskap bestaan nie - heading: Die boodskap bestaan nie + title: Geen so 'n boodskap nie + heading: Geen so 'n boodskap nie outbox: - title: Uitboks + title: Uit-vakkie my_inbox: My %{inbox_link} - inbox: inboks - outbox: uitboks + inbox: in-vakkie + outbox: uit-vakkie to: Aan subject: Onderwerp date: Datum - no_sent_messages: U het nog geen boodskappe gestuur nie. Hoekom kontak u nie - sommige van die %{people_mapping_nearby_link} nie? + no_sent_messages: U het nog geen boodskappe gestuur nie. Waarom tree u nie met + sommige van die %{people_mapping_nearby_link} in verbinding nie? people_mapping_nearby: nabygeleë karteerders read: title: Lees boodskap from: Van subject: Onderwerp date: Datum - reply_button: Antwoord + reply_button: Beantwoord unread_button: Merk as ongelees + delete_button: Skrap + back: Terug to: Aan sent_message_summary: delete_button: Verwyder mark: - as_read: Boodskap gemerk as gelees - as_unread: Boodskap gemerk as ongelees + as_read: Boodskap as gelees gemerk + as_unread: Boodskap as ongelees gemerk delete: deleted: Boodskap is verwyder site: index: - permalink: Permanente skakel - shortlink: Kort skakel + permalink: Perma-skakel + shortlink: Kortskakel edit: user_page_link: gebruikersbladsy anon_edits_link_text: Lees waarom dit die geval is. sidebar: - search_results: Soekresultate + search_results: Soekuitslae close: Sluit search: search: Soek - get_directions_title: Kry aanwysings tussen twee punte - where_am_i: Waar is ek? + get_directions: Kry rigtingaanwysings + get_directions_title: Kry rigtingaanwysings tussen twee punte + from: Vanaf + to: Na + where_am_i: Waar bevind ek my? submit_text: Soek key: table: entry: motorway: Snelweg + main_road: Hoofweg trunk: Hoofroete primary: Primêre pad secondary: Sekondêre pad @@ -733,6 +1088,7 @@ af: track: Spoor bridleway: Ruiterpad cycleway: Fietspad + cycleway_national: Nasionale fietsroete footway: Voetpad rail: Spoorweg subway: Ondergrondse spoorweg @@ -740,11 +1096,11 @@ af: - Ligte spoor - trem cable: - - Kabelkar + - Sweefspoor - stoelhyser runway: - Lughawe aanloopbaan - - taxibaan + - vliegtuigrybaan apron: - Lughaweplatform - terminaal @@ -757,98 +1113,117 @@ af: common: - Gemeen - weiland - retail: Winkelgebied - industrial: Industriële gebied + retail: Handelsgebied + industrial: Nywerheidsgebied commercial: Kommersiële gebied heathland: Heide lake: - Meer - reservoir farm: Plaas - brownfield: Braakveld terrein + brownfield: Braakveldterrein cemetery: Begraafplaas allotments: Volkstuine pitch: Sportveld - centre: Sport-sentrum + centre: Sportsentrum reserve: Natuurreservaat military: Militêre gebied school: - Skool - universiteit - building: Belangrike gebou + building: Betekenisvolle gebou station: Spoorwegstasie summit: - Piek - piek tunnel: Strepieomhulsel = tonnel bridge: Swartomhulsel = brug - private: Privaat toegang + private: Privaat-toegang destination: Bestemmingsverkeer - construction: Paaie onder konstruksie + construction: Paaie in aanbou + bicycle_shop: Fietswinkel + bicycle_parking: Fietsparkering + toilets: Toilette + richtext_area: + edit: Redigeer + preview: Voorskou + markdown_help: + headings: Opskrifte + heading: Opskrif + unordered: Ongeordende lys + ordered: Geordende lys + first: Eerste item + second: Tweede item + link: Skakel + text: Teks + image: Beeld + alt: Alternatiewe teks + url: URL trace: create: upload_trace: Laai GPS-spore op edit: - title: Wysig spoor %{name} + title: Redigeer tans spoor %{name} heading: Wysig spoor %{name} filename: 'Lêernaam:' - download: aflaai + download: laai af uploaded_at: 'Opgelaai op:' points: 'Punte:' start_coord: 'Beginkoördinaat:' map: kaart - edit: wysig + edit: redigeer owner: 'Eienaar:' description: 'Beskrywing:' - tags: 'Etikette:' - tags_help: met kommas geskei - save_button: Stoor wysigings + tags: 'Merkers:' + tags_help: komma afgebaken + save_button: Stoor Wysigings visibility: 'Sigbaarheid:' visibility_help: wat beteken dit? trace_form: upload_gpx: 'Laai GPX-lêer op:' description: 'Beskrywing:' - tags: 'Etikette:' - tags_help: met kommas geskei + tags: 'Merkers:' + tags_help: komma afgebaken visibility: 'Sigbaarheid:' visibility_help: wat beteken dit? upload_button: Laai op help: Hulp trace_header: + upload_trace: Laai 'n GPS-spoor op see_all_traces: Wys alle spore see_your_traces: Sien al u spore trace_optionals: - tags: Etikette + tags: Merkers view: title: Besigtig spoor %{name} heading: Besigtig spoor %{name} - pending: BESIG + pending: HANGEND filename: 'Lêernaam:' download: laai af uploaded: 'Opgelaai op:' points: 'Punte:' start_coordinates: 'Beginkoördinaat:' map: kaart - edit: wysig + edit: redigeer owner: 'Eienaar:' description: 'Beskrywing:' - tags: 'Etikette:' + tags: 'Merkers:' none: Geen edit_track: Wysig hierdie spoor delete_track: Verwyder hierdie spoor - trace_not_found: Spoor nie gevind nie! + trace_not_found: Spoor onverkrygbaar! visibility: 'Sigbaarheid:' trace_paging_nav: showing_page: Bladsy %{page} trace: - pending: BESIG + pending: HANGEND count_points: '%{count} punte' ago: '%{time_in_words_ago} gelede' more: meer - trace_details: Wys spoor besonderhede + trace_details: Wys Besonderhede van die Spoor view_map: Wys kaart - edit: wysig - edit_map: Wysig kaart + edit: redigeer + edit_map: Redigeer Kaart public: OPENBAAR identifiable: IDENTIFISEERBAAR private: PRIVAAT @@ -859,48 +1234,68 @@ af: public_traces: Openbare GPS-spore your_traces: U GPS-spore public_traces_from: Openbare GPS-spore van %{user} - tagged_with: geëtiketteer met %{tags} + tagged_with: gemerk met %{tags} delete: - scheduled_for_deletion: Spoor is geskeduleer vir verwydering + scheduled_for_deletion: Spoor is vir verwydering geoormerk make_public: made_public: Spoor is openbaar gemaak oauth: oauthorize: allow_read_prefs: lees u gebruikersvoorkeure. allow_write_prefs: verander jou gebruikersvoorkeure. - allow_write_api: die kaart wysig. + allow_write_api: wysig die kaart. allow_write_gpx: laai GPS-spore op. + allow_write_notes: wysig opmerkings. + grant_access: Verleen toegang + oauthorize_success: + title: Magtigingsversoek toegestaan + allowed: U het die program %{app_name} toegang tot u rekening verleen. + verification: Die bevestigingskode is %{code} + oauthorize_failure: + title: Magtigingsversoek het misluk + denied: U het die program %{app_name} toegang tot u rekening geweier. + invalid: Die magtigingsteken is ongeldig. + revoke: + flash: U het die teken vir %{application} teruggetrek. + permissions: + missing: U het nie die program toegang tot hierdie fasilititeit verleen nie. oauth_clients: new: title: Registreer 'n nuwe toepassing submit: Registreer edit: - title: Wysig u toepassing - submit: Wysig + title: Redigeer u program + submit: Redigeer show: + title: OAuth-besonderhede vir %{app_name} + secret: 'Verbruikersgeheim:' + url: Versoek teken-URL + access_url: 'Toegangsteken URL:' authorize_url: 'Magtig URL:' - edit: Wysig details - allow_read_prefs: lees hulle gebruikersvoorkeure. - allow_write_diary: skep dagboekinskrywings, lewer kommentaar en maak vriende. + edit: Redigeer Besonderhede + confirm: Is u seker? + allow_read_prefs: lees hul gebruikersvoorkeure. + allow_write_diary: skep dagboekinskrywings, maak opmerkings en maak vriende. allow_write_api: wysig die kaart. allow_write_gpx: laai GPS-spore op. index: - title: My OAuth-details - application: Toepassingnaam + title: My OAuth-gegewens + application: Programnaam issued_at: Uitgereik op revoke: Herroep! - my_apps: My kliënt-toepassing - register_new: Registreer u toepassing + my_apps: My Kliënt-programme + register_new: Registreer u program form: name: Naam required: Verplig url: Toepassing-URL support_url: Ondersteunings-URL - allow_read_prefs: lees hulle gebruikersvoorkeure. + allow_read_prefs: lees hul gebruikersvoorkeure. allow_write_prefs: verander hulle gebruikersvoorkeure. - allow_write_diary: skep dagboekinskrywings, lewer kommentaar en maak vriende. + allow_write_diary: skep dagboekinskrywings, lewer kommentaar en ontmoet vriende. + allow_write_api: wysig die kaart. not_found: - sorry: Jammer, die %{type} kon nie gevind word nie. + sorry: Jammer, die %{type} blyk onverkrygbaar te wees. user: login: title: Meld aan @@ -910,17 +1305,18 @@ af: remember: Onthou my lost password link: Wagwoord vergeet? login_button: Meld aan + register now: Skryf nou in auth failure: Jammer, kon nie met hierdie inligting aanmeld nie. logout: title: Teken af - heading: Teken van OpenStreetMap af + heading: Meld van OpenStreetMap af logout_button: Teken af lost_password: - title: Wagwoord vergeet + title: Wagwoord verloor heading: Wagwoord vergeet? email address: 'E-posadres:' new password button: Herstel wagwoord - notice email cannot find: Kon nie die e-posadres vind nie, jammer. + notice email cannot find: E-posadres is ongelukkig onverkrygbaar, jammer. reset_password: title: Herstel wagwoord heading: Herstel wagwoord vir %{user} @@ -929,19 +1325,29 @@ af: reset: Herstel wagwoord flash changed: U wagwoord is verander. new: - title: Skep rekening - license_agreement: Deur 'n rekening hier te skep bevestig u dat u akkoord gaan - met voorwaarde dat al die werk wat u na OpenStreetMap oplaai onder die Creative Commons-lisensie - (by-sa) gelisensieer word (nie-eksklusief). + title: Teken aan + about: + header: Gratis en redigeerbaar + html:

      Anders as ander kaarte, skep mense soos jy OpenStreetMap geheel en + al; daarbenewens is dit gratis vir enigeen om te herstel, by te werk, af + te laai en te benut.

      Registreer om 'n bydrae te lewer. Ons sal dan + u registrasie per e-pos bevestig.

      + license_agreement: Wanneer u u rekening bevestig, sal u ooreenkomstig die bepalings + vir bydraers moet toestem. email address: 'E-posadres:' - confirm email address: 'Bevestig E-posadres:' - not displayed publicly: Word nie publiek vertoon nie (sien geheimhoudingbeleid) - display name: 'Vertoon naam:' + confirm email address: 'Bevestig e-posadres:' + not displayed publicly: U adres word nie openbaar gemaak nie; raadpleeg ons + privaatheidsbeleid + vir verdere inligting. + display name: 'Skermnaam:' + display name description: U gebruikernaam wat openbaar verskyn. U kan dit wel + later nog onder voorkeure wysig. password: 'Wagwoord:' confirm password: 'Bevestig wagwoord:' - continue: Gaan voort + use external auth: Gebruik andersins 'n derde party om mee aan te meld + continue: Teken aan terms accepted: Dankie dat u die nuwe bydraerooreenkoms aanvaar het! terms: title: Bydraerooreenkoms @@ -951,24 +1357,24 @@ af: legale_names: france: Frankryk italy: Italië - rest_of_world: Res van die wêreld + rest_of_world: Die res van die wêreld no_such_user: - title: Gebruiker bestaan nie + title: Geen so 'n gebruiker nie heading: Die gebruiker %{user} bestaan nie - body: Daar is geen gebruiker met die naam %{user} nie. Kontroleer u spelling, - of die skakel waarop u gekliek het is verkeerd. + body: Daar is geen gebruiker met die naam %{user} nie. Gaan u spelling na, of + u het moontlik op 'n foutiewe skakel geklik. view: - my diary: My dagboek + my diary: My Dagboek new diary entry: nuwe dagboekinskrywing - my edits: My wysigings - my traces: My spore - my settings: My voorkeure + my edits: My Redigerings + my traces: My Spore + my settings: My Instellings oauth settings: Oauth-instellings - blocks on me: blokkades op my - blocks by me: blokkades deur my - send message: Stuur boodskap + blocks on me: Versperrings vir u + blocks by me: Versperrings deur u + send message: Stuur Boodskap diary: Dagboek - edits: Wysigings + edits: Redigerings traces: Spore remove as friend: Verwyder as vriend add as friend: Voeg by as vriend @@ -980,16 +1386,16 @@ af: spam score: 'SPAM-telling:' description: Beskrywing user location: Ligging van gebruiker - if set location: As u u ligging stel, sal 'n pragtige kaart en ander inligting - hieronder verskyn. U kan u ligging stel in u %{settings_link}. - settings_link_text: voorkeure + if set location: Stel u tuisligging by %{settings_link} in om gebruikers naby + u te sien. + settings_link_text: instellings your friends: U vriende no friends: U het nog geen vriende bygevoeg nie. km away: '%{count}km vêr' m away: '%{count}m vêr' nearby users: Ander nabygeleë gebruikers - no nearby users: Daar is nog geen gebruikers wat erken dat hulle nabygeleë karterinswerk - doen nie. + no nearby users: Daar is nog geen ander gebruikers wat erken dat hulle kaarte + in die nabye gebied afrond nie. role: administrator: Hierdie gebruiker is 'n administrateur moderator: Hierdie gebruiker is 'n moderator @@ -997,66 +1403,77 @@ af: administrator: Ken adminregte toe moderator: Ken moderatorregte toe revoke: - administrator: Trek adminregte terug - moderator: Trek moderatorregte terug - block_history: wys blokkades ontvang - moderator_history: wys blokkades uitgedeel - create_block: blokkeer die gebruiker - activate_user: aktiveer hierdie gebruiker - deactivate_user: deaktiveer hierdie gebruiker - confirm_user: bevestig hierdie gebruiker - hide_user: versteek hierdie gebruiker - unhide_user: maak die gebruiker weer sigbaar - delete_user: skrap die gebruiker + administrator: Herroep adminregte + moderator: Herroep moderatorregte + block_history: Aktiewe Versperrings + moderator_history: Uitgevoerde Versperrings + create_block: Versper hierdie gebruiker + activate_user: Aktiveer hierdie gebruiker + deactivate_user: Deaktiveer hierdie gebruiker + confirm_user: Bevestig dié Gebruiker + hide_user: Versteek hierdie gebruiker + unhide_user: Wys hierdie gebruiker + delete_user: Skrap dié Gebruiker confirm: Bevestig popup: your location: U ligging nearby mapper: Nabygeleë karteerder friend: Vriend account: - title: Wysig rekening - my settings: My voorkeure + title: Redigeer rekening + my settings: My instellings current email address: 'Huidige e-posadres:' new email address: 'Nuwe e-posadres:' - email never displayed publicly: (word nie openbaar gemaak nie) + email never displayed publicly: (word nooit openbaar vertoon nie) public editing: - heading: 'Openbaar wysigings:' - enabled: Geaktiveer. U is nie anoniem nie en kan inligting wysig. - enabled link text: wat is dit? - disabled link text: hoekom kan ek niks wysig nie? + heading: 'Openbare redigerings:' + enabled: Geaktiveer. Nie anoniem nie en kan tog data redigeer. + enabled link text: wat is dié? + disabled link text: hoekom kan ek nie redigeer nie? contributor terms: - link text: wat is dit? + link text: wat is dié? profile description: 'Profielbeskrywing:' - preferred languages: 'Voorkeur tale:' + preferred languages: 'Verkose Tale:' image: 'Beeld:' - new image: Voeg beeld by + new image: Voeg 'n beeld by replace image: Vervang die huidige beeld home location: 'Tuisligging:' - no home location: U het nog nie u huis se ligging ingevoer nie. + no home location: U het nog geen tuisligging ingelees nie. latitude: 'Breedtegraad:' longitude: 'Lengtegraad:' - update home location on click: Opdateer tuisligging wanneer ek op die kaart - kliek? - save changes button: Stoor wysigings - make edits public button: Maak al my wysigings openbaar + update home location on click: Werk tuisligging by wanneer ek op die kaart klik? + save changes button: Stoor Wysigings + make edits public button: Stel al my redigerings openbaar return to profile: Terug na profiel - flash update success: U gebruikersinligting is verander. + flash update success: Gebruikersbesonderhede suksesvol bygewerk. confirm: - heading: Kontroleer u e-pos! - press confirm button: Kliek op "Bevestig" hieronder om u rekening aktiveer. + heading: Gaan u e-pos na! + introduction_1: Ons het u 'n e-pos ter bevestiging getuur. + introduction_2: Klik op die skakel in die e-pos en bevestig u rekening, dan + sal u kan karteer. + press confirm button: Klik 'bevestig' hieronder om u rekening te aktiveer. button: Bevestig + success: U rekening is bevestig. Dankie dat u aangeteken het! + already active: Hierdie rekening is reeds bevestig. + unknown token: Die bevestigingskode het reeds verval of bestaan nie. + reconfirm_html: Sou u van ons verlang om weer die e-pos ter bevestiging te stuur, + klik hier. + confirm_resend: + failure: Die gebruiker %{name} is nie gevind nie. confirm_email: - heading: Bevestig verandering van e-posadres + heading: Bevestig 'n verandering van e-posadres + press confirm button: Klik op die volgende knoppie om u e-posadres te bevestig. button: Bevestig - success: U e-posadres verandering is bevestig! + success: Die verandering van u e-posadres is bevestig! set_home: flash success: U tuisligging is suksesvol gestoor make_friend: + button: As vriend byvoeg success: '%{name} is nou u vriend!' failed: Jammer, kon nie %{name} as 'n vriend byvoeg nie. already_a_friend: U is reeds met %{name} bevriend. remove_friend: - success: '%{name} is uit u lys van vriende verwyder.' + success: '%{name} is uit u vriendekring verwyder.' not_a_friend: '%{name} is nie een van u vriende nie.' list: title: Gebruikers @@ -1064,7 +1481,7 @@ af: summary: '%{name} geskep vanaf %{ip_address} op %{date}' summary_no_ip: '%{name} geskep op %{date}' confirm: Bevestig geselekteerde gebruikers - hide: Versteek geselekteerde gebruikers + hide: Versteek verkose gebruikers empty: Geen gebruikers gevind nie suspended: webmaster: webmeester @@ -1080,92 +1497,123 @@ af: user_block: not_found: sorry: Jammer, die gebruiker met ID %{id} kon nie gevind word nie. - back: Terug na die indeks + back: Terug na die register new: - heading: Skep blokkade op %{name} - submit: Skep blokkade - back: Wys alle blokkades + heading: Skep versperring op %{name} + submit: Skep versperring + back: Wys alle versperrings edit: - title: Wysig blokkade op %{name} - heading: Wysig blokkade op %{name} - submit: Opdateer blokkade - show: Wys hierdie blokkade - back: Wys alle blokkades + title: Redigeer versperring op %{name} + heading: Redigeer versperring op %{name} + submit: Werk versperring by + show: Wys dié versperring + back: Wys alle versperrings create: - try_contacting: Kontak asseblief die gebruiker en gee hom 'n redelike tyd om - te reageer alvorens u hom blokkeer. - try_waiting: Gee die gebruikers asseblief 'n redelike tyd om te reageer voordat - u 'n blokkade instel. - flash: Het gebruiker %{name} geblokkeer. + try_contacting: Probeer eers met die gebruiker in verbinding tree voordat u + hulle versper, en gun hulle 'n billike tyd om te antwoord. + try_waiting: Gun asseblief die gebruiker billik tyd om te antwoord voordat u + hulle versper. + flash: Het gebruiker %{name} versper. update: - success: Die blokkade is opgedateer. + success: Versperring bygewerk. index: - title: Gebruikersblokkades - heading: Lys van gebruikersblokkades - empty: Daar is nog geen blokkades ingestel nie. + title: Gebruikerversperrings + heading: Lys van gebruikersversperrings + empty: Daar is nog geen versperrings ingestel nie. revoke: - confirm: Is u seker u wil hierdie blokkade herroep? + confirm: Is u seker u wil hierdie versperring herroep? revoke: Herroep! - flash: Hierdie blokkade is herroep. + flash: Hierdie versperring is herroep. period: one: 1 uur other: '%{count} ure' partial: show: Wys - edit: Wysig + edit: Redigeer revoke: Herroep! confirm: Is u seker? - display_name: Geblokkeerde gebruiker + display_name: Versperde gebruiker creator_name: Skepper - reason: Rede vir blokkade + reason: Rede vir die versperring status: Status revoker_name: Herroep deur not_revoked: (nie herroep nie) + next: Volgende » + previous: « Vorige helper: - time_future: Verval oor %{time}. + time_future: Tyd oor %{time} verstreke. until_login: Aktief totdat die gebruiker aanmeld. - time_past: Het %{time} gelede verval. + time_past: Tyd is %{time} gelede verstreke. blocks_on: - title: Blokkades op %{name} - heading: Lys van blokkades teen %{name} - empty: '%{name} is nog nooit geblokkeer nie.' + title: Versperrings op %{name} + heading: Lys van versperrings teen %{name} + empty: '%{name} is nog nooit versper nie.' blocks_by: - title: Blokkades deur %{name} - heading: Lys van blokkades deur %{name} - empty: '%{name} het nog geen blokkades uitgevoer nie.' + title: Versperrings deur %{name} + heading: Lys van versperrings deur %{name} + empty: '%{name} het nog niks versper nie.' show: - title: '%{block_on} geblokkeer deur %{block_by}' - heading: '%{block_on} geblokkeer deur %{block_by}' - time_future: Verval oor %{time} - time_past: Het %{time} gelede verval + title: '%{block_on} word deur %{block_by} versper' + heading: '%{block_on} word deur %{block_by} versper' + time_future: Tyd oor %{time} verstreke. + time_past: Tyd is %{time} gelede verstreke status: Status show: Wys - edit: Wysig + edit: Redigeer revoke: Herroep! confirm: Is u seker? - reason: 'Rede vir blokkade:' - back: Wys alle blokkades + reason: 'Rede agter die versperring:' + back: Wys alle versperrings revoker: 'Herroep deur:' - needs_view: Die gebruiker moet aanmeld alvorens hierdie blokkade verwyder sal - word. + needs_view: Die gebruiker moet aanmeld alvorens hierdie versperring verwyder + sal word. javascripts: share: title: Deel + key: + title: Kaartsleutel + tooltip: Kaartsleutel map: zoom: - in: Zoom in + in: Zoem in + out: Zoem uit locate: title: Wys my ligging base: cycle_map: Fietskaart site: - edit_disabled_tooltip: Zoom in om die kaart te wysig - createnote_disabled_tooltip: Zoom in om 'n nota by die kaart te voeg - map_data_zoom_in_tooltip: Zoom in om kaartdata te sien + edit_disabled_tooltip: Zoem in om die kaart te wysig + createnote_disabled_tooltip: Zoem in om 'n nota by die kaart te voeg + map_data_zoom_in_tooltip: Zoem in om kaartdata te sien + changesets: + show: + comment: Opmerking + subscribe: Inskryf + unsubscribe: Kanselleer subskripsie + hide_comment: verskuil + unhide_comment: bring weer aan die lig directions: engines: graphhopper_bicycle: Fiets (GraphHopper) + graphhopper_car: Kar (GraphHopper) mapquest_bicycle: Fiets (MapQuest) mapquest_car: Kar (MapQuest) osrm_car: Kar (OSRM) + mapzen_bicycle: Fiets (Mapzen) + mapzen_car: Motor (Mapzen) + time: Tyd + query: + node: Knooppunt + way: Weg + relation: Verwantskap + nothing_found: Geen eienskappe gevind nie + context: + directions_from: Ringtingaanwysings vanaf hier + directions_to: Ringtingaanwysings hierheen + add_note: Voeg 'n nota hier by + show_address: Wys adres + centre_map: Stel kaartmiddelpunt hier in + redaction: + edit: + description: Beskrywing ... diff --git a/config/locales/aln.yml b/config/locales/aln.yml index 7d3a63378..6d8730d99 100644 --- a/config/locales/aln.yml +++ b/config/locales/aln.yml @@ -239,7 +239,6 @@ aln: search: title: latlon: Rezultatet prej Internal - us_postcode: Rezultatet prej Geocoder.us uk_postcode: Rezultatet prej NPEMap / FreeThe Postcode ca_postcode: Rezultatet prej Geocoder.CA diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 7872d1c7b..a0dfc880c 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -401,7 +401,6 @@ ar: search: title: latlon: نتائج داخليًا - us_postcode: نتائج من Geocoder.us uk_postcode: نتائج من NPEMap / FreeThe Postcode ca_postcode: نتائج من Geocoder.CA @@ -1246,6 +1245,7 @@ ar: date: التاريخ reply_button: رد unread_button: علّم كغير مقروءة + delete_button: احذف back: رجوع to: إلى wrong_user: "\uFEFFأنت مسجل دخول باسم '%{user}' ولكن الرسالة التي طلبت قراءتها diff --git a/config/locales/arz.yml b/config/locales/arz.yml index f9a4e88ba..a32b4ecb8 100644 --- a/config/locales/arz.yml +++ b/config/locales/arz.yml @@ -210,7 +210,6 @@ arz: search: title: latlon: نتائج داخليًا - us_postcode: نتائج من Geocoder.us uk_postcode: نتائج من NPEMap / FreeThe Postcode ca_postcode: نتائج من Geocoder.CA diff --git a/config/locales/ast.yml b/config/locales/ast.yml index 97a3ceb30..41f7b5735 100644 --- a/config/locales/ast.yml +++ b/config/locales/ast.yml @@ -40,7 +40,7 @@ ast: tracetag: Etiqueta de traza user: Usuariu user_preference: Preferencia d'usuariu - user_token: Token d'usuariu + user_token: Pase d'usuariu way: Vía way_node: Nuedu de vía way_tag: Etiqueta de vía @@ -170,16 +170,16 @@ ast: note: nota redacted: redaction: Redaición de %{id} - message_html: La versión %{version} de %{type} nun se pue amosar porque ta redactada. + message_html: La versión %{version} de %{type} nun puede amosase porque se redactó. Por favor consulta %{redaction_link} pa más detalles. type: node: nuedu way: vía relation: rellación start_rjs: - feature_warning: Cargando %{num_features} carauterístiques, que puen facer que'l - navegador vaya lentu o nun respuenda. ¿Ta seguru de que quier amosar estos - datos? + feature_warning: Cargando %{num_features} carauterístiques, que pueden facer + que'l navegador vaya lentu o nun respuenda. ¿Tas seguru de que quies amosar + estos datos? load_data: Cargar datos loading: Cargando... tag_details: @@ -230,25 +230,25 @@ ast: comment: Comentariu area: Área list: - title: Conxuntos de cambios + title: Conxuntos de cambeos title_user: Conxuntos de cambeos de %{user} - title_friend: Conxuntos de cambios de los tos collacios - title_nearby: Conxuntos de cambios d'usuarios cercanos - empty: Nun s'alcontró dengún conxuntu de cambios. - empty_area: Nun hai conxuntos de cambios nesti área. - empty_user: Nun hai conxuntos de cambios d'esti usuariu. - no_more: Nun s'alcontraron más conxuntos de cambios. - no_more_area: Nun hai más conxuntos de cambios nesti área. - no_more_user: Nun hai más conxuntos de cambios d'esti usuariu. + title_friend: Conxuntos de cambeos de los tos collacios + title_nearby: Conxuntos de cambeos d'usuarios cercanos + empty: Nun s'alcontró nengún conxuntu de cambeos. + empty_area: Nun hai conxuntos de cambeos nesti área. + empty_user: Nun hai conxuntos de cambeos d'esti usuariu. + no_more: Nun s'alcontraron más conxuntos de cambeos. + no_more_area: Nun hai más conxuntos de cambeos nesti área. + no_more_user: Nun hai más conxuntos de cambeos d'esti usuariu. load_more: Cargar más timeout: sorry: Llevó demasiao tiempu baxar la llista de conxuntos de cambeos que pidisti. rss: - title_all: Alderique del conxuntu de cambios d'OpenStreetMap - title_particular: 'Alderique del conxuntu de cambios #%{changeset_id} d''OpenStreetMap' + title_all: Alderique del conxuntu de cambeos d'OpenStreetMap + title_particular: 'Alderique del conxuntu de cambeos #%{changeset_id} d''OpenStreetMap' comment: 'Comentariu nuevu sobro''l conxuntu de cambios #%{changeset_id} de %{author}' - commented_at_html: Anovado hai %{when} + commented_at_html: Anovao hai %{when} commented_at_by_html: Anovao hai %{when} por %{user} full: Alderique completu diary_entry: @@ -288,8 +288,8 @@ ast: no_such_entry: title: Nun esiste la entrada del diariu heading: 'Nun esiste la entrada con id: %{id}' - body: Sentímoslo, nun hai denguna entrada del diariu cola id %{id}. Comprueba - la escritura o si calcasti nun enllaz enquivocáu. + body: Sentímoslo, nun hai nenguna entrada del diariu cola id %{id}. Comprueba + la escritura o si primisti nun enllaz enquivocáu. diary_entry: posted_by: Unviáu por %{link_user} el %{created} en %{language_link} comment_link: Comentar esta entrada @@ -312,20 +312,20 @@ ast: feed: user: title: Entraes nel diariu d'OpenStreetMap de %{user} - description: Entraes recientes de %{user} nel diariu d'OpenStreetMap + description: Entraes recién de %{user} nel diariu d'OpenStreetMap language: title: Entraes nel diariu d'OpenStreetMap en %{language_name} - description: Entraes recientes nel diariu d'usuarios d'OpenStreetMap en %{language_name} + description: Entraes recién nel diariu d'usuarios d'OpenStreetMap en %{language_name} all: title: Entraes nel diariu d'OpenStreetMap - description: Entraes recientes nel diariu d'usuarios d'OpenStreetMap + description: Entraes recién nel diariu d'usuarios d'OpenStreetMap comments: has_commented_on: '%{display_name} comentó nes siguientes entraes del diariu' post: Publicar when: Cuándo comment: Comentariu ago: hai %{ago} - newer_comments: Comentarios nuevos + newer_comments: Comentarios más nuevos older_comments: Comentarios anteriores export: title: Esportar @@ -335,13 +335,13 @@ ast: format_to_export: Formatu a esportar osm_xml_data: Datos XML d'OpenStreetMap map_image: Imaxe del mapa (amuesa la capa estándar) - embeddable_html: HTML empotrable + embeddable_html: HTML pa embrivir licence: Llicencia - export_details: Los datos d'OpenStreetMap tan llicenciaos embaxo la llicencia + export_details: Los datos d'OpenStreetMap tan llicenciaos baxo la llicencia Open Data Commons Open Database (ODbL). too_large: - advice: 'Si falla la esportación anterior, por favor, piense n''utilizar una - de les fontes de la llista siguiente:' + advice: 'Si falla la esportación anterior, considera utilizar una de les fontes + de la llista siguiente:' body: Esti área ye abondo grande pa esportase como Datos XML d'OpenStreetMap. Acerca'l mapa o esbilla un área menor, o usa una de les fontes siguientes pa descargar cantidaes grandes de datos. @@ -373,13 +373,12 @@ ast: latitude: 'Llat:' longitude: 'Llon:' output: Salida - paste_html: Pegar el HTML pa empotrar nun sitiu web + paste_html: Pegar el HTML pa embrivir nun sitiu web export_button: Esportar geocoder: search: title: latlon: Resultaos internos - us_postcode: Resultaos de Geocoder.us uk_postcode: Resultaos de NPEMap / FreeThe Postcode ca_postcode: Resultaos de Geocoder.CA @@ -424,7 +423,7 @@ ast: car_rental: Alquiler de coches car_sharing: Compartir coche car_wash: Llaváu de coches - casino: Casino + casino: Casinu charging_station: Estación de carga childcare: Ludoteca cinema: Cine @@ -435,8 +434,8 @@ ast: courthouse: Xulgáu crematorium: Crematoriu dentist: Dentista - doctors: Ambulatoriu - dormitory: Dormitoriu + doctors: Médicos + dormitory: Residencia drinking_water: Agua potable driving_school: Autoescuela embassy: Embaxada @@ -445,27 +444,27 @@ ast: ferry_terminal: Terminal de ferry fire_hydrant: Boca d'incendios fire_station: Bomberos - food_court: Zona de restaurantes + food_court: Zona de restoranes fountain: Fonte fuel: Combustible gambling: Xuegos d'azar grave_yard: Cementeriu - gym: Ximnasiu / Fitness + gym: Ximnasiu health_centre: Centru de salú hospital: Hospital hunting_stand: Puestu de caza ice_cream: Xelaos - kindergarten: Guardería + kindergarten: Xardín d'infancia library: Biblioteca market: Mercáu marketplace: Mercáu monastery: Monasteriu motorcycle_parking: Aparcamientu pa motocicletes nightclub: Sala de fiestes - nursery: Preescolar - nursing_home: Residencia asistencial + nursery: Guardería + nursing_home: Residencia asistida office: Oficina - parking: Aparcaderu + parking: Aparcamientu parking_entrance: Entrada d'aparcamientu pharmacy: Farmacia place_of_worship: Llugar de cultu @@ -476,10 +475,10 @@ ast: prison: Cárcel pub: Pub public_building: Edificiu públicu - reception_area: Llugar de recepción + reception_area: Área de recepción recycling: Puntu llimpiu - restaurant: Restaurán - retirement_home: Residencia de mayores + restaurant: Restorán + retirement_home: Residencia de xubilaos sauna: Sauna school: Escuela shelter: Abellugu @@ -494,11 +493,11 @@ ast: telephone: Teléfonu públicu theatre: Teatru toilets: Servicios - townhall: Casa conceyu + townhall: Casa del conceyu university: Universidá vending_machine: Venta automática veterinary: Ciruxía veterinaria - village_hall: Casa de la villa + village_hall: Sala polivalente waste_basket: Papelera waste_disposal: Contenedor pa basories youth_centre: Centru de mocedá @@ -532,50 +531,50 @@ ast: landing_site: Llugar de aterrizaxe d'emerxencia phone: Teléfonu d'emerxencia highway: - abandoned: Autopista abandonada + abandoned: Estrada abandonada bridleway: Caleya bus_guideway: Carril bus con guía bus_stop: Parada d'autobús - construction: Carretera en construcción - cycleway: Sienda ciclista + construction: Estrada en construcción + cycleway: Pista pa bicicletes elevator: Ascensor - emergency_access_point: Puntu de llocalización d'emerxencia - footway: Sienda + emergency_access_point: Accesu d'emerxencia + footway: Senderu ford: Vau - living_street: Cai residencial - milestone: Finxu - motorway: Autopista - motorway_junction: Enllaz d'autopista - motorway_link: Autopista + living_street: Rúa residencial + milestone: Moyón + motorway: Autoestrada + motorway_junction: Encruz d'autoestrada + motorway_link: Enllaz d'autovía path: Camín - pedestrian: Vía peatonal + pedestrian: Camín peonil platform: Andén - primary: Carretera primaria - primary_link: Enllaz de carretera primaria - proposed: Carretera propuesta + primary: Estrada primaria + primary_link: Estrada primaria + proposed: Estrada propuesta raceway: Pista de carreres - residential: Cai residencial + residential: Rúa rest_area: Área de descansu - road: Carretera - secondary: Carretera secundaria - secondary_link: Enllaz de carretera secundaria - service: Carretera de serviciu - services: Servicios n'autopista + road: Estrada + secondary: Estrada secundaria + secondary_link: Estrada secundaria + service: Estrada de serviciu + services: Área de serviciu speed_camera: Radar steps: Escaleres street_lamp: Farola - tertiary: Carretera terciaria - tertiary_link: Carretera terciaria + tertiary: Estrada terciaria + tertiary_link: Estrada terciaria track: Pista - traffic_signals: Semáforos - trail: Camín - trunk: Carretera nacional - trunk_link: Enllaz de carretera nacional - unclassified: Carretera ensin clasificar - unsurfaced: Carretera ensin asfaltar - "yes": Carretera + traffic_signals: Señales de tráficu + trail: Senderu + trunk: Estrada nacional + trunk_link: Estrada nacional + unclassified: Estrada ensin clasificar + unsurfaced: Estrada ensin asfaltar + "yes": Estrada historic: - archaeological_site: Llugar arqueolóxicu + archaeological_site: Xacimientu arqueolóxicu battlefield: Campu de batalla boundary_stone: Finxu building: Edificiu históricu @@ -589,7 +588,7 @@ ast: house: Casa icon: Iconu manor: Casona - memorial: Monumentu + memorial: Memorial mine: Mina monument: Monumentu roman_road: Via romana @@ -598,27 +597,27 @@ ast: tomb: Sepulcru tower: Torre wayside_cross: Cruceru - wayside_shrine: Ermita + wayside_shrine: Santuariu de camín wreck: Naufraxu junction: "yes": Interseición landuse: - allotments: Güertes recreatives - basin: Conca - brownfield: Terrén en derribu + allotments: Güertos recreativos + basin: Cuenca + brownfield: Solar derribáu cemetery: Cementeriu - commercial: Área comercial + commercial: Área de negocios conservation: Conservación construction: Construcción - farm: Casería - farmland: Tierres de llabor - farmyard: Corral + farm: Granxa + farmland: Tierra de llabranza + farmyard: Antoxana forest: Área forestal garages: Garaxes grass: Yerba - greenfield: Plan d'espansión + greenfield: Terrén pa urbanizar industrial: Área industrial - landfill: Vertederu + landfill: Basureru meadow: Prau military: Área militar mine: Mina @@ -630,33 +629,33 @@ ast: reservoir_watershed: Cuenca del banzáu residential: Área residencial retail: Área comercial - road: Área de carretera + road: Zona d'estrada village_green: Prau municipal - vineyard: Viña + vineyard: Viñéu "yes": Usu del terrén leisure: - beach_resort: Turismu de playa + beach_resort: Complexu playeru bird_hide: Observatoriu d'aves club: Club common: Terrén común dog_park: Parque pa perros fishing: Área de pesca - fitness_centre: Centru de fitness + fitness_centre: Ximnasiu (fitness) fitness_station: Ximnasiu garden: Xardín golf_course: Campu de golf - horse_riding: Equitación + horse_riding: Hípica ice_rink: Pista de xelu marina: Puertu deportivu miniature_golf: Mini golf nature_reserve: Reserva natural park: Parque - pitch: Campu deportivu + pitch: Campu de deportes playground: Xuegos infantiles recreation_ground: Campu recreativu - resort: Urbanización pa vacaciones + resort: Centru de vacaciones sauna: Sauna - slipway: Rampla de botadura + slipway: Varaderu sports_centre: Centru deportivu stadium: Estadiu swimming_pool: Piscina @@ -668,7 +667,7 @@ ast: pipeline: Tubería tower: Torre works: Fábrica - "yes": Fecho pol home + "yes": Artificial military: airfield: Aeródromu militar barracks: Cuartel @@ -676,25 +675,25 @@ ast: mountain_pass: "yes": Puertu de montaña natural: - bay: Golfu + bay: Badea beach: Playa cape: Cabu cave_entrance: Boca de cueva cliff: Cantil - crater: Crater + crater: Cráter dune: Duna fell: Braña fjord: Fiordu forest: Área forestal geyser: Guéiser glacier: Glaciar - grassland: Prau + grassland: Pradería heath: Berezal hill: Llomba island: Islla land: Tierra - marsh: Llamuerga - moor: Amarradera + marsh: Basa + moor: Granda mud: Barru peak: Picu point: Puntu @@ -705,12 +704,12 @@ ast: sand: Sable scree: Llera scrub: Cotollal - spring: Fonte + spring: Naciente stone: Piedra strait: Estrechu tree: Árbol valley: Valle - volcano: Volcan + volcano: Volcán water: Agua wetland: Llamuerga wood: Viesca @@ -729,12 +728,12 @@ ast: travel_agent: Axencia de viaxes "yes": Oficina place: - allotments: Güertes recreatives + allotments: Güertos recreativos block: Bloque airport: Aeropuertu city: Ciudá country: País - county: Condáu, conceyu + county: Condáu farm: Casería hamlet: Aldea house: Casa @@ -743,17 +742,17 @@ ast: islet: Castru de mar isolated_dwelling: Vivienda aisllada locality: Llocalidá - moor: Amarradera + moor: Granda municipality: Conceyu - neighbourhood: Vecindá + neighbourhood: Barriu postcode: Códigu postal - region: Fastera, provincia + region: Rexón sea: Mar - state: Estáu, comunidá autónoma + state: Estáu o provincia subdivision: Subdivisión - suburb: Barriu + suburb: Suburbiu town: Villa - unincorporated_area: Área ensin conceyu + unincorporated_area: Área ensin incorporar village: Pueblu "yes": Llugar railway: @@ -764,7 +763,7 @@ ast: funicular: Tren funicular halt: Parada de tren historic_station: Estación de ferrocarril históricu - junction: Disvíu de ferrocarril + junction: Encruz ferroviariu level_crossing: Pasu a nivel light_rail: Ferrocarril llixeru miniature: Ferrocarril en miniatura @@ -773,16 +772,16 @@ ast: platform: Andén de ferrocarril preserved: Ferrocarril conserváu proposed: Ferrocarril propuestu - spur: Apartaderu industrial + spur: Ramal ferroviariu station: Estación de tren stop: Apeaderu subway: Metro subway_entrance: Entrada de metro - switch: Aguyes de ferrocarril + switch: Aguya de ferrocarril tram: Tranvía tram_stop: Parada de tranvía shop: - alcohol: Venta de bébores + alcohol: Venta de llicores antiques: Antigüedaes art: Venta d'arte bakery: Panadería @@ -792,41 +791,41 @@ ast: books: Llibrería boutique: Boutique butcher: Carnicería - car: Automóvil + car: Concesionariu car_parts: Repuestos d'automóvil car_repair: Taller d'automóviles carpet: Alfombres - charity: Rastru solidariu + charity: Tienda benéfica chemist: Droguería clothes: Tienda de ropa computer: Tienda d'informática confectionery: Confitería convenience: Alimentación copyshop: Copistería - cosmetics: Perfumería - deli: Tienda gourmet + cosmetics: Tienda de cosmética + deli: Delicatessen department_store: Grandes almacenes - discount: Productos con descuentu + discount: Tienda de descuentos doityourself: Bricolax dry_cleaning: Tintorería electronics: Tienda d'electrónica estate_agent: Axencia inmobiliaria farm: Tienda de casería fashion: Tienda de modes - fish: Pescaos + fish: Pescadería florist: Floristería food: Comestibles funeral_directors: Servicios funerarios furniture: Muebles - gallery: Venta d'arte + gallery: Galería d'arte garden_centre: Xardinería general: Mercancía xeneral gift: Tienda de regalos greengrocer: Frutería - grocery: Frutería + grocery: Tienda d'alimentación hairdresser: Peluquería hardware: Ferretería - hifi: Soníu + hifi: Hi-Fi insurance: Seguros jewelry: Xoyería kiosk: Quioscu @@ -835,29 +834,29 @@ ast: market: Mercáu mobile_phone: Tienda de telefonía móvil motorcycle: Venta de motos - music: Discos + music: Tienda de música newsagent: Prensa optician: Óptica organic: Comida ecolóxica - outdoor: Aire llibre - pet: Paxarería + outdoor: Deportes d'aire llibre + pet: Tienda d'animales pharmacy: Farmacia photo: Fotografía salon: Cuidaos corporales second_hand: Tienda d'oxetos usaos shoes: Zapatería shopping_centre: Centru comercial - sports: Deportes + sports: Tienda de deportes stationery: Papelería supermarket: Supermercáu tailor: Sastrería toys: Xuguetería travel_agency: Axencia de viaxes video: Videu club - wine: Venta de bébores + wine: Venta de llicores "yes": Tienda tourism: - alpine_hut: Refuxu de montaña + alpine_hut: Refuxu de monte apartment: Apartamentu artwork: Obra d'arte attraction: Interés turísticu @@ -867,13 +866,13 @@ ast: caravan_site: Camping pa caravanes chalet: Xalé gallery: Galería - guest_house: Agospiamientu + guest_house: Pensión hostel: Albergue hotel: Hotel information: Información motel: Motel museum: Muséu - picnic_site: Área recreativa + picnic_site: Área de picnic theme_park: Parque temáticu viewpoint: Mirador zoo: Zoo @@ -881,11 +880,11 @@ ast: culvert: Cañu "yes": Túnel waterway: - artificial: Vía acuática artificial + artificial: Vía d'agua artificial boatyard: Astilleru canal: Canal dam: Presa - derelict_canal: Canal abandonáu + derelict_canal: Canal abandonada ditch: Riega dock: Dársena drain: Desagüe @@ -896,7 +895,7 @@ ast: river: Ríu stream: Regatu wadi: Riera - waterfall: Saltu d'agua + waterfall: Tabayón weir: Banzáu "yes": Cursu d'agua admin_levels: @@ -909,9 +908,9 @@ ast: level10: Frontera de barriu description: title: - osm_nominatim: Llugar de OpenStreetMap + osm_nominatim: Llugar según OpenStreetMap Nominatim - geonames: Llugar de GeoNames + geonames: Llugar según GeoNames types: cities: Ciudaes towns: Villes @@ -925,26 +924,26 @@ ast: home: Dir al llugar d'entamu logout: Salir log_in: Aniciar sesión - log_in_tooltip: Entrar nuna cuenta esistente - sign_up: Dase d'alta + log_in_tooltip: Entrar con una cuenta esistiente + sign_up: Rexistrase start_mapping: Principiar col mapéu - sign_up_tooltip: Crear una cuenta pa editar + sign_up_tooltip: Crea una cuenta pa editar edit: Editar history: Historial export: Esportar data: Datos export_data: Esportar datos gps_traces: Traces GPS - gps_traces_tooltip: Xestionar traces de GPS + gps_traces_tooltip: Alministrar traces de GPS user_diaries: Diarios d'usuariu user_diaries_tooltip: Ver los diarios d'usuariu edit_with: Editar con %{editor} - tag_line: El wikimapamundi llibre - intro_header: ¡Bienveníos a OpenStreetMap! + tag_line: El Wiki Mapamundi llibre + intro_header: ¡Afáyate n'OpenStreetMap! intro_text: OpenStreetMap ye un mapa del mundu, creáu por persones como tu y d'usu llibre baxo una llicencia abierta. intro_2_create_account: Crear una cuenta d'usuariu - partners_html: L'agospiamientu tien l'encontu de %{ucl}, %{ic} y %{bytemark}, + partners_html: L'agospiamientu tien l'encontu de %{ucl}, %{bytemark} y %{ic}, y otros %{partners}. partners_ucl: UCL partners_ic: Imperial College de Londres @@ -988,22 +987,22 @@ ast: href="http://opendatacommons.org/licenses/odbl/">Open Data Commons Open Database License (ODbL) de la Fundación OpenStreetMap (OSMF). - intro_2_html: Pues copiar, distribuir, tresmitir y adautar los nuesos datos - de mou llibre, mentanto des reconocimientu a OpenStreetMap y a los sos collaboradores. - Si camudes o creas conteníu sobre los nuesos datos, namái podrás distribuir + intro_2_html: Puedes copiar, distribuir, tresmitir y adautar los nuesos datos + de mou llibre, mentanto deas reconocimientu a OpenStreetMap y a los sos collaboradores. + Si camudes o crees conteníu sobre los nuesos datos, namái podrás distribuir el resultáu baxo la mesma llicencia. El códigu - llegal completu t'esplica los tos drechos y obligaciones. + llegal completu t'esplica los tos drechos y obligaciones. intro_3_html: La cartografía de los mosaicos del mapa y la nuesa documentación, tan llicenciaos baxo la llicencia Creative Commons Reconocimientu-CompartirIgual 2.0 (CC-BY-SA). credit_title_html: Cómo dar reconocimientu a OpenStreetMap - credit_1_html: Requerimos qu'uses el créditu “© Collaboradores d'OpenStreetMap”. + credit_1_html: Riquimos qu'uses el créditu “© Collaboradores d'OpenStreetMap”. credit_2_html: |- - Tamién debes dexar claro que los datos tan disponibles baxo la llicencia Open Database License (ODbL), y si utilices los nuesos mosaicos de mapa, que la cartografía tien llicencia CC-BY-SA. Pues facelo enllazando a esta páxina de drechos d'autor. - Alternativamente, y como requisitu si distribúis OSM en forma de datos, pues nomar y enllazar direutamente a les llicencies. En medios onde los enllaces nun seyan posibles (por exemplu, obres impreses), te suxerimos dirixir a los llectores a openstreetmap.org (espandiendo «OpenStreetMap» a esta dirección completa, seique), a opendatacommons.org y, si ye'l casu, a creativecommons.org. + Tamién tienes de dexar claro que los datos tan disponibles baxo la llicencia Open Database License (ODbL), y si utilices los nuesos mosaicos de mapa, que la cartografía tien llicencia CC BY-SA. Pues facelo enllazando a esta páxina de drechos d'autor. + Alternativamente, y como requisitu si distribues OSM en forma de datos, pues nomar y enllazar direutamente a les llicencies. En medios onde los enllaces nun seyan posibles (por exemplu, obres imprentaes), suxerímoste dirixir a los llectores a openstreetmap.org (espandiendo 'OpenStreetMap' a esta dirección completa, seique), a opendatacommons.org y, si ye'l casu, a creativecommons.org. credit_3_html: |- Nun mapa electrónicu navegable, los créditos tendríen d'apaecer na esquina del mapa. - Por exemplu: + Por casu: attribution_example: alt: Exemplu de cómo dar reconocimientu a OpenStreetMap nuna páxina web title: Exemplu de reconocimientu @@ -1077,11 +1076,11 @@ ast: al usu de les marques, mándales al grupu de trabayu sobro llicencies. welcome_page: - title: ¡Bienveníu! + title: ¡Afáyate! introduction_html: |- - Bienveníu a OpenStreetMap, el mapa del mundu llibre y editable. Agora - qu'anició sesión, yá ta preparáu editar mapes. Esta ye una guía rápida - de les coses más importantes que necesita saber. + Afáyate n'OpenStreetMap, el mapa del mundu llibre y editable. Agora + qu'aniciasti sesión, yá puedes editar mapes. Esta ye una guía rápida + de les coses más importantes que necesites saber. whats_on_the_map: title: Qué hai nel Mapa on_html: |- @@ -1089,8 +1088,8 @@ ast: incluye millones d'edificios, carreteres, y otros detalles de llugares. Puedes poner nel mapa cualquier carauterística del mundu real que t'interese. off_html: |- - Lo que nun incluye son datos suxetivos como calificaciones, carauterístiques históriques o hipotétiques, y datos de fontes con drechos d'autor. Si nun tien - un permisu especial, nun copie de mapes en llinia o en papel. + Lo que nun incluye son datos suxetivos como calificaciones, carauterístiques históriques o hipotétiques, y datos de fontes con drechos d'autor. Si nun tienes + un permisu especial, nun copies de mapes en llinia o en papel. basic_terms: title: Términos básicos pa facer mapes paragraph_1_html: OpenStreetMap tien cierta xíriga de so. Estes son delles pallabres @@ -1144,8 +1143,8 @@ ast: other_concerns: title: Otres preocupaciones explanation_html: |- - Si tien dalguna preocupación tocante a cómo tan usándose los nuesos datos o tocante al conteníu, consulte la - páxina de drechos d'autor pa más información llegal, o comuníquese col grupu de trabayu de la OSMF afayadizu. + Si tienes dalguna preocupación tocante a cómo tan usándose los nuesos datos o tocante al conteníu, consulta la + páxina de drechos d'autor pa más información llegal, o comunícate col grupu de trabayu de la OSMF afayadizu. help_page: title: Algamar ayuda introduction: OpenStreetMap tien dellos recursos p'aprender sobro'l proyeutu, @@ -1210,7 +1209,7 @@ ast: legal_html: "Esti sitiu y munchos otros servicios rellacionaos xestiónalos formalmente la \nFundación OpenStreetMap (OSMF) \nnel nome de la comunidá. L'usu de tolos servicios remanaos pola OSMF tán suxetos - les nueses polítiques + a les nueses polítiques d'usu aceptable y la nuesa política de privacidá\n
      \nComunícate cola OSMF \nsi tienes entrugues o problemes relativos a les llicencies, @@ -1385,6 +1384,7 @@ ast: date: Data reply_button: Contestar unread_button: Marcar como non lleíu + delete_button: Desaniciar back: Anterior to: Pa wrong_user: Tas coneutáu como `%{user}' pero'l mensaxe que quies lleer nun s'unvió @@ -1443,7 +1443,7 @@ ast: key: table: entry: - motorway: Autopista + motorway: Autoestrada main_road: Carretera principal trunk: Carretera nacional primary: Carretera primaria @@ -1658,7 +1658,7 @@ ast: aceutalos, pero debes conocelos. oauth: oauthorize: - title: Autorizar l'accesu a la so cuenta + title: Autorizar l'accesu a la to cuenta request_access: L'aplicación %{app_name} ta solicitando accesu a la to cuenta, %{user}. Por favor, revisa si quies que l'aplicación tenga les capacidaes darréu. Puedes esbillar tantes o tan poques como te preste. @@ -2323,10 +2323,10 @@ ast: unhide_comment: amosar notes: new: - intro: ¿Alcontró un error o falta daqué? Informe a otros mapeadores pa que - podamos igualo. Mueva'l marcador a la posición correuta y escriba una nota - pa esplicar el problema. (Por favor, nun escriba información personal o - información de mapes con drechos d'autor o de llistes de teléfonos). + intro: ¿Alcontrasti un error o falta daqué? Informa a otros mapeadores pa + que podamos igualo. Mueve'l marcador a la posición correuta y escribi una + nota pa esplicar el problema. (Por favor, nun escribas información personal + o información de mapes con drechos d'autor o de llistes de teléfonos). add: Amestar nota show: anonymous_warning: Esta nota incluye comentarios d'usuarios anónimos que tendríen diff --git a/config/locales/az.yml b/config/locales/az.yml index 5345f315d..e819673e5 100644 --- a/config/locales/az.yml +++ b/config/locales/az.yml @@ -266,7 +266,6 @@ az: search: title: latlon: Daxili nəticələr - us_postcode: Geocoder.us nəticələri uk_postcode: NPEMap / FreeThe Postcode nəticələri ca_postcode: Geocoder.CA nəticələri diff --git a/config/locales/be-Tarask.yml b/config/locales/be-Tarask.yml index 8be10b30b..2b2201668 100644 --- a/config/locales/be-Tarask.yml +++ b/config/locales/be-Tarask.yml @@ -284,7 +284,6 @@ be-Tarask: search: title: latlon: Вынікі з Internal - us_postcode: Вынікі з Geocoder.us uk_postcode: Вынікі з NPEMap / FreeThe Postcode ca_postcode: Вынікі з Geocoder.CA diff --git a/config/locales/be.yml b/config/locales/be.yml index f9619c73e..a60883a64 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -387,7 +387,6 @@ be: search: title: latlon: Вынікі з Internal - us_postcode: Вынікі з Geocoder.us uk_postcode: Вынінкі з NPEMap / FreeThe Postcode ca_postcode: Вынікі з Geocoder.CA @@ -953,7 +952,7 @@ be: для выкарыстання на ўмовах адкрытай ліцэнзіі. intro_2_create_account: Стварыць рахунак удзельніка partners_html: Хостынг падтрымліваецца %{ucl}, %{ic} і %{bytemark}, і іншымі %{partners}. - partners_ucl: UCL VR-цэнтр + partners_ucl: UCL partners_ic: Imperial College London partners_bytemark: Bytemark Hosting partners_partners: партнёрамi @@ -1025,10 +1024,10 @@ be: Даведайцеся больш аб выкарыстанні нашых дадзеных і аб тым, як паказваць нас як крыніцу паходжання дадзеных на старонцы OSMF Licence і адказах на прававыя пытанні. more_2_html: Хоць дадзеныя OpenStreetMap з'яўляецца адкрытымі дадзенымі, мы - не ў стане прадастаўляць бясплатны картаграфічны API для іншых распрацоўнікаў. - Азнаёмціся з нашымі Правіламі - выкарыстання API, Правіламі - выкарыстання графічных карт і Правіламі + не ў стане прадастаўляць бясплатны картаграфічны API для іншых распрацоўшчыкаў. + Азнаёмцеся з нашымі Правіламі + выкарыстання API, Правіламі + выкарыстання графічных карт і Правіламі выкарыстання сэрвісу Nominatim. contributors_title_html: Нашы ўдзельнікі contributors_intro_html: 'Нашымі ўдзельнікамі з''яўляюцца тысячы людзей. Мы @@ -1241,6 +1240,7 @@ be: footer_html: Вы можаце таксама прачытаць паведамленне на %{readurl}, і вы можаце адказаць на %{replyurl} friend_notification: + hi: Прывітанне, %{to_user}, subject: '[OpenStreetMap] %{user} дадаў вас у спіс сваіх сяброў' had_added_you: '%{user} пасябраваў з Вамі на OpenStreetMap.' see_their_profile: Вы можаце прагледзець профіль на %{userurl} і дадаць, як @@ -1325,6 +1325,7 @@ be: Заўвага каля %{place}.' details: Больш падрабязна пра ўвагу можна прачытаць на %{url}. changeset_comment_notification: + hi: Прывітанне, %{to_user}, greeting: Прывітанне, commented: subject_own: '[OpenStreetMap] %{commenter} пракаментаваў адзін з вашых набораў @@ -1338,6 +1339,8 @@ be: partial_changeset_with_comment: з каментаром '%{changeset_comment}' partial_changeset_without_comment: без каментароў details: Дадатковыя звесткі аб наборы зьменаў можна знайсці ў %{url}. + unsubscribe: Каб адпісацца ад абнаўленняў гэтага пакета правак наведайце %{url} + і націсніце кнопку "Адпісацца". message: inbox: title: Уваходныя @@ -1399,6 +1402,7 @@ be: date: Дата reply_button: Адказаць unread_button: Адзначыць, як непрачытанае + delete_button: Выдаліць back: Назад to: Каму wrong_user: Вы ўвайшлі ў сістэму як `%{user}', але паведамленне, якое Вы жадаеце @@ -1466,6 +1470,9 @@ be: track: Палявая дарога bridleway: Дарога для коней cycleway: Веласіпедная дарожка + cycleway_national: Нацыянальная веладарожка + cycleway_regional: Рэгіянальная веладарожка + cycleway_local: Веладарожка мясцовага значэння footway: Пешаходная дарожка rail: Чыгунка subway: Метро @@ -1657,6 +1664,8 @@ be: require_moderator: not_a_moderator: Вам неабходна быць мадэратарам для выканання гэтага дзеяння. setup_user_auth: + blocked_zero_hour: У вас ёсць тэрміновае паведамленне на сайце OpenStreetMap. + Вам трэба прачытаць паведамленне, перш чым вы зможаце захаваць вашы змены. blocked: Ваш доступ да API быў заблакаваны. Калі ласка, ўвайдзіце ў вэб-інтэрфейс, каб даведацца больш. need_to_see_terms: Ваш доступ да API часова прыпынены. Калі ласка, ўвайдзіце @@ -1687,6 +1696,8 @@ be: invalid: Токен аўтарызацыі не сапраўдны. revoke: flash: Вы адклікалі токен для дастасавання %{application} + permissions: + missing: Вы не дазволілі праграме атрымаць доступ да гэтай функцыі oauth_clients: new: title: Зарэгістраваць новае дастасаванне @@ -1792,6 +1803,9 @@ be: github: title: Уваход праз GitHub alt: Увайсці праз уліковы запіс GitHub + wikipedia: + title: Увайсці праз Вікіпедыю + alt: Уваход з выкарыстаннем рахунку ў Вікіпедыі yahoo: title: Уваход праз Yahoo alt: Уваход праз Yahoo OpenID @@ -2196,6 +2210,8 @@ be: helper: time_future: Заканчваецца праз %{time}. until_login: Актыўная да моманту ўваходу ўдзельніка ў сістэму. + time_future_and_until_login: Заканчваецца праз %{time} і пасля таго, як карыстальнік + увойдзе ў сістэму. time_past: Скончылася %{time} таму. blocks_on: title: Блакіроўкі для %{name} @@ -2299,6 +2315,7 @@ be: header: Слаі карты notes: Заўвагі на карце data: Картаграфічныя дадзеныя + gps: Агульныя GPS-сляды overlays: Уключыць накладкі для ліквідацыі памылак карты title: Слаі copyright: © OpenStreetMap contributors @@ -2337,16 +2354,19 @@ be: edit_help: Перамясціце карту і наблізце месца, якое вы хочаце рэдагаваць, затым націсніце тут. directions: + ascend: Угору engines: - graphhopper_bicycle: Ровар (GraphHopper) - graphhopper_foot: Пешаход (GraphHopper) - mapquest_bicycle: Ровар (MapQuest) + graphhopper_bicycle: Веласіпед (GraphHopper) + graphhopper_car: Аўтамабіль (GraphHopper) + graphhopper_foot: Пешшу (GraphHopper) + mapquest_bicycle: Веласіпед (MapQuest) mapquest_car: Аўтамабіль (MapQuest) - mapquest_foot: Пешаход (MapQuest) + mapquest_foot: Пешшу (MapQuest) osrm_car: Аўтамабіль (OSRM) mapzen_bicycle: Веласіпед (Mapzen) mapzen_car: Аўтамабіль (Mapzen) mapzen_foot: Пешшу (Mapzen) + descend: Уніз directions: Маршрут distance: Адлегласць errors: @@ -2355,11 +2375,21 @@ be: instructions: continue_without_exit: Працягвайце рух па %{name} slight_right_without_exit: Плаўна павярніце направа на %{name} + offramp_right_without_exit: Павярніце направа на з'езд да %{name} + onramp_right_without_exit: Павярніце направа на з'езд да %{name} + endofroad_right_without_exit: У канцы дарогі павярніце направа на %{name} + merge_right_without_exit: Перастройцеся ўправа на %{name} + fork_right_without_exit: На развілцы павярніце направа на %{name} turn_right_without_exit: Павярніце направа на %{name} sharp_right_without_exit: Рэзка павярніце направа на %{name} uturn_without_exit: Развярніцеся на %{name} sharp_left_without_exit: Рэзка павярніце налева на %{name} turn_left_without_exit: Павярніце налева на %{name} + offramp_left_without_exit: Павярніце налева на з'езд да %{name} + onramp_left_without_exit: Павярніце налева на з'езд да %{name} + endofroad_left_without_exit: У канцы дарогі павярніце налева на %{name} + merge_left_without_exit: Перастройцеся ўлева на %{name} + fork_left_without_exit: На развілцы павярніце налева на %{name} slight_left_without_exit: Плаўна павярніце налева на %{name} via_point_without_exit: (праз кропку) follow_without_exit: Рухайцеся па %{name} @@ -2371,6 +2401,11 @@ be: against_oneway_without_exit: Рухайцеся супраць аднабаковага руху па %{name} end_oneway_without_exit: Канец аднабаковага руху на %{name} roundabout_with_exit: Пакіньце кальцавую развязку праз выезд %{exit} на %{name} + turn_left_with_exit: На кругавой развязцы павярніце налева на %{name} + slight_left_with_exit: На кругавой развязцы плаўна павярніце налева на %{name} + turn_right_with_exit: На кругавой развязцы павярніце направа на %{name} + slight_right_with_exit: На кругавой развязцы плаўна павярніце направа на %{name} + continue_with_exit: На кругавой развязцы працягвайце рух прама на %{name} unnamed: без назвы courtesy: Маршрут прадастаўлены %{link} time: Час @@ -2381,6 +2416,13 @@ be: nothing_found: Аб’екты не знойдзены error: 'Памылка сувязі з %{server}: %{error}' timeout: Тайм-аўт падключэння да %{server} + context: + directions_from: Маршрут адсюль + directions_to: Маршрут сюды + add_note: Дадаць заўвагу тут + show_address: Паказаць адрас + query_features: Пошук аб’ектаў + centre_map: Цэнтраваць карту redaction: edit: description: Апісанне diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 099cf7a5d..56547d363 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -6,6 +6,7 @@ # Author: MrPanyGoff # Author: Plamen # Author: Ricordo.tenerissimo +# Author: ShockD # Author: StanProg # Author: Vodnokon4e # Author: АдмиралАнимЕ @@ -25,6 +26,7 @@ bg: node: Възел notifier: Известител old_node: Стар възел + old_relation: Стара релация relation: Релация relation_member: Член на релация relation_tag: Таг на релация @@ -101,8 +103,8 @@ bg: changeset: title: 'Списък с промени: %{id}' belongs_to: Автор - node: Точки (%{count}) - node_paginated: Точки (%{x}-%{y} от %{count}) + node: Възли (%{count}) + node_paginated: Възли (%{x}-%{y} от %{count}) way: Пътища (%{count}) way_paginated: Пътища (%{x}-%{y} от общо %{count}) relation: Релации (%{count}) @@ -114,12 +116,12 @@ bg: join_discussion: Впишете се, за да се присъедините към обсъждането discussion: Обсъждане node: - title: 'Точка: %{name}' + title: 'Възел: %{name}' history_title: 'История на точка: %{name}' way: title: 'Път: %{name}' history_title: 'История на пътя: %{name}' - nodes: Точки + nodes: Възли also_part_of: one: част от път %{related_ways} other: част от пътища %{related_ways} @@ -143,7 +145,7 @@ bg: way: път relation: релация changeset: списък с промени - note: Бележка + note: бележка timeout: type: node: възел @@ -162,6 +164,8 @@ bg: loading: Зареждане... tag_details: tags: Етикети + wikidata_link: Обектът %{page} в Уикиданни + wikipedia_link: Статията %{page} в Уикипедия telephone_link: Позвънете на %{phone_number} note: title: 'Бележка: %{id}' @@ -188,9 +192,13 @@ bg: area: Област list: title: Списък с промени + title_user: Списък с промени на %{user} + title_friend: Списъци с промени на Ваши приятели + title_nearby: Списъци с промени от потребители наблизо empty: Няма намерени списъци с промени. empty_area: Няма списъци с промени в този район. empty_user: Няма списъци с промени от този потребител. + no_more: Не са намерени повече списъци с промени. load_more: Зареждане на още rss: commented_at_html: Обновено преди %{when} @@ -239,7 +247,7 @@ bg: hide_link: Скриване на този пост confirm: Потвърди diary_comment: - hide_link: Скрий този коментар + hide_link: Скриване на коментара confirm: Потвърждаване location: location: 'Местоположение:' @@ -284,7 +292,6 @@ bg: search: title: latlon: Вътрешни резултати - us_postcode: Резултати от Geocoder.us uk_postcode: Резултати от NPEMap / FreeThe Postcode ca_postcode: Резултати от Geocoder.CA @@ -300,7 +307,9 @@ bg: cable_car: Кабинков лифт chair_lift: Седалков лифт aeroway: + gate: Врата helipad: Вертолетна площадка + runway: Писта taxiway: Път за рулиране terminal: Терминал amenity: @@ -313,12 +322,16 @@ bg: bench: Пейка bicycle_parking: Паркинг за велосипеди bicycle_rental: Велосипеди под наем + biergarten: Бирария на открито + boat_rental: Наем на лодки + brothel: Бордел bureau_de_change: Обменно бюро bus_station: Автобусна спирка cafe: Кафене car_rental: Коли под наем car_wash: Автомивка casino: Казино + charging_station: Зарядна станция cinema: Кино clinic: Поликлиника clock: Часовник @@ -330,6 +343,7 @@ bg: doctors: Лекари dormitory: Пансион drinking_water: Питейна вода + driving_school: Автошкола embassy: Посолство emergency_phone: Телефон за спешни повиквания fast_food: Заведения за бързо хранене @@ -351,6 +365,7 @@ bg: nightclub: Нощен клуб office: Офис parking: Паркинг + parking_entrance: Вход на паркинг pharmacy: Аптека place_of_worship: Място за поклонение police: Полиция @@ -403,12 +418,12 @@ bg: tailor: Шивач "yes": Работилница emergency: - ambulance_station: Пожарна + ambulance_station: Станция за линейки defibrillator: Дефибрилатор landing_site: Място за аварийно кацане phone: Телефон за спешни повиквания highway: - abandoned: Изоставена железопътна линия + abandoned: Изоставена магистрала bridleway: Конен път bus_stop: Автобусна спирка construction: Магистрала в строеж @@ -436,13 +451,14 @@ bg: speed_camera: Камера за контрол на скоростта steps: Стълбище street_lamp: Улична лампа - track: Полски път - trunk: Скоростен път - trunk_link: Скоростен път + track: Селски път + traffic_signals: Светофар + trunk: Междуградски път + trunk_link: Междуградски път unsurfaced: Път без настилка "yes": Път historic: - archaeological_site: Археологическа зона + archaeological_site: Разкопки battlefield: Бойно поле boundary_stone: Граничен камък building: Историческа сграда @@ -456,7 +472,7 @@ bg: house: Къща icon: Икона manor: Имение - memorial: Паметник + memorial: Мемориал mine: Рудник monument: Паметник roman_road: Римски път @@ -465,6 +481,8 @@ bg: tomb: Гробница tower: Кула wreck: Потънал кораб + junction: + "yes": Кръстовище landuse: allotments: Градини basin: Басейн @@ -498,7 +516,7 @@ bg: fitness_centre: Фитнес център garden: Градина golf_course: Игрище за голф - horse_riding: Конна езда + horse_riding: Конна база ice_rink: Ледена пързалка marina: Пристанище за лодки miniature_golf: Мини-голф @@ -542,7 +560,7 @@ bg: peak: Връх reef: Риф rock: Скала - saddle: Седло + saddle: Седловина sand: Пясък spring: Ручей stone: Камък @@ -550,7 +568,7 @@ bg: valley: Долина volcano: Вулкан water: Вода - wood: Дърво + wood: Гора office: accountant: Счетоводител architect: Архитект @@ -588,12 +606,13 @@ bg: railway: abandoned: Изоставена железопътна линия construction: Железопътна линия в строеж + disused: Изоставена ж.п. линия disused_station: изоставена гара halt: Железопътна спирка historic_station: Гара с историческо значение junction: Железопътен възел level_crossing: Прелез - light_rail: Бърз трамвай + light_rail: Лека железница monorail: Монорелсов път narrow_gauge: Теснолинейка platform: Железопътна платформа @@ -605,14 +624,14 @@ bg: tram_stop: Трамвайна спирка shop: antiques: Антики - art: Магазин на изкуствата + art: Арт магазин bakery: Пекарна beauty: Салон за красота beverages: Магазин за напитки bicycle: Магазин за велосипеди books: Книжарница boutique: Бутик - butcher: Месарница + butcher: Месар car: Автосалон car_parts: Авточасти car_repair: Автосервиз @@ -629,7 +648,7 @@ bg: general: Смесен магазин gift: Магазин за подаръци greengrocer: Плод и зеленчук - grocery: Бакалия + grocery: Магазин за хранителни стоки hairdresser: Фризьорски салон insurance: Застраховане jewelry: Бижутериен магазин @@ -654,12 +673,12 @@ bg: tourism: apartment: Апартамент artwork: Произведения на изкуството - chalet: Хижа + chalet: Бунгало gallery: Галерия guest_house: Къща за гости hostel: Хостел hotel: Хотел - information: Сведения + information: Информация motel: Мотел museum: Музей picnic_site: Място за пикник @@ -669,7 +688,7 @@ bg: "yes": Тунел waterway: canal: Канал - dam: Яз + dam: Язовирна стена river: Река waterfall: Водопад admin_levels: @@ -682,11 +701,14 @@ bg: level10: Граница на предградията description: types: + towns: Градове places: Места results: no_results: Не бяха открити резултати more_results: Повече резултати layouts: + logo: + alt_text: Лого на OpenStreetMap home: Моят дом logout: Излизане log_in: Влизане @@ -700,17 +722,19 @@ bg: export_data: Изнасяне на данни gps_traces: GPS-следи gps_traces_tooltip: Управление на GPS-следи - user_diaries: Дневник + user_diaries: Потребителски дневник user_diaries_tooltip: Дневници на потребители edit_with: Редактиране с %{editor} tag_line: Свободна Wiki-карта на света intro_header: Добре дошли в OpenStreetMap! intro_2_create_account: Създаване на сметка + partners_ucl: UCL partners_partners: партньори help: Помощ about: За проекта copyright: Авторски права community: Общност + foundation: Фондация make_a_donation: text: Направете дарение learn_more: Научете повече @@ -726,6 +750,9 @@ bg: mapping_link: картографиране legal_babble: title_html: Авторски права и лиценз + contributors_fr_html: |- + Франция: Съдържа данни от + Главната данъчна дирекция. infringement_title_html: Нарушаване на авторските права trademarks_title_html: Търговски марки trademarks_1_html: OpenStreetMap и логото с лупата са регистрирани търговски @@ -743,6 +770,8 @@ bg: fixthemap: how_to_help: title: Как да помогна + join_the_community: + title: Присъединете са към общността help_page: welcome: title: Добре дошли в OSM @@ -750,6 +779,7 @@ bg: title: Наръчник за начинаещи help: url: https://help.openstreetmap.org/ + title: help.openstreetmap.org mailing_lists: title: Пощенски списъци forums: @@ -764,6 +794,7 @@ bg: about_page: next: Следващ legal_title: Правни въпроси + partners_title: Партньори notifier: diary_comment_notification: hi: Здравейте %{to_user}, @@ -797,6 +828,8 @@ bg: note_comment_notification: anonymous: Анонимен потребител greeting: Здравейте, + commented: + subject_other: '[OpenStreetMap] %{commenter} коментира бележка, която ви интересува' changeset_comment_notification: hi: Здравейте %{to_user}, greeting: Здравейте, @@ -828,6 +861,7 @@ bg: title: Изпратете съобщение send_message_to: Изпратете ново съобщение на %{name} subject: Тема + body: Текст send_button: Изпращане message_sent: Съобщението е изпратено no_such_message: @@ -850,6 +884,7 @@ bg: date: Дата reply_button: Отговор unread_button: Отбелязване като непрочетено + delete_button: Изтриване back: Назад to: До sent_message_summary: @@ -858,6 +893,8 @@ bg: deleted: Съобщението беше изтрито site: index: + permalink: Постоянна връзка + shortlink: Къса връзка createnote: Добавяне на бележка sidebar: search_results: Резултати от търсенето @@ -951,6 +988,7 @@ bg: filename: 'Име на файл:' download: сваляне uploaded_at: 'Качени:' + points: 'Точки:' map: карта edit: редактиране owner: 'Собственик:' @@ -976,6 +1014,7 @@ bg: view: pending: Обработва се filename: 'Име на файл:' + download: изтегляне map: карта edit: редактиране owner: 'Собственик:' @@ -992,6 +1031,9 @@ bg: view_map: Вижте на картата edit: редактиране edit_map: Редактиране на картата + public: ПУБЛИЧНО + private: ЧАСТНО + trackable: ПРОСЛЕДИМО by: от in: в map: карта @@ -999,6 +1041,8 @@ bg: public_traces: Публични GPS-следи your_traces: Вашите GPS-следи public_traces_from: Публични GPS-следи от потребител %{user} + description: + description_without_count: GPX-файл от %{user} oauth: oauthorize: allow_write_api: промени картата. @@ -1089,6 +1133,7 @@ bg: no_such_user: title: Няма такъв потребител heading: Потребителят %{user} не съществува + deleted: изтрито view: my edits: Mоите редакции my traces: Моите следи @@ -1108,15 +1153,21 @@ bg: latest edit: 'Последна редакция %{ago}:' email address: 'Електронна поща:' created from: 'Създадено от:' + status: 'Състояние:' + spam score: 'Оценка за спам:' description: Описание user location: Местоположение settings_link_text: настройки your friends: Вашите приятели no friends: Все още нямате добавени приятели. km away: '%{count} км от вас' + nearby users: Други потребители наблизо comments: Коментари create_block: Блокиране на този потребител delete_user: Изтриване на този потребител + confirm: Потвърдете + popup: + friend: Приятел account: title: Редакция на профил my settings: Моите настройки @@ -1160,6 +1211,7 @@ bg: success: '%{name} беше премахнат от списъка с приятелите.' list: title: Потребители + heading: Потребители user_role: grant: confirm: Потвърждаване @@ -1182,6 +1234,7 @@ bg: entry: comment: Коментар mine: + creator: Автор ago_html: преди %{when} javascripts: share: @@ -1231,6 +1284,8 @@ bg: notes: new: add: Добавяне на бележка + show: + comment: Коментар directions: engines: graphhopper_bicycle: Велосипед (GraphHopper) @@ -1254,6 +1309,8 @@ bg: destination_without_exit: Пристигнахте на местоназначението unnamed: неименуван път time: Време + query: + node: Възел context: add_note: Добавете бележка тук ... diff --git a/config/locales/bn.yml b/config/locales/bn.yml index 4ed4b2c7f..009091e9d 100644 --- a/config/locales/bn.yml +++ b/config/locales/bn.yml @@ -379,7 +379,6 @@ bn: search: title: latlon: অভ্যন্তরীণ থেকে ফলাফল - us_postcode: Geocoder.usNPEMap / FreeThe Postcode থেকে ফলাফল ca_postcode: Geocoder.CA থেকে ফলাফল @@ -475,6 +474,7 @@ bn: reception_area: অভ্যর্থন এলাকা restaurant: রেঁস্তোরা retirement_home: অবসর গৃহ + sauna: বাষ্পস্নান school: বিদ্যালয় shelter: আশ্রয় shop: দোকান @@ -672,6 +672,7 @@ bn: volcano: আগ্নেয়গিরি water: পানি wetland: জলাভূমি + wood: কাঠ office: accountant: হিসাবরক্ষক administrative: প্রশাসন @@ -935,6 +936,7 @@ bn: other_concerns: title: অন্যান্য উদ্বেগ help_page: + title: সাহায্য পান welcome: url: /স্বাগতম title: ওএসএম-এ স্বাগতম @@ -1002,10 +1004,10 @@ bn: note_comment_notification: anonymous: একজন বেনামি ব্যবহারকারী greeting: হাই, - details: টীকাটি সম্পর্কে আরও বিস্তারিত %{url|এখানে} পাওয়া যাবে। + details: টীকাটি সম্পর্কে আরও বিস্তারিত %{url} এ পাওয়া যাবে। changeset_comment_notification: greeting: হাই, - details: পরিবর্তনধার্য সম্পর্কে আরও বিস্তারিত %{url|এখানে} পাওয়া যাবে। + details: পরিবর্তনধার্য সম্পর্কে আরও বিস্তারিত %{url} এ পাওয়া যাবে। message: inbox: title: ইনবক্স @@ -1047,6 +1049,7 @@ bn: date: তারিখ reply_button: প্রত্যুত্তর unread_button: অপঠিত হিসেবে চিহ্নিত করুন + delete_button: অপসারণ back: পিছনে to: প্রাপক sent_message_summary: @@ -1371,6 +1374,8 @@ bn: reactivate: পুনঃসক্রিয় comment: মন্তব্য directions: + engines: + graphhopper_car: গাড়ি (GraphHopper) directions: দিক distance: দূরত্ব errors: diff --git a/config/locales/br.yml b/config/locales/br.yml index f28795547..d1218b530 100644 --- a/config/locales/br.yml +++ b/config/locales/br.yml @@ -387,7 +387,6 @@ br: search: title: latlon: Disoc'hoù diwar Internal - us_postcode: Disoc'hoù diwar Geocoder.us uk_postcode: Disoc'hoù diwar NPEMap / FreeThe Postcode ca_postcode: Disoc'hoù diwar Geocoder.CA @@ -954,7 +953,7 @@ br: intro_2_create_account: Krouiñ ur gont implijer partners_html: '%{ucl}, %{ic}, %{bytemark}, ha %{partners} all a ra war-dro an herberc''hiañ.' - partners_ucl: ↓Kreizenn VR an UCL + partners_ucl: ↓"Universiy College" Londrez partners_ic: Skolaj impalaerel Londrez partners_bytemark: ↓Herberc'hiañ Bytemark partners_partners: Kevelourien @@ -1415,6 +1414,7 @@ br: date: Deiziad reply_button: Respont unread_button: Merkañ evel anlennet + delete_button: Diverkañ back: Distreiñ to: Da wrong_user: Kevreet oc'h evel "%{user}", met ar gemennadenn a fell deoc'h lenn @@ -2379,6 +2379,7 @@ br: ascend: Pignat engines: graphhopper_bicycle: Marc'h-houarn (GraphHopper) + graphhopper_car: Karr GraphHopper) graphhopper_foot: Troad (GraphHopper) mapquest_bicycle: Marc'h-houarn (MapQuest) mapquest_car: Karr (MapQuest) diff --git a/config/locales/bs.yml b/config/locales/bs.yml index 7f4e3a8d0..2f2d03731 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -325,7 +325,6 @@ bs: search: title: latlon: Rezultati sa Internal - us_postcode: Rezultati sa Geocoder.us uk_postcode: Rezultati sa NPEMap / FreeThe Postcode ca_postcode: Rezultati sa Geocoder.CA @@ -859,7 +858,7 @@ bs: intro_2_create_account: Napravite korisnički račun partners_html: Hosting je podržan od strane %{ucl}, %{ic} i %{bytemark}, i drugih %{partners}. - partners_ucl: UCL VR Centar + partners_ucl: UCL partners_ic: Imperial College London partners_bytemark: Bytemark Hosting partners_partners: partnera @@ -1614,16 +1613,16 @@ bs: revoke: administrator: Opozvati pristup za administatora moderator: Opozvati pristup za moderatora - block_history: prikazati dobivene blokade - moderator_history: prikazati date blokade + block_history: Aktivne blokade + moderator_history: Date blokade comments: komentari - create_block: blokirati ovog korisnika - activate_user: aktivirati ovog korisnika - deactivate_user: deaktivirati ovog korisnika - confirm_user: potvrditi ovog korisnika - hide_user: sakriti ovog korisnika - unhide_user: otkriti ovog korisnika - delete_user: izbrisati ovog korisnika + create_block: Blokiraj ovog korisnika + activate_user: Aktiviraj ovog korisnika + deactivate_user: Deaktiviraj ovog korisnika + confirm_user: Potvrdi ovog korisnika + hide_user: Sakrij ovog korisnika + unhide_user: Otkrij ovog korisnika + delete_user: ObriÅ¡i ovog korisnika confirm: Potvrditi friends_changesets: promjena spiska prijatelja friends_diaries: unosi u dnevnik prijatelja diff --git a/config/locales/ca.yml b/config/locales/ca.yml index e23b4f80c..106f2c060 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -224,7 +224,7 @@ ca: telephone_link: Telefona %{phone_number} note: title: 'Nota: %{id}' - new_note: Nova nota + new_note: Nota nova description: Descripció open_title: 'Nota no resolta: #%{note_name}' closed_title: 'Nota resolta #%{note_name}' @@ -282,7 +282,7 @@ ca: full: Discussió sencera diary_entry: new: - title: Nova Entrada de Diari + title: Entrada de diari nova publish_button: Publica list: title: Diaris d'usuari/a @@ -290,7 +290,7 @@ ca: title_nearby: Diaris d'amics propers user_title: Diari de %{user} in_language_title: Entrades de diari en %{language} - new: Nova Entrada de Diari + new: Entrada de diari nova new_title: Redacta una nova entrada al teu diari d'usuari/a no_entries: No hi ha entrades al diari recent_entries: 'Entrades recents al diari:' @@ -412,7 +412,6 @@ ca: search: title: latlon: Resultats propis - us_postcode: Resultats de Geocoder.us uk_postcode: Resultats de NPEMap / FreeThe Postcode ca_postcode: Resultats de Geocoder.CA @@ -1439,6 +1438,7 @@ ca: date: Data reply_button: Respon unread_button: Marca com a no llegit + delete_button: Suprimeix back: Enrere to: Per a wrong_user: Heu iniciat la sessió com a "%{user}", però el missatge que voleu @@ -1990,7 +1990,7 @@ ca: block_history: Blocatges actius moderator_history: Blocatges imposats comments: Comentaris - create_block: Bloqueja aquest usuari + create_block: Bloca aquest usuari activate_user: Activa aquest usuari deactivate_user: Desactiva aquest usuari confirm_user: Confirma aquest usuari @@ -2197,31 +2197,29 @@ ca: s'aturés. tried_waiting: Li he donat una quantitat raonable de temps a l'usuari per a respondre a aquestes comunicacions. - needs_view: L'usuari necessita connectar-se abans que aquest bloqueig es suprimeixi + needs_view: L'usuari necessita connectar-se abans que aquest blocatge es suprimeixi back: Mostra tots els blocs edit: title: Bloc d'edició en %{name} heading: Bloc d'edició en %{name} - reason: La raó per què està sent bloquejat %{name}. Si us plau, ser tan tranquil - i tan raonable com sigui possible, donant amb tant detall com sigui possible - sobre la situació. Tingueu en compte que no tots els usuaris de comprendre - l'argot de la comunitat, així que si us plau, intenti utilitzar termes de - l'home comú. - period: Quant de temps, a partir d'ara, l'usuari es bloqueja des de l'API per - a. + reason: La raó per la qual %{name} està sent blocat. Si us plau, sigueu tan + tranquil i tan raonable com sigui possible, donant tant detall com sigui possible + sobre la situació. Tingueu en compte que no tots els usuaris comprenen l'argot + de la comunitat, així que si us plau, intenteu utilitzar termes comuns. + period: Quant de temps, a partir d'ara, l'usuari tindrà blocat l'accés a l'API. submit: Bloc d'Actualització show: Mostra el bloc back: Mostra tots els blocs - needs_view: L'usuari necessita connectar-se abans que aquest bloqueig es suprimeixi? + needs_view: L'usuari necessita connectar-se abans que aquest blocatge es suprimeixi? filter: block_expired: El bloc ja ha expirat i no es pot editar. block_period: El període de blocatge ha de ser un dels valors seleccionables de la llista desplegable. create: - try_contacting: Si us plau, intentar contactar-se amb l'usuari abans de bloqueig + try_contacting: Si us plau, intentar contactar-se amb l'usuari abans de blocatge d'ells i donar-los un termini raonable per respondre. try_waiting: Si us plau tracti de donar l'usuari d'un termini raonable per respondre - abans de bloqueig d'ells. + abans de blocatge d'ells. flash: Crear un bloc a l'usuari %{name}. update: only_creator_can_edit: Només el moderador que ha creat aquest bloc pot editar-lo. @@ -2268,8 +2266,8 @@ ca: heading: Llista de blocs %{name} empty: '%{name} no ha fet cap blocs encara.' show: - title: '%{block_on} bloquejat per %{block_by}' - heading: '%{block_on} bloquejat per %{block_by}' + title: '%{block_on} blocat per %{block_by}' + heading: '%{block_on} blocat per %{block_by}' time_future: Finalitza en %{time} time_past: Va acabar fa %{time} created: Creat diff --git a/config/locales/cs.yml b/config/locales/cs.yml index f9a9fa35d..1e7cec987 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -410,7 +410,6 @@ cs: search: title: latlon: Výsledky z interní databáze - us_postcode: Výsledky z Geocoder.us uk_postcode: Výsledky z NPEMap / FreeThe Postcode ca_postcode: Výsledky z Geocoder.CA @@ -1407,6 +1406,7 @@ cs: date: Datum reply_button: Odpovědět unread_button: Označit jako nepřečtené + delete_button: Smazat back: Zpět to: Komu wrong_user: Jste přihlášeni jako „%{user}“, ale zpráva, kterou si chcete přečíst, diff --git a/config/locales/cy.yml b/config/locales/cy.yml index c90978652..b97ad20cf 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -290,7 +290,6 @@ cy: search: title: latlon: Canlyniadau o Internal - us_postcode: Canlyniadau o Geocoder.us uk_postcode: Canlyniadau o NPEMap / FreeThe Postcode ca_postcode: Canlyniadau o Geocoder.CA diff --git a/config/locales/da.yml b/config/locales/da.yml index 979f21fe6..edfc15ca6 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -403,7 +403,6 @@ da: search: title: latlon: Resultater fra interne - us_postcode: Resultater fra Geocoder.us uk_postcode: Resultater fra NPEMap / FreeThe Postcode ca_postcode: Resultater fra Geocoder.CA @@ -969,7 +968,7 @@ da: at bruge under en Ã¥ben licens. intro_2_create_account: Opret en brugerkonto partners_html: Hosting understøttes af %{ucl}, %{ic} og %{bytemark} og andre %{partners}. - partners_ucl: UCL VR centret + partners_ucl: University College London partners_ic: Imperial College London partners_bytemark: Bytemark Hosting partners_partners: partnere @@ -1016,18 +1015,18 @@ da: Hvis du ændrer eller bygger pÃ¥ vores\ndata, mÃ¥ du kun distribuere resultatet under den samme licens. Den\nfulde juridiske tekst\nforklarer dine rettigheder og pligter." - intro_3_html: Kartografi i vores kort, og vores dokumentation er licenseret - under Creative + intro_3_html: Kartografien i vores kort-fliser, samt vores dokumentation er + licenseret under Creative Commons Navngivelse-DelPÃ¥SammeVilkÃ¥r 2.0 (CC BY-SA). credit_title_html: Kildeangivelse og OpenStreetMap credit_1_html: Vi kræver at din kildeangivelse mindst bestÃ¥r af “© OpenStreetMap-bidragsydere”.. credit_2_html: "Du skal ogsÃ¥ gøre det klart, at dataene er tilgængelige under - Open \nDatabase License, og hvis du bruger vores kort fliser, at kartografi - er\n licenseret som CC-BY-SA. Du kan gøre dette ved at linke til\ndenne + Open \nDatabase License, og hvis du bruger vores kort-fliser, at kartografien + er\n licenseret som CC BY-SA. Du kan gøre dette ved at linke til\ndenne side om ophavsret. \nAlternativt, og som et krav, hvis du distribuerer - OSM i en\n dataform, kan du navngive og oprette et hyperlink direkte til licenserne. - I medier\n hvor hyperlinks ikke er mulig (f.eks. trykte værker), foreslÃ¥r + OSM som\n data, kan du navngive og oprette et hyperlink direkte til licenserne. + I medier\n hvor hyperlinks ikke er mulige (f.eks. trykte værker), foreslÃ¥r vi, at du\n henviser dine læsere til openstreetmap.org (mÃ¥ske ved at udvide\n'OpenStreetMap' til denne fuld adresse), til opendatacommons.org, og\n hvis relevant, til creativecommons.org." @@ -1039,17 +1038,17 @@ da: title: Eksempel pÃ¥ kildeangivelse more_title_html: Læs mere more_1_html: |- - Læs mere om brug af vores data, og hvordan du kreditere os, pÃ¥ OSMF Licenssiden og pÃ¥ den juridiske + Læs mere om brug af vores data, og hvordan du krediterer os, pÃ¥ OSMF Licens-siden og i fællesskabets Juridiske FAQ. more_2_html: |- Selvom OpenStreetMap er Ã¥bne data, kan vi ikke levere et gratis kort-API til tredjeparter. Se vores Politik for brug af API, - Politik for brug af kortbilleder - og politik for brug af Nominatim. + Politik for brug af kort-fliser + og Politik for brug af Nominatim. contributors_title_html: Vores bidragsydere contributors_intro_html: |- Vores bidragsydere er tusinder af individer. Vi medtager ogsÃ¥ @@ -1432,6 +1431,7 @@ da: date: Dato reply_button: Svar unread_button: Marker som ulæst + delete_button: Slet back: Tilbage to: Til wrong_user: Du er logget pÃ¥ som '%{user}', men den besked du har bedt om at @@ -2382,8 +2382,10 @@ da: comment: Kommenter edit_help: Flyt kortet og zoom ind pÃ¥ et sted, du vil redigere, og klik sÃ¥ her. directions: + ascend: Stigning engines: graphhopper_bicycle: Cykel (GraphHopper) + graphhopper_car: Bil (GraphHopper) graphhopper_foot: Til fods (GrapHopper) mapquest_bicycle: Cykel (MapQuest) mapquest_car: Bil (MapQuest) @@ -2392,6 +2394,7 @@ da: mapzen_bicycle: Cykel (Mapzen) mapzen_car: Bil (Mapzen) mapzen_foot: Fod (Mapzen) + descend: Fald directions: Rutevejledning distance: Afstand errors: diff --git a/config/locales/de.yml b/config/locales/de.yml index ea7906de6..f7f350ec7 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -430,7 +430,6 @@ de: search: title: latlon: Suchergebnisse von Internal - us_postcode: Suchergebnisse von Geocoder.us uk_postcode: Suchergebnisse von NPEMap / FreeThe Postcode ca_postcode: Suchergebnisse von Geocoder.CA @@ -1477,6 +1476,7 @@ de: date: Datum reply_button: Antworten unread_button: Als ungelesen markieren + delete_button: Löschen back: Zurück to: An wrong_user: Du bist angemeldet als '%{user}', aber die Nachricht, die du lesen diff --git a/config/locales/diq.yml b/config/locales/diq.yml index a646cc13d..dc8ecc6be 100644 --- a/config/locales/diq.yml +++ b/config/locales/diq.yml @@ -274,7 +274,6 @@ diq: search: title: latlon: OSM ra neticey - us_postcode: Geocoder.us ra neticey uk_postcode: FreeThe Postcode ra neticey ca_postcode: Geocoder.CA ra neticey osm_nominatim: OSM Nominatim @@ -466,7 +465,7 @@ diq: historic: archaeological_site: Arkeolojik Ca battlefield: Cay herbi - boundary_stone: Siya sinori + boundary_stone: Kemera Sinori building: Binaya verên bunker: Stare castle: Qela @@ -678,8 +677,11 @@ diq: gift: Çiyo Hediye salon: Kuafor tourism: + gallery: Galeriye hostel: Hostel hotel: Hotel + information: Melumat + motel: Motel tunnel: "yes": Tûnêl waterway: @@ -698,9 +700,16 @@ diq: edit: Bıvırne history: Tarix export: Tebergroten + data: Melumati help: Peşti + copyright: Heqa telıfi community: Cemaet community_blogs: Blogê Cemaeti + license_page: + native: + title: Heqa na pele de + welcome_page: + title: Xeyr amey! notifier: diary_comment_notification: hi: Merheba %{to_user}, @@ -716,6 +725,10 @@ diq: greeting: Merheba, lost_password_html: greeting: Merheba, + note_comment_notification: + greeting: Merheba, + changeset_comment_notification: + greeting: Merheba, message: inbox: title: Ameyan @@ -728,6 +741,7 @@ diq: reply_button: Cewab bıde delete_button: Bestere new: + title: Mesac bırışê subject: Mewzu body: Vêrey mesaci send_button: Bırışe @@ -739,13 +753,18 @@ diq: subject: Mewzu date: Dem read: + title: Mesaci bıwanê subject: Mewzu date: Dem reply_button: Cewab bıde + delete_button: Bestere + back: Peyser to: Kêrê sent_message_summary: delete_button: Bestere site: + edit: + user_page_link: pela karberi sidebar: search_results: Neticeyê geyrayışi close: Racnê @@ -1075,6 +1094,9 @@ diq: entry: comment: Mışewre javascripts: + share: + cancel: Bıtexelne + image: Resım map: base: standard: Standard diff --git a/config/locales/dsb.yml b/config/locales/dsb.yml index 948147f06..1a605354d 100644 --- a/config/locales/dsb.yml +++ b/config/locales/dsb.yml @@ -363,7 +363,6 @@ dsb: search: title: latlon: Wuslědki z Internal - us_postcode: Wuslědki z Geocoder.us uk_postcode: Wuslědki z NPEMap / FreeThe Postcode ca_postcode: Wuslědki z Geocoder.CA diff --git a/config/locales/el.yml b/config/locales/el.yml index dd772a2d9..efa40abda 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -13,6 +13,7 @@ # Author: Kongr43gpen # Author: Logictheo # Author: Macofe +# Author: Nikosgranturismogt # Author: Omnipaedista # Author: Protnet # Author: Ruila @@ -418,7 +419,6 @@ el: title: latlon: Αποτελέσματα από την εσωτερική βάση δεδομένων - us_postcode: Αποτελέσματα από Geocoder.us uk_postcode: Αποτελέσματα από NPEMap / FreeThe Postcode ca_postcode: Αποτελέσματα από Geocoder.CA @@ -1281,6 +1281,7 @@ el: footer_html: Μπορείτε επίσης να διαβάσετε το μήνυμα στο %{readurl} και να απαντήσετε στο %{replyurl} friend_notification: + hi: Γεια σας %{to_user}, subject: '[OpenStreetMap] Ο χρήστης %{user} σας πρόσθεσε ως φίλο' had_added_you: Ο χρήστης %{user} σας πρόσθεσε ως φίλο στο OpenStreetMap. see_their_profile: Μπορείτε να δείτε το προφίλ του στο %{userurl}. @@ -1452,6 +1453,7 @@ el: date: Ημ/νία reply_button: Απάντηση unread_button: Σήμανση ως αδιάβαστο + delete_button: Διαγραφή back: Επιστροφή to: Προς wrong_user: Έχετε συνδεθεί ως «%{user}» αλλά το μήνυμα που ζητάτε να διαβάσετε @@ -2249,6 +2251,8 @@ el: helper: time_future: Τελειώνει σε %{time}. until_login: Ενεργό έως ότου ο χρήστης συνδεθεί. + time_future_and_until_login: Τελειώνει σε %{time} και μετά αφότου ο χρήστης + έχει συνδεθεί. time_past: Τελείωσε %{time} πριν. blocks_on: title: Φραγές στον %{name} @@ -2392,8 +2396,10 @@ el: edit_help: Μετακινήστε το χάρτη και να κάνετε ζουμ σε μια τοποθεσία που θέλετε να επεξεργαστείτε, στη συνέχεια, κάντε κλικ εδώ. directions: + ascend: Ανάβαση engines: graphhopper_bicycle: Ποδήλατο (GraphHopper) + graphhopper_car: Με τα πόδια (GraphHopper) graphhopper_foot: Με τα πόδια (GraphHopper) mapquest_bicycle: Ποδήλατο (MapQuest) mapquest_car: Αυτοκίνητο (MapQuest) @@ -2402,6 +2408,7 @@ el: mapzen_bicycle: Ποδήλατο (Mapzen) mapzen_car: Αυτοκίνητο (Mapzen) mapzen_foot: Με τα πόδια (Mapzen) + descend: Κατάβαση directions: Οδηγίες distance: Απόσταση errors: diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 430af7d45..07f8eaeec 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -399,7 +399,6 @@ en-GB: search: title: latlon: Results from Internal - us_postcode: Results from Geocoder.us uk_postcode: Results from NPEMap / FreeThe Postcode ca_postcode: Results from Geocoder.CA @@ -1423,6 +1422,7 @@ en-GB: date: Date reply_button: Reply unread_button: Mark as unread + delete_button: Delete back: Back to: To wrong_user: You are logged in as `%{user}' but the message you have asked to @@ -2383,6 +2383,7 @@ en-GB: ascend: Ascend engines: graphhopper_bicycle: Bicycle (GraphHopper) + graphhopper_car: Car (GraphHopper) graphhopper_foot: Foot (GraphHopper) mapquest_bicycle: Bicycle (MapQuest) mapquest_car: Car (MapQuest) diff --git a/config/locales/en.yml b/config/locales/en.yml index a05083a1e..6b7fb470c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -367,7 +367,6 @@ en: search: title: latlon: 'Results from Internal' - us_postcode: 'Results from Geocoder.us' uk_postcode: 'Results from NPEMap / FreeThe Postcode' ca_postcode: 'Results from Geocoder.CA' osm_nominatim: 'Results from OpenStreetMap Nominatim' diff --git a/config/locales/eo.yml b/config/locales/eo.yml index ce7e57fda..202b064a7 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -390,7 +390,6 @@ eo: search: title: latlon: Rezultoj el Internal - us_postcode: Rezultoj el Geocoder.us uk_postcode: Rezultoj el NPEMap / FreeThe Postcode ca_postcode: Rezultoj el Geocoder.CA @@ -801,14 +800,14 @@ eo: beverages: Trinkaĵ-vendejo bicycle: Bicikl-vendejo books: Libro-vendejo - boutique: Galanterio + boutique: Mod-butiko butcher: Viand-vendejo car: AÅ­tomobil-vendejo car_parts: AÅ­tomobil-parta vendejo car_repair: AÅ­toriparejo carpet: Tapiŝ-vendejo charity: Almoza vendejo - chemist: Drogejo + chemist: Purigaĵ-vendejo clothes: Vesto-vendejo computer: Komputil-vendejo confectionery: Sukeraĵejo @@ -836,7 +835,7 @@ eo: greengrocer: Legom-butiko grocery: Manĝovendejo hairdresser: Frizejo - hardware: Il-vendejo + hardware: Laboril-vendejo hifi: Altfidel-son-vendejo insurance: Asekurkompaniejo jewelry: Juvel-vendejo @@ -1003,9 +1002,9 @@ eo: modifos aÅ­ uzos niajn datumojn, vi povos distribui la verkon laÅ­ la sama permesilo. La plena interkonsento de uzado klarigas viajn rajtojn kaj devojn. - intro_3_html: |- - La kartografio de niaj map-kaheloj kaj nia dokumentaro estas disponeblaj laÅ­ la permesilo Creative - Commons Atribuite-Samkondiĉe 2.0 (CC BY-SA). + intro_3_html: La kartografio de niaj map-kaheloj kaj nia dokumentaro estas disponeblaj + laÅ­ la permesilo Krea + Komunaĵo Atribuite-Samkondiĉe 2.0 (CC BY-SA). credit_title_html: Kiel atribui aÅ­torecon credit_1_html: 'Ni postulas, ke vi markos: “© Kontribuintoj de OpenStreetMap”.' credit_2_html: Vi ankaÅ­ devas klarigi, ke datumoj estas disponeblaj laÅ­ la permesilo @@ -1037,7 +1036,7 @@ eo: inkludas datumoj laÅ­ malferma permesilo el landaj kartografiaj organizaĵoj kaj el aliaj fontoj, inter ili:' contributors_at_html: |- - AÅ­strujo: enhavas datumojn el Stadt Wien (sub CC BY), + AÅ­strujo: enhavas datumojn el Stadt Wien (laÅ­ CC BY), Land Vorarlberg kaj Land Tirol (sub CC BY AT kun postaj ŝanĝoj). contributors_ca_html: |- @@ -1388,6 +1387,7 @@ eo: date: Dato reply_button: Respondi unread_button: Marki kiel nelegitan + delete_button: Forigi back: Reen to: Al wrong_user: Vi estas ensalutinta kiel '%{user}', sed la mesaĝo, kiun vi volas @@ -1529,7 +1529,7 @@ eo: text: Teksto image: Bildo alt: Kromteksto - url: Retadreso + url: URL trace: visibility: private: Privata (kunhavigita nur kiel sennomaj, malordigitaj punktoj) @@ -2270,7 +2270,7 @@ eo: key: title: Mapklarigo tooltip: Mapklarigo - tooltip_disabled: Mapklarigo estas ne disponeblas por ĉi tiu tavolo + tooltip_disabled: Mapklarigo ne disponeblas por tiu ĉi tavolo map: zoom: in: Pligrandigi @@ -2285,7 +2285,7 @@ eo: hot: Hom-helpa mapo layers: header: Tavoloj de mapo - notes: Notoj pri mapo + notes: Map-rimarkoj data: Map-datumoj gps: Publikaj GPS-spuroj overlays: Aktivigu surtavolojn por solvi problemojn kun la mapo @@ -2296,7 +2296,7 @@ eo: edit_tooltip: Redakti la mapon edit_disabled_tooltip: Pligrandigu por redakti la mapon createnote_tooltip: Aldoni rimarkon al la mapo - createnote_disabled_tooltip: Pligrandigu por aldoni noton al la mapo + createnote_disabled_tooltip: Pligrandigu por aldoni rimarkon al la mapo map_notes_zoom_in_tooltip: Pligrandigu por vidi map-rimarkoj map_data_zoom_in_tooltip: Pligrandigu por vidi map-datumoj queryfeature_tooltip: Montri informoj pri objekto @@ -2310,9 +2310,9 @@ eo: unhide_comment: malkaŝi notes: new: - intro: Vi rimarkis eraron aÅ­ iu mankas? Sciigu aliajn mapigistojn, por ili + intro: Vi rimarkis eraron aÅ­ io mankas? Sciigu aliajn mapigistojn, por ili povos ripari tion. Movu la markon al la respektivan pozicion kaj enmetu - la noton priskribantan la problemon. (Bonvolu ne enmeti personajn informojn + la rimarkon priskribantan la problemon. (Bonvolu ne enmeti personajn informojn aÅ­ informojn el kopirajtaj mapoj aÅ­ fontoj.) add: Aldoni rimarkon show: @@ -2348,20 +2348,21 @@ eo: continue_without_exit: AntaÅ­en al %{name} slight_right_without_exit: Ete dekstren al %{name} offramp_right_without_exit: Veturu la elveturejon dekstre al %{name} - onramp_right_without_exit: Turnu dekstren al la elveturejo al %{name} - endofroad_right_without_exit: Ĉe la fino de la vojo turnu dekstren al %{name} - merge_right_without_exit: Turnu dekstren al %{name} - fork_right_without_exit: Ĉe la vojforko turnu dekstren al %{name} - turn_right_without_exit: Turnu dekstren al %{name} - sharp_right_without_exit: Akute dekstren al %{name} + onramp_right_without_exit: Turniĝu dekstren al la elveturejo al %{name} + endofroad_right_without_exit: Ĉe la fino de la vojo turniĝu dekstren al %{name} + merge_right_without_exit: Turniĝu dekstren al %{name} + fork_right_without_exit: Ĉe la vojforko turniĝu dekstren al %{name} + turn_right_without_exit: Turniĝu dekstren al %{name} + sharp_right_without_exit: Ege dekstren al %{name} uturn_without_exit: U-forma ĝirado laÅ­ %{name} - sharp_left_without_exit: Akute maldekstren al %{name} - turn_left_without_exit: Turnu maldekstren al %{name} + sharp_left_without_exit: Ege maldekstren al %{name} + turn_left_without_exit: Turniĝu maldekstren al %{name} offramp_left_without_exit: Veturu la elveturejon maldekstre al %{name} - onramp_left_without_exit: Turnu maldekstren al la elveturejo al %{name} - endofroad_left_without_exit: Ĉe la fino de la vojo turnu maldekstren al %{name} - merge_left_without_exit: Turnu maldekstren al %{name} - fork_left_without_exit: Ĉe la vojforko turnu maldekstren al %{name} + onramp_left_without_exit: Turniĝu maldekstren al la elveturejo al %{name} + endofroad_left_without_exit: Ĉe la fino de la vojo turniĝu maldekstren al + %{name} + merge_left_without_exit: Turniĝu maldekstren al %{name} + fork_left_without_exit: Ĉe la vojforko turniĝu maldekstren al %{name} slight_left_without_exit: Ete maldekstren al %{name} via_point_without_exit: (tra punkto) follow_without_exit: Sekvu %{name} @@ -2373,11 +2374,11 @@ eo: against_oneway_without_exit: Iru kontraÅ­-direkte al %{name} end_oneway_without_exit: Fino de unuflanka vojo ĉe %{name} roundabout_with_exit: Ĉe trafikcirklo prenu %{exit}-an elveturejon al %{name} - turn_left_with_exit: En trafikcirklo turnu maldekstren al %{name} - slight_left_with_exit: En trafikcirklo turnetu maldekstren al %{name} - turn_right_with_exit: En trafikcirklo turnu dekstren al %{name} - slight_right_with_exit: En trafikcirklo turnetu dekstren al %{name} - continue_with_exit: En trafikcirklo veturi rekten al %{name} + turn_left_with_exit: Ĉe trafikcirklo turniĝu maldekstren al %{name} + slight_left_with_exit: Ĉe trafikcirklo turniĝetu maldekstren al %{name} + turn_right_with_exit: Ĉe trafikcirklo turniĝu dekstren al %{name} + slight_right_with_exit: Ĉe trafikcirklo turniĝetu dekstren al %{name} + continue_with_exit: Ĉe trafikcirklo veturu rekten al %{name} unnamed: sennoma vojo courtesy: Kalkulado de kurso danke al %{link} time: Tempo @@ -2412,7 +2413,7 @@ eo: title: Kreado de nova korekto show: description: 'Priskribo:' - heading: Montrado de korekto "%{title}" + heading: Montrado de redakto “%{title}” title: Montrado de korekto user: 'AÅ­toro:' edit: Redakti ĉu tiun korekton diff --git a/config/locales/es.yml b/config/locales/es.yml index 79fa198f7..db52988d8 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -16,6 +16,7 @@ # Author: Idontknow # Author: Indiralena # Author: Invadinado +# Author: Javiersanp # Author: Johnarupire # Author: Jynus # Author: Larjona @@ -419,7 +420,6 @@ es: search: title: latlon: Resultados internos - us_postcode: Resultados de Geocoder.us uk_postcode: Resultados de NPEMap / FreeThe Postcode ca_postcode: Resultados de Geocoder.CA @@ -1056,8 +1056,8 @@ es: more_2_html: |- A pesar de que OpenStreetMap es contenido abierto, no podemos suminstrar una API de mapas gratuita para terceros. - Consulta nuestra Política de uso del API, - Política de uso de mosaicos de mapas y Política de uso de Nominatim. + Consulta nuestra normativa de uso de la API, la + normativa de uso de mosaicos de mapas y la normativa de uso de Nominatim. contributors_title_html: Nuestros colaboradores contributors_intro_html: 'Nuestros colaboradores son miles de personas. Incluimos también datos con licencia abierta de organismos cartográficos nacionales @@ -1124,8 +1124,9 @@ es: y actuales - esto incluye millones de edificios, carreteras, y otros detalles acerca de lugares. Puede mapear cualquier característica de la vida real que es interesante para usted. - off_html: Lo que no se incluyen son datos obstinados como clasificaciones, - características históricas o hipotéticas, y datos procedentes de fuentes con + off_html: Lo que no se incluye son datos basados en opiniones (por + ejemplo, valoraciones), características históricas que ya no existen sobre + el terreno o hipotéticas, ni datos provenientes de fuentes protegidas por derechos de autor. A menos que tenga un permiso especial, no copie de mapas en línea o en papel. basic_terms: @@ -1246,8 +1247,8 @@ es: legal_html: "Este sitio y muchos otros servicios relacionados son gestionados por la \nFundación OpenStreetMap (OSMF) \nen nombre de la comunidad. El uso de todos los servicios gestionados por la - OSMF está sujeto \na nuestra \npolítica - de uso aceptable y nuestra política + OSMF está sujeto \na nuestra \nnormativa + de uso aceptable y nuestra normativa de privacidad\n
      \nContacta con la OSMF \nsi tienes preguntas o problemas sobre licencias, derechos de autor u otro tema legal." @@ -1432,6 +1433,7 @@ es: date: Fecha reply_button: Responder unread_button: Marcar como no leído + delete_button: Eliminar back: Volver to: A wrong_user: Está conectado como `%{user}' pero el mensaje que quiere leer no @@ -1750,7 +1752,7 @@ es: support_notice: Soportamos HMAC-SHA1 (recomendado) y firmas RSA-SHA1. edit: Editar detalles delete: Eliminar cliente - confirm: ¿Estás seguro? + confirm: ¿Lo confirmas? requests: 'Solicitando los siguientes permisos del usuario:' allow_read_prefs: leer sus preferencias de usuario. allow_write_prefs: modificar sus preferencias de usuario. @@ -1891,9 +1893,9 @@ es: email address: 'Dirección de correo electrónico:' confirm email address: 'Confirmar la dirección de correo electrónico:' not displayed publicly: Tu dirección no se muestra de forma pública (consulta - la política de privacidad - para más información) + la normativa de privacidad para más información) display name: 'Nombre en pantalla:' display name description: Tu nombre de usuario público. Puedes cambiarlo más tarde en "preferencias". @@ -2160,14 +2162,16 @@ es: grant: title: Confirmar adjudicación de función heading: Confirmar adjudicación de función - are_you_sure: ¿Seguro que deseas otorgar la función `%{role}' al usuario `%{name}'? + are_you_sure: ¿Confirmas que quieres otorgar la función «%{role}» al usuario + «%{name}»? confirm: Confirmar fail: No pudo otorgarse la función `%{role}' al usuario `%{name}'. Por favor, comprueba que el usuario y la función sean válidos. revoke: title: Confirmar revocación de función heading: Confirmar revocación de función - are_you_sure: ¿Seguro que deseas revocar la función `%{role}' del usuario `%{name}'? + are_you_sure: ¿Confirmas que quieres revocar la función «%{role}» del usuario + «%{name}»? confirm: Confirmar fail: No se pudo revocar la función `%{role}' del usuario `%{name}'. Por favor, comprueba que el usuario y la función sean válidos. @@ -2232,7 +2236,7 @@ es: heading: Revocando el bloqueo sobre %{block_on} por %{block_by} time_future: Este bloqueo finalizará en %{time}. past: Este bloqueo terminó hace %{time} y no puede ser revocado ahora. - confirm: ¿Seguro que deseas revocar este bloqueo? + confirm: ¿Confirmas que quieres revocar este bloqueo? revoke: Revocar flash: Este bloqueo ha sido revocado. period: @@ -2242,7 +2246,7 @@ es: show: Mostrar edit: Editar revoke: Revocar - confirm: ¿Está seguro? + confirm: ¿Lo confirmas? display_name: Usuario bloqueado creator_name: Creador reason: Razón del bloqueo @@ -2277,7 +2281,7 @@ es: show: Mostrar edit: Editar revoke: Revocar - confirm: ¿Está seguro? + confirm: ¿Lo confirmas? reason: 'Razón del bloqueo:' back: Ver todos los bloqueos revoker: 'Revocador:' @@ -2401,6 +2405,7 @@ es: ascend: Ascender engines: graphhopper_bicycle: En bicicleta (GraphHopper) + graphhopper_car: Auto (GraphHopper) graphhopper_foot: A pie (GraphHopper) mapquest_bicycle: En bicicleta (MapQuest) mapquest_car: En coche (MapQuest) @@ -2492,7 +2497,7 @@ es: user: 'Creador:' edit: Editar esta redacción destroy: Eliminar esta redacción - confirm: ¿Estás seguro? + confirm: ¿Lo confirmas? create: flash: Redacción creada. update: diff --git a/config/locales/et.yml b/config/locales/et.yml index ce3983ba8..6277ba47f 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -386,7 +386,6 @@ et: search: title: latlon: Sisemised tulemused - us_postcode: Geocoder.us tulemused uk_postcode: ' NPEMap / FreeThe Postcode tulemused' ca_postcode: Geocoder.CA tulemused @@ -1346,6 +1345,7 @@ et: table: entry: motorway: Kiirtee + main_road: Peatee trunk: Esimese klassi tee primary: Põhimaantee secondary: Tugimaantee @@ -2187,7 +2187,7 @@ et: distance: Vahemaa errors: no_route: Ei suutnud leida teekonda nende kahe koha vahel. - no_place: Vabandust - ei suuda leida sellist kohta. + no_place: Seda kohta kahjuks ei leitud. instructions: unnamed: nimetu time: Kestus @@ -2233,8 +2233,8 @@ et: update: flash: Salvestati muudatused. destroy: - not_empty: Redaktsioon ei ole tühi. Palun eemaldage enne selle hävitamist kõik - versioonid, mis kuuluvad selle redaktsiooni alla. + not_empty: Redaktsioon ei ole tühi. Palun eemalda enne redaktsiooni hävitamist + kõik versioonid, mis selle alla kuuluvad. flash: Redaktsioon hävitatud. error: Viga selle redaktsiooni hävitamisel. ... diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 715eb80b1..45891c424 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -405,7 +405,6 @@ fa: search: title: latlon: نتایج داخلی - us_postcode: نتایج Geocoder.us uk_postcode: نتایج NPEMap / FreeThe Postcode ca_postcode: نتایج Geocoder.CA osm_nominatim: نتایج OpenStreetMap @@ -1393,6 +1392,7 @@ fa: date: تاریخ reply_button: پاسخ unread_button: علامت‌گذاری به عنوان خوانده‌شده + delete_button: حذف back: عقب to: به wrong_user: شما بعنوان `%{user}' وارد سامانه شده‌اید اما پیامی که درخواست خواندنش @@ -1794,6 +1794,9 @@ fa: github: title: ورود با GitHub alt: با یک حساب کاربری در GitHub وارد شوید + wikipedia: + title: ورود با ویکی‌پدیا + alt: ورود با حساب کاربر ویکی‌پدیا yahoo: title: ورود با یاهو alt: ورود با OpenID یاهو @@ -2295,6 +2298,7 @@ fa: header: لایه های نقشه notes: یادداشت های نقشه data: داده های نقشه + gps: پیگیری‌های GPS عمومی overlays: فعال سازی همپوشانی ها برای اشکال زدایی نقشه title: لایه ها copyright: © شرکت کنندگانOpenStreetMap @@ -2332,8 +2336,10 @@ fa: edit_help: نقشه را جابجا کنید و روی مکانی که میخواهید ویرایش کنید بزرگنمایی کنید، سپس اینجا کلیک کنید. directions: + ascend: صعود engines: graphhopper_bicycle: دوچرخه (GraphHopper) + graphhopper_car: ماشین (GraphHopper) graphhopper_foot: پیاده (GraphHopper) mapquest_bicycle: دوچرخه (MapQuest) mapquest_car: اتومبیل (MapQuest) diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 19777376f..d20247085 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -412,7 +412,6 @@ fi: search: title: latlon: Sisäiset tulokset - us_postcode: Tulokset palvelusta Geocoder.us uk_postcode: Tulokset palvelusta NPEMap / FreeThe Postcode ca_postcode: Tulokset palvelusta Geocoder.CA @@ -978,7 +977,7 @@ fi: käyttäminen on ilmaista avoimen lisenssin ansiosta. intro_2_create_account: luomalla ensin käyttäjätunnuksen partners_html: Palvelinta ylläpitää %{ucl}, %{ic} ja %{bytemark} sekä muut %{partners}. - partners_ucl: UCL VR Centre + partners_ucl: UCL partners_ic: Imperial College London partners_bytemark: Bytemark Hosting partners_partners: kumppanimme @@ -1412,6 +1411,7 @@ fi: date: Päiväys reply_button: Vastaa unread_button: Merkitse lukemattomaksi + delete_button: Poista back: Takaisin to: 'Vastaanottaja:' wrong_user: Olet kirjautunut sisään tunnuksella `%{user}' mutta viestiä, jonka @@ -2350,6 +2350,7 @@ fi: directions: engines: graphhopper_bicycle: Pyörällä (GraphHopper) + graphhopper_car: Auto (GraphHopper) graphhopper_foot: Kävellen (GraphHopper) mapquest_bicycle: Pyörällä (MapQuest) mapquest_car: Ajaen (MapQuest) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a32ce85a0..8ef7a5676 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -442,7 +442,6 @@ fr: search: title: latlon: Résultats internes - us_postcode: Résultats depuis Geocoder.us uk_postcode: Résultats depuis NPEMap / FreeThe Postcode ca_postcode: Résultats depuis Geocoder.CA @@ -608,8 +607,8 @@ fr: living_street: Rue en zone de rencontre milestone: Borne kilométrique motorway: Autoroute - motorway_junction: Bretelle d’autoroute / Sortie - motorway_link: Voie autoroutière + motorway_junction: Sortie / Échangeur + motorway_link: Bretelle d’autoroute path: Chemin pedestrian: Rue piétonne platform: Plateforme @@ -711,7 +710,7 @@ fr: horse_riding: Équitation ice_rink: Patinoire marina: Port de plaisance - miniature_golf: Golf miniature + miniature_golf: Mini golf nature_reserve: Réserve naturelle park: Parc pitch: Terrain de sport @@ -853,7 +852,7 @@ fr: beverages: Magasin de boissons bicycle: Magasin de vélos books: Librairie - boutique: Boutique + boutique: Boutique de mode butcher: Boucherie car: Concession automobile car_parts: Pièces d’automobile @@ -894,7 +893,7 @@ fr: jewelry: Bijouterie kiosk: Kiosque laundry: Blanchisserie - mall: Galerie marchande + mall: Centre commercial market: Marché mobile_phone: Boutique de téléphones mobiles motorcycle: Magasin de motos @@ -1463,6 +1462,7 @@ fr: date: Date reply_button: Répondre unread_button: Marque comme non lu + delete_button: Supprimer back: Retour to: À wrong_user: Vous êtes identifié comme « %{user} » mais le message que vous essayez @@ -1497,8 +1497,8 @@ fr: user_page_link: page utilisateur anon_edits_link_text: Trouvez pourquoi ici. flash_player_required: Vous avez besoin d’un lecteur Flash pour utiliser Potlatch, - l’éditeur Flash de OpenStreetMap. Vous pouvez télécharger - Flash Player sur le site d’Adobe. D’autres + l’éditeur Flash d’OpenStreetMap. Vous pouvez télécharger + Flash Player depuis le site d’Adobe. D’autres options sont également disponibles pour modifier OpenStreetMap. potlatch_unsaved_changes: Vous avez des modifications non enregistrées. (Pour enregistrer dans Potlatch, désélectionnez la ligne ou le nœud actuel lors diff --git a/config/locales/fur.yml b/config/locales/fur.yml index ba6225930..66dff0829 100644 --- a/config/locales/fur.yml +++ b/config/locales/fur.yml @@ -354,7 +354,6 @@ fur: search: title: latlon: Risultâts cjolts dal sît interni - us_postcode: Risultâts cjolts di Geocoder.us uk_postcode: Risultâts cjolts di NPEMap / FreeThe Postcode ca_postcode: Risultâts cjolts di Geocoder.CA diff --git a/config/locales/ga.yml b/config/locales/ga.yml index f32a5cb06..a575b3224 100644 --- a/config/locales/ga.yml +++ b/config/locales/ga.yml @@ -382,7 +382,6 @@ ga: search: title: latlon: Torthaí Inmheánach - us_postcode: Torthaí ó Geocoder.us uk_postcode: Torthaí ó NPEMap / FreeThe Postcode ca_postcode: Torthaí ó Geocoder.CA diff --git a/config/locales/gd.yml b/config/locales/gd.yml index 4b25790c2..09c5570f7 100644 --- a/config/locales/gd.yml +++ b/config/locales/gd.yml @@ -402,7 +402,6 @@ gd: search: title: latlon: Toraidhean on taobh a-staigh - us_postcode: Toraidhean o Geocoder.us uk_postcode: Toraidhean o NPEMap / FreeThe Postcode ca_postcode: Toraidhean o Geocoder.CA diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 324b9723a..9003bb3ce 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -384,7 +384,6 @@ gl: search: title: latlon: Resultados internos - us_postcode: Resultados desde Geocoder.us uk_postcode: Resultados desde NPEMap / FreeThe Postcode ca_postcode: Resultados desde Geocoder.CA @@ -951,7 +950,7 @@ gl: intro_2_create_account: Cree unha conta de usuario partners_html: O aloxamento é posible grazas ao %{ucl}, %{ic} e %{bytemark}, e outros %{partners}. - partners_ucl: centro de realidade virtual do UCL + partners_ucl: UCL partners_ic: Imperial College London partners_bytemark: Bytemark Hosting partners_partners: socios @@ -1423,6 +1422,7 @@ gl: date: Data reply_button: Responder unread_button: Marcar como non lida + delete_button: Borrar back: Volver to: Para wrong_user: Accedeu ao sistema como "%{user}", pero a mensaxe que pediu ler @@ -2384,6 +2384,7 @@ gl: ascend: Ascendente engines: graphhopper_bicycle: Bicicleta (GraphHopper) + graphhopper_car: En coche (GraphHopper) graphhopper_foot: A pé (GraphHopper) mapquest_bicycle: Bicicleta (MapQuest) mapquest_car: Coche (MapQuest) diff --git a/config/locales/he.yml b/config/locales/he.yml index 522eaaebc..97b949145 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -9,6 +9,7 @@ # Author: ExampleTomer # Author: GilCahana # Author: Guycn2 +# Author: HarelM # Author: Inkbug # Author: Itay naor # Author: LaG roiL @@ -94,7 +95,7 @@ he: display_name: שם לתצוגה description: תיאור languages: שפות - pass_crypt: ססמה + pass_crypt: סיסמה printable_name: with_name_html: '%{name} (%{id})' editor: @@ -392,7 +393,6 @@ he: search: title: latlon: תוצאות מתוך האתר הזה - us_postcode: תוצאות מאתר Geocoder.us uk_postcode: תוצאות מאתר NPEMap / FreeThe Postcode ca_postcode: תוצאות מאתר Geocoder.CA @@ -1288,17 +1288,17 @@ he: בשרת %{server_url} אל %{new_address}. click_the_link: אם באמת עשית את זה, נא ללחוץ על הקישור להלן כדי לאשר את השינוי. lost_password: - subject: '[אופן סטריט מאפ OpenStreetMap] בקשת איפוס ססמה' + subject: '[אופן סטריט מאפ OpenStreetMap] בקשת איפוס סיסמה' lost_password_plain: greeting: שלום, - hopefully_you: מישהו (אולי את או אתה) ביקש שהססמה המשויכת לחשבון המזוהה עם כתובת - הדוא"ל הזאת באתר openstreetmap.org. - click_the_link: אם אכן עשית את זה, יש ללחוץ על הקישור להלן כדי לאפס את הססמה. + hopefully_you: מישהו (אולי את או אתה) ביקש שהסיסמה המשויכת לחשבון המזוהה עם + כתובת הדוא"ל הזאת באתר openstreetmap.org. + click_the_link: אם אכן עשית זאת, יש ללחוץ על הקישור להלן כדי לאפס את הסיסמה. lost_password_html: greeting: שלום, - hopefully_you: מישהו (בתקווה מדובר בך) ביקש כי הססמה לחשבון המזוהה עם כתובת + hopefully_you: מישהו (בתקווה שמדובר בך) ביקש כי הסיסמה לחשבון המזוהה עם כתובת הדוא״ל הזאת באתר openstreetmap.org תאופס. - click_the_link: אם באמת ביקשת את זה, נא ללחוץ על הקישור להלן כדי לאפס את הססמה. + click_the_link: אם באמת ביקשת את זה, נא ללחוץ על הקישור להלן כדי לאפס את הסיסמה. note_comment_notification: anonymous: משתמש אלמוני greeting: שלום, @@ -1398,6 +1398,7 @@ he: date: תאריך reply_button: להשיב unread_button: לסימון כהודעה שלא נקראה + delete_button: מחיקה back: חזרה to: אל wrong_user: נכנסת בשם „%{user}”, אבל ההודעה שביקשת לקרוא לא נשלחה לאותו המשתמש. @@ -1547,8 +1548,8 @@ he: זמן) create: upload_trace: העלאת מסלול GPS - trace_uploaded: קובץ ה־GPX שלך הועלה ומחכה להכנסה אל מסד הנתונים. זה בדרך יקרה - בתוך חצי שעה ויישלח לך מכתב עם השלמת הפעולה. + trace_uploaded: קובץ ה־GPX שלך הועלה ומחכה להכנסה אל מסד הנתונים. זה בדרך כלל + יקרה בתוך חצי שעה ויישלח לך מכתב עם השלמת הפעולה. edit: title: עריכת מסלול %{name} heading: עריכת המסלול %{name} @@ -1752,13 +1753,13 @@ he: title: כניסה heading: כניסה email or username: 'כתובת דואר אלקטרוני או שם משתמש:' - password: 'ססמה:' + password: 'סיסמה:' openid: '%{logo} OpenID:' remember: לזכור אותי - lost password link: איבדת את הססמה שלך? + lost password link: איבדת את הסיסמה שלך? login_button: כניסה register now: להירשם עכשיו - with username: 'כבר יש לך חשבון OpenStreetMap? נא להיכנס עם שם משתמש וססמה:' + with username: 'כבר יש לך חשבון OpenStreetMap? נא להיכנס עם שם משתמש וסיסמה:' with external: 'לחלופין, השתמשו בצד שלישי כדי להיכנס:' new to osm: הגעת עכשיו ב־OpenStreetMap? to make changes: כדי לשנות את נתוני OpenStreetMap, צריך שיהיה לך חשבון. @@ -1804,22 +1805,22 @@ he: heading: יציאה מ־OpenStreetMap logout_button: יציאה lost_password: - title: הססמה הלכה לאיבוד - heading: שכחת ססמה? + title: הסיסמה הלכה לאיבוד + heading: שכחת סיסמה? email address: 'כתובת דוא״ל:' - new password button: נא לשלוח לי ססמה חדשה + new password button: נא לשלוח לי סיסמה חדשה help_text: נא להזין את כתובת הדוא״ל שהשתמשת בה כדי להירשם. אנו נשלח אליה קישור - שאפשר להשתמש בו כדי לאפס את ססמתך. + שאפשר להשתמש בו כדי לאפס את סיסמתך. notice email on way: אנו מצטערים לשמוע שאיבדת אותה :-( אבל נשלח לדואר האלקטרוני שלך מכתב שבאמצעותו אפשר לאפס אותה. notice email cannot find: סליחה, הכתובת הזאת לא נמצאה. reset_password: - title: איפוס ססמה + title: איפוס סיסמה heading: איפוס הססמה עבור %{user} - password: 'ססמה:' - confirm password: 'אימות הססמה:' + password: 'סיסמה:' + confirm password: 'אימות הסיסמה:' reset: איפוס הססמה - flash changed: ססמתך שונתה. + flash changed: סיסמתך שונתה. flash token bad: לא מצאנו את האסימון ההוא, אולי בדיקת הכתובת תעזור? new: title: הרשמה @@ -1843,11 +1844,11 @@ he: display name description: שם המשתמש שלך, שמוצג בפומבי. אפשר לשנות את זה בהעפות שלך. external auth: 'אימות עם צד שלישי:' - password: 'ססמה:' - confirm password: 'אימות ססמה:' + password: 'סיסמה:' + confirm password: 'אימות סיסמה:' use external auth: 'לחלופין, השתמשו בצד שלישי כדי להיכנס:' - auth no password: עם אימות צד שלישי אין צורך בססמה, אבל כלים נוספים או שרת יכולים - להזדקק לכזה. + auth no password: עם אימות צד שלישי אין צורך בסיסמה, אבל כלים נוספים או שרת + יכולים להזדקק לכזה. continue: הרשמה terms accepted: תודה על קבלת תנאי התרומה החדשים! terms declined: אנחנו מצטערים שהחלטת לא לקבל את תנאי התרומה החדשים. למידע נוסף @@ -2082,7 +2083,7 @@ he: heading: המזהה שלך עדיין אינו משויך לחשבון לחשבון OpenStreetMap. option_1: אם התחלת רק עכשיו עם OpenStreetMap, נא ליצור חשבון חדש באמצעות הטופס להלן. - option_2: אם כבר יש לך חשבון, אפשר להיכנס לחשבון שלך באמצעות שם המשתמש והססמה + option_2: אם כבר יש לך חשבון, אפשר להיכנס לחשבון שלך באמצעות שם המשתמש והסיסמה שלך ואז לשייך את החשבון שלך למזהה מהגדרות המשתמש שלך. user_role: filter: @@ -2318,6 +2319,7 @@ he: ascend: מעלה engines: graphhopper_bicycle: באופניים (GraphHopper) + graphhopper_car: במכונית (GraphHopper) graphhopper_foot: ברגל (GraphHopper) mapquest_bicycle: באופניים (MapQuest) mapquest_car: במכונית (MapQuest) diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 2864ba2f0..636a7cad2 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -1,6 +1,7 @@ # Messages for Croatian (hrvatski) # Exported from translatewiki.net # Export driver: phpyaml +# Author: Bugoslav # Author: Ex13 # Author: Janjko # Author: Macofe @@ -387,7 +388,6 @@ hr: search: title: latlon: Rezultati iz Internal - us_postcode: Rezultati iz Geocoder.us uk_postcode: Rezultati iz NPEMap / FreeThe Postcode ca_postcode: Rezultati iz Geocoder.CA @@ -573,7 +573,9 @@ hr: steps: Stepenice street_lamp: Ulična rasvjeta tertiary: Lokalna cesta + tertiary_link: Lokalna cesta track: Makadam + traffic_signals: Semafori trail: Staza trunk: Cesta rezervirana za motorna vozila trunk_link: Cesta rezrevirana za mot. voz. - prilazna cesta @@ -588,20 +590,25 @@ hr: bunker: Bunker castle: Dvorac church: Crkva + city_gate: Gradska vrata citywalls: Gradske zidine fort: Tvrđava house: Kuća icon: Ikona manor: Zamak - memorial: Spomen dom + memorial: Spomenik mine: Rudnik monument: Spomenik + roman_road: Rimska cesta ruins: Ruševine + stone: Kamen tomb: Grob tower: Toranj wayside_cross: Krajputaš wayside_shrine: Usputno svetište wreck: Olupina + junction: + "yes": Križanje landuse: allotments: Vrtovi basin: Bazen @@ -633,8 +640,11 @@ hr: vineyard: Vinograd leisure: beach_resort: Plaža + club: Klub common: Općinsko zemljište + dog_park: Park za pse fishing: Ribičko područje + fitness_centre: Fitness centar garden: Vrt golf_course: Golf igralište ice_rink: Klizalište @@ -652,9 +662,17 @@ hr: swimming_pool: Bazen track: Staza za trčanje water_park: Vodeni park + man_made: + lighthouse: Svjetionik + pipeline: Cjevovod + tower: Toranj + works: Tvornica + "yes": Ljudska građevina military: barracks: Barake bunker: Bunker + mountain_pass: + "yes": Planinski prijevoj natural: bay: Zaljev beach: Plaža @@ -680,6 +698,8 @@ hr: reef: Greben ridge: Greben rock: Stijena + saddle: Sedlo + sand: Pijesak scree: Šljunak scrub: Guštara spring: Izvor @@ -693,6 +713,7 @@ hr: wood: Šuma office: accountant: Računovođa + administrative: Administracija architect: Arhitekt company: Tvrtka employment_agency: Agencija za zapošljavanje @@ -722,6 +743,7 @@ hr: town: grad unincorporated_area: Slobodna zemlja village: Selo + "yes": Mjesto railway: abandoned: Napuštena pruga construction: Pruga u izgradnji @@ -733,12 +755,15 @@ hr: junction: Željeznički čvor level_crossing: Pružni prijelaz light_rail: Laka željeznica + miniature: Maketa željeznice monorail: Jednotračna pruga narrow_gauge: Uskotračna pruga platform: Željeznička platforma preserved: Sačuvana pruga + proposed: Predložena trasa željeznice spur: Pruga station: Željeznički kolodvor + stop: Željezničko stajalište subway: Podzemna željeznica subway_entrance: Podzemna - ulaz switch: Skretnica @@ -746,12 +771,14 @@ hr: tram_stop: Tramvajska stanica shop: alcohol: Trgovina pićem + antiques: Antikviteti art: Atelje bakery: Pekara beauty: Parfumerija beverages: Trgovina pićem bicycle: Trgovina biciklima books: Knjižara + boutique: Butik butcher: Mesnica car: Autokuća car_parts: Autodijelovi @@ -765,6 +792,7 @@ hr: convenience: Minimarket copyshop: Kopiraona cosmetics: Parfumerija + deli: Delikatesni dućan department_store: Robna kuća discount: Diskont doityourself: Uradi sam @@ -801,6 +829,7 @@ hr: organic: Trgovina zdrave hrane outdoor: Trgovina za slobodno vrijeme pet: Trgovina za kućne ljubimce + pharmacy: Ljekarna photo: Fotograf salon: Salon shoes: Trgovina obućom @@ -808,12 +837,15 @@ hr: sports: Trgovina sportskom opremom stationery: Papirnica supermarket: Supermarket + tailor: Krojač toys: Trgovina igračkama travel_agency: Putnička agencija video: Videoteka wine: Vinoteka + "yes": Prodavaonica tourism: alpine_hut: Alpska kuća + apartment: Apartmani artwork: Umjetničko djelo attraction: Atrakcija bed_and_breakfast: Noćenje i doručak @@ -821,6 +853,7 @@ hr: camp_site: Kamp caravan_site: Kamp-kućice (mjesto) chalet: Planinska kuća + gallery: Galerija guest_house: Apartman hostel: Hostel hotel: Hotel @@ -850,6 +883,14 @@ hr: wadi: Suho korito rijeke waterfall: Vodopad weir: Brana + "yes": Vodotok + admin_levels: + level2: Državna granica + level5: Granica regije + level6: Granica županije + level8: Granica grada + level9: Granica sela + level10: Granica predgrađa description: title: osm_nominatim: Lokacija sa OpenStreetMap @@ -1095,6 +1136,13 @@ hr: title: Dolazna pošta my_inbox: Dolazna pošta outbox: odlazna pošta + messages: Imate %{new_messages} i %{old_messages} + new_messages: + one: '%{count} nova poruka' + other: '%{count} nove poruke' + old_messages: + one: '%{count} stara poruka' + other: '%{count} stare poruke' from: Od subject: Tema date: Datum @@ -1125,6 +1173,9 @@ hr: my_inbox: ' %{inbox_link}' inbox: dolazna pošta outbox: odlazna pošta + messages: + one: Imate %{count} poslanu poruku + other: Imate %{count} poslane poruke to: Za subject: Tema date: Datum @@ -1142,6 +1193,7 @@ hr: date: Datum reply_button: Odgovori unread_button: Označi kao nepročitano + delete_button: Obriši back: Natrag to: Za wrong_user: 'Prijavljeni ste kao: `%{user}'', ali poruka za koju ste zamoljeni @@ -1182,6 +1234,7 @@ hr: SPREMI ako imate taj gumb.) potlatch2_unsaved_changes: Neke promjene nisu spremljene. (Da biste spremili u Potlatch 2, trebali bi kliknuti Spremi.) + id_not_configured: iD nije konfiguriran no_iframe_support: Tvoj preglednik ne podržava HTML iframes, koji su potrebni za ovu značajku. sidebar: @@ -1189,6 +1242,9 @@ hr: close: Zatvori search: search: Traži + get_directions_title: Nađi upute između dvije točke + from: Od + to: Do where_am_i: Gdje sam? where_am_i_title: Opiši trenutnu lokaciju koristeći pretraživač submit_text: Idi @@ -1196,6 +1252,7 @@ hr: table: entry: motorway: Autocesta + main_road: Glavna cesta trunk: Brza cesta primary: Primarna cesta secondary: Sekundarna cesta @@ -1203,6 +1260,9 @@ hr: track: Neasfaltirani put bridleway: Staza za konje cycleway: Biciklistička staza + cycleway_national: Državna biciklistička staza + cycleway_regional: Regionalna biciklistička staza + cycleway_local: Lokalna biciklistička staza footway: Pješačka staza rail: Željeznica subway: Podzemna željeznica @@ -1255,6 +1315,9 @@ hr: private: Privatni pristup destination: Pristup odredištu construction: Ceste u izgradnji + bicycle_shop: Biciklistička prodavaonica + bicycle_parking: Parkiralište za bicikle + toilets: Zahodi richtext_area: edit: Uredi markdown_help: @@ -1477,6 +1540,35 @@ hr: Molimo vas da koristite link u e-pošti potvrde da biste aktivirali svoj račun, ili zatražiti novu e-poštu potvrde . auth failure: Žao mi je, ne mogu prijaviti s ovim detaljima. + openid_logo_alt: Prijavi se sa OpenID-om + auth_providers: + openid: + title: Prijavi se sa OpenID-om + alt: Prijavi se sa URL-om OpenID-a + google: + title: Prijavi se sa Google-om + alt: Prijavi se sa Google-ovim OpenID-om + facebook: + title: Prijavi se sa Facebook-om + alt: Prijavi se sa računom Facebook-a + windowslive: + title: Prijavi se sa Windows Live-om + alt: Prijavi se sa računom Windows Live-a + github: + title: Prijavi se sa Github-om + alt: Prijavi se sa računom Github-a + wikipedia: + title: Prijavi se preko Wikipedije + alt: Prijavi se s Wikipedijinim računom + yahoo: + title: Prijavi se sa Yahoo-om + alt: Prijavi se sa Yahoo-ovim OpenID-om + wordpress: + title: Prijavi se sa Wordpressom + alt: Prijavi se sa Wordpressovim OpenID-om + aol: + title: Prijavi se sa AOL-om + alt: Prijavi se sa AOL-ovim OpenID-om logout: title: Odjava heading: Odjava iz OpenStreetMap @@ -1506,17 +1598,27 @@ hr: contact_webmaster: Molim kontaktirajte webmastera da priredi za stvaranje korisničkog računa - pokušati ćemo se pozabaviti s ovime u najkraćem vremenu. + about: + header: Slobodna i može ju svatko uređivati + html: |- +

      Za razliku od drugih karata, OpenStreetMap su u potpunosti napravili ljudi kao vi, + i slobodno ju svatko može popraviti, osvježiti, skinuti i koristiti.

      +

      Prijavite se i krenite uređivati. Poslat ćemo vam e-mail kako bi potvrdili vaš račun.

      license_agreement: Kada potvrdiÅ¡ svoj račun trebati ćeÅ¡ pristati na uvjete pridonositelja. email address: 'Email:' confirm email address: 'Potvrdi e-mail:' - not displayed publicly: Nije javno prikazano (vidi privacy policy) + not displayed publicly: VaÅ¡a adresa nije javno prikazana, vidi naÅ¡a pravila o privatnosti) display name: 'Korisničko ime:' display name description: Javno prikazano korisničko ime. Možete ga promjeniti i kasnije u postavkama. + external auth: 'Prijavljivanje sa drugog servisa:' password: 'Lozinka:' confirm password: 'Potvrdi zaporku:' + use external auth: Alternativno, koristite drugi servis za prijavljivanje + auth no password: Sa prijavljivanjem sa drugog servisa ne trebate lozinku, ali + drugi alati ili serveri će možda trebati. continue: Otvori račun terms accepted: Hvala za prihvaćanje novih pridonositeljskih uvjeta! terms: @@ -1541,6 +1643,7 @@ hr: heading: Korisnik %{user} ne postoji body: Žao mi je, ne postoji korisnik s imenom %{user}. Molim provjerite ukucano ili je link na koji ste kliknuli neispravan. + deleted: obrisano view: my diary: Moj dnevnik new diary entry: novi unos u dnevnik @@ -1564,6 +1667,8 @@ hr: mapper since: 'Maper od:' ago: prije (%{time_in_words_ago}) ct status: 'Uvjeti doprinositelja:' + ct undecided: Neopredjeljen + ct declined: Odbio ct accepted: Prihvaćeno prije %{ago} latest edit: 'Najnovija izmjena %{ago}:' email address: 'Email adresa:' @@ -1602,6 +1707,7 @@ hr: unhide_user: Otkrij ovog korisnika delete_user: ObriÅ¡i ovog korisnika confirm: Potvrdi + friends_changesets: changesetovi prijatelja popup: your location: VaÅ¡a lokacija nearby mapper: Obližnji maper @@ -1935,6 +2041,30 @@ hr: comment_and_resolve: Komentiraj i razrijeÅ¡i comment: Komentiraj edit_help: Pomakni kartu i približi dio koji želiÅ¡ urediti, zatim klikni ovdje. + directions: + engines: + graphhopper_bicycle: Bicikl (GraphHopper) + graphhopper_car: Automobil (GraphHopper) + graphhopper_foot: PjeÅ¡ke (GraphHopper) + mapquest_bicycle: Bicikl (MapQuest) + mapquest_car: Automobil (MapQuest) + mapquest_foot: PjeÅ¡ke (MapQuest) + osrm_car: Automobil (OSRM) + mapzen_bicycle: Bicikl (Mapzen) + mapzen_car: Automobil (Mapzen) + mapzen_foot: PjeÅ¡ke (Mapzen) + descend: Silazno + directions: Upute + distance: Udaljenost + errors: + no_route: Nismo mogli naći put između ta dva mjesta. + no_place: Žao nam je - nismo mogli naći to mjesto. + instructions: + continue_without_exit: Nastavi na %{name} + slight_right_without_exit: Lagano desno na %{name} + offramp_right_without_exit: Siđi sa autoceste desno na %{name} + onramp_right_without_exit: Skreni desno na autocestu %{name} + endofroad_right_without_exit: Na kraju ceste skreni desno na %{name} redaction: edit: description: Opis diff --git a/config/locales/hsb.yml b/config/locales/hsb.yml index 4fd0ed828..756e2e76c 100644 --- a/config/locales/hsb.yml +++ b/config/locales/hsb.yml @@ -383,7 +383,6 @@ hsb: search: title: latlon: Wuslědki wot Internal - us_postcode: Wuslědki wot Geocoder.us uk_postcode: Wuslědki wot NPEMap / FreeThe Postcode ca_postcode: Wuslědki wot Geocoder.CA diff --git a/config/locales/hu.yml b/config/locales/hu.yml index df42831f7..5ed3a9b82 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -397,7 +397,6 @@ hu: search: title: latlon: Eredmények az Internalról - us_postcode: Eredmények a Geocoder.us-ról uk_postcode: Eredmények a NPEMap / FreeThe Postcode-ról ca_postcode: Eredmények a Geocoder.CA-ről @@ -1415,6 +1414,7 @@ hu: date: Érkezett reply_button: Válasz unread_button: Jelölés olvasatlanként + delete_button: Törlés back: Vissza to: Ide wrong_user: „%{user}” néven jelentkeztél be, de a levelet, amit lekérdeztél @@ -2372,6 +2372,7 @@ hu: ascend: Emelkedés engines: graphhopper_bicycle: Kerékpár (GraphHopper) + graphhopper_car: Autó (GraphHopper) graphhopper_foot: Gyalog (GraphHopper) mapquest_bicycle: Kerékpár (MapQuest) mapquest_car: Autó (MapQuest) @@ -2432,8 +2433,8 @@ hu: error: 'Hiba a %{server} szerverhez való kapcsolódáshoz: %{error}' timeout: Időtúllépés a %{server}szerverhez kapcsolódás során context: - directions_from: Útvonaltervezés innen - directions_to: Útvonaltervezés ide + directions_from: Navigáció innen + directions_to: Navigáció ide add_note: Jegyzet hozzáadása itt show_address: Cím megjelenítése query_features: Funkciók lekérdezése diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 31f96a683..06e576118 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -180,8 +180,8 @@ ia: way: via relation: relation start_rjs: - feature_warning: Le cargamento de %{num_features} elementos pote relentar o - congelar tu navigator. Es tu secur de voler visualisar iste datos? + feature_warning: Le cargamento de %{num_features} objectos pote relentar o congelar + tu navigator. Es tu secur de voler visualisar iste datos? load_data: Cargar datos loading: Cargamento... tag_details: @@ -214,8 +214,8 @@ ia: retro hidden_by: Celate per %{user} %{when} retro query: - title: Cercar objectos proxime - introduction: Clicca sur le carta pro cercar elementos a proximitate. + title: Cercar objectos + introduction: Clicca sur le carta pro cercar objectos a proximitate. nearby: Objectos proxime enclosing: Objectos inglobante changeset: @@ -385,7 +385,6 @@ ia: search: title: latlon: Resultatos interne - us_postcode: Resultatos de Geocoder.us uk_postcode: Resultatos de NPEMap / FreeThe Postcode ca_postcode: Resultatos de Geocoder.CA @@ -1096,11 +1095,11 @@ ia: Ecce un guida curte con le cosas le plus importante a saper. whats_on_the_map: title: Que es sur le carta? - on_html: OpenStreetMap es un loco pro cartographiar cosas real e actual; + on_html: OpenStreetMap es un loco pro cartographar cosas real e actual; illo include milliones de edificios, stratas e altere detalios sur locos. - Tu pote cartographiar qualcunque elemento del mundo real que te interessa. + Tu pote cartographar qualcunque cosa del mundo real que te interessa. off_html: Illo non include datos subjective como punctos de appreciation, - elementos historic o hypothetic. Le datos ab fontes sub copyright es equalmente + objectos historic o hypothetic. Le datos ab fontes sub copyright es equalmente excludite; non copia cosas ab cartas in linea o de papiro sin permission special! basic_terms: title: Vocabulario de base pro le cartographia @@ -1402,6 +1401,7 @@ ia: date: Data reply_button: Responder unread_button: Marcar como non legite + delete_button: Deler back: Retornar to: A wrong_user: Tu es authenticate como "%{user}", ma le message que tu vole leger @@ -2334,8 +2334,8 @@ ia: createnote_disabled_tooltip: Face zoom avante pro adder un nota al carta map_notes_zoom_in_tooltip: Face zoom avante pro vider le notas del carta map_data_zoom_in_tooltip: Face zoom avante pro vider le datos del carta - queryfeature_tooltip: Cercar objectos proxime - queryfeature_disabled_tooltip: Face zoom avante pro cercar objectos a proximitate + queryfeature_tooltip: Cercar objectos + queryfeature_disabled_tooltip: Face zoom avante pro cercar objectos changesets: show: comment: Commento @@ -2364,6 +2364,7 @@ ia: ascend: Ascender engines: graphhopper_bicycle: Bicycletta (GraphHopper) + graphhopper_car: Auto (GraphHopper) graphhopper_foot: Pedestre (GraphHopper) mapquest_bicycle: Bicycletta (MapQuest) mapquest_car: Auto (MapQuest) @@ -2419,7 +2420,7 @@ ia: node: Nodo way: Via relation: Relation - nothing_found: Nulle elemento trovate + nothing_found: Nulle objecto trovate error: 'Error al contactar %{server}: %{error}' timeout: Tempore limite excedite contactante %{server} context: @@ -2427,6 +2428,7 @@ ia: directions_to: Itinerario verso hic add_note: Adder un nota hic show_address: Monstrar adresse + query_features: Cercar objectos centre_map: Centrar le carta hic redaction: edit: diff --git a/config/locales/id.yml b/config/locales/id.yml index aa67456c3..915eeed68 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -3,6 +3,7 @@ # Export driver: phpyaml # Author: Arief # Author: Arifin.wijaya +# Author: Atriwidada # Author: C5st4wr6ch # Author: Dewisulistio # Author: Emirhartato @@ -16,6 +17,7 @@ # Author: JakArtisan # Author: Kenrick95 # Author: Macofe +# Author: Rachmat04 # Author: Relly Komaruzaman # Author: Rizkiahmadz # Author: Vasanthi @@ -403,7 +405,6 @@ id: search: title: latlon: Hasil dari Internal - us_postcode: Hasil dari Geocoder.us uk_postcode: Hasil dari NPEMap / FreeThe Postcode ca_postcode: Hasil dari Geocoder.CA @@ -970,7 +971,7 @@ id: intro_2_create_account: Buat Akun partners_html: Hosting didukung oleh %{ucl}, %{ic} dan %{bytemark} dan %{partners} lainnya. - partners_ucl: Pusat UCL VR + partners_ucl: UCL partners_ic: Imperial College London partners_bytemark: Hosting Bytemark partners_partners: mitra @@ -1045,10 +1046,10 @@ id: Baca lebih lanjut tentang pemakaian data kami, dan cara memberi kami kredit, di halaman lisensi OSMF dan Pertanyaan Legal yang sering diajukan (FAQ) komunitas. more_2_html: |- - Meskipun OpenStreetMap merupakan data yang terbuka, kami tidak dapat menyediakan API peta gratis bagi pengembang (developer) pihak ketiga. - Lihat Kebijakan Penggunaan API, - Kebijakan Penggunaan Tile - dan Kebijakan Penggunaan Nominatim. + Meskipun OpenStreetMap merupakan data yang terbuka, kami tidak dapat menyediakan API peta gratis bagi pihak ketiga. + Lihat Kebijakan Penggunaan API, + Kebijakan Penggunaan Tile + dan Kebijakan Penggunaan Nominatim. contributors_title_html: Kontributor kami contributors_intro_html: 'Kontributor kami terdiri dari ribuan orang. Kami juga memasukkan data dengan lisensi terbuka yang didapat dari badan-badan pemetaan @@ -1253,10 +1254,10 @@ id: partners_title: Rekan notifier: diary_comment_notification: - subject: '[OpenStreetMap] %{user} mengomentari entri catatan harian Anda' + subject: '[OpenStreetMap] %{user} mengomentari sebuah entri catatan harian' hi: Halo %{to_user}, header: '%{from_user} mengomentari entri terbaru dari catatan harian OpenStreetMap - Anda dengan subjek %{subject}:' + dengan subjek %{subject}:' footer: Anda juga dapat membaca komentar pada %{readurl} dan Anda juga dapat berkomentar pada %{commenturl} atau membalas pada %{replyurl} message_notification: @@ -1266,6 +1267,7 @@ id: footer_html: Anda juga dapat membaca pesan di %{readurl} dan membalasnya di %{replyurl} friend_notification: + hi: Halo %{to_user}, subject: '[OpenStreetMap] %{user} menambahkan Anda sebagai teman' had_added_you: '%{user} telah menambahkan Anda sebagai teman pada OpenStreetMap.' see_their_profile: Anda dapat melihat profilnya pada %{userurl}. @@ -1355,6 +1357,7 @@ id: yang Anda komentari. Catatan ini dekat %{place}.' details: Rincian lebih lanjut mengenai catatan dapat ditemukan di %{url}. changeset_comment_notification: + hi: Halo %{to_user}, greeting: Halo, commented: subject_own: '[OpenStreetMap] %{commenter} mengomentari salah satu perubahan @@ -1429,6 +1432,7 @@ id: date: Tanggal reply_button: Balas unread_button: Tandai belum dibaca + delete_button: Hapus back: Kembali to: Kepada wrong_user: Anda login sebagai '%{user}' tetapi pesan yang anda balas tidak @@ -1726,6 +1730,8 @@ id: invalid: Otorisasi token ini tidak berlaku. revoke: flash: Anda telah menolak token untuk %(application} + permissions: + missing: Anda tidak mengizinkan akses aplikasi ke fasilitas ini oauth_clients: new: title: Daftar aplikasi baru @@ -1830,6 +1836,9 @@ id: github: title: Masuk dengan GitHub. alt: Masuk dengan Akun GitHub. + wikipedia: + title: Masuk log dengan Wikipedia + alt: Masuk log dengan akun Wikipedia yahoo: title: Masuk log dengan Yahoo alt: Masuk log dengan Yahoo OpenID @@ -2243,6 +2252,7 @@ id: helper: time_future: Berakhir pada %{time}. until_login: Aktif sampai pengguna melakukan log in. + time_future_and_until_login: Berakhir dalam %{time} dan setelah pengguna masuk. time_past: Berakhir %{time} yang lalu. blocks_on: title: Diblokir pada %{name} @@ -2327,7 +2337,7 @@ id: key: title: Kunci Peta tooltip: Kunci Peta - tooltip_disabled: Kunci Peta tersedia hanya untuk lapisan standar + tooltip_disabled: Legenda tidak tersedia untuk lapisan ini map: zoom: in: Perbesar @@ -2344,6 +2354,7 @@ id: header: Layer Peta notes: Catatan Peta data: Data Peta + gps: Jejak GPS Umum overlays: Mengaktifkan overlay untuk penyelesaian masalah peta title: Lapisan copyright: © Kontributor OpenStreetMap @@ -2382,8 +2393,10 @@ id: edit_help: Memindahkan peta dan memperbesar lokasi yang ingin Anda sunting, kemudian klik di sini. directions: + ascend: Naik engines: graphhopper_bicycle: Sepeda (GraphHopper) + graphhopper_car: Mobil (GraphHopper) graphhopper_foot: Jalan Kaki (GraphHopper) mapquest_bicycle: Sepeda (MapQuest) mapquest_car: Mobil (MapQuest) @@ -2392,6 +2405,7 @@ id: mapzen_bicycle: Sepeda (Mapzen) mapzen_car: Mobil (Mapzen) mapzen_foot: Kaki (Mapzen) + descend: Turun directions: Petunjuk Arah distance: Jarak errors: @@ -2426,6 +2440,11 @@ id: against_oneway_without_exit: Lawan arah pada %{name} end_oneway_without_exit: Akhir dari satu arah pada %{name} roundabout_with_exit: Di bundaran keluar %{exit} menuju %{name} + turn_left_with_exit: Pada bundaran belok kiri ke %{name} + slight_left_with_exit: Pada bundaran belok kiri sedikit ke %{name} + turn_right_with_exit: Pada bundaran belok kanan ke %{name} + slight_right_with_exit: Pada bundaran belok kanan sedikit ke %{name} + continue_with_exit: Pada bundaran lurus saja ke %{name} unnamed: jalan tanpa nama courtesy: Petunjuk arah disediakan oleh %{link} time: Waktu tempuh @@ -2437,8 +2456,12 @@ id: error: 'Kelasahan menghubungi %{server}: %{error}' timeout: Waktu habis menghubungi %{server} context: + directions_from: Petunjuk arah dari sini + directions_to: Petunjuk arah ke sini add_note: Tambahkan sebuah catatan disini show_address: Tampilkan alamat + query_features: Fitur-fitur kueri + centre_map: Pusatkan peta di sini redaction: edit: description: Deskripsi diff --git a/config/locales/is.yml b/config/locales/is.yml index 1cae3f1e8..a0561b28a 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -362,7 +362,6 @@ is: search: title: latlon: Niðurstöður frá Internal - us_postcode: Niðurstöður frá Geocoder.us uk_postcode: Niðurstöður frá NPEMap / FreeThe Postcode ca_postcode: Niðurstöður frá Geocoder.CA diff --git a/config/locales/it.yml b/config/locales/it.yml index 85d3eb40b..6c69fe1bd 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -224,10 +224,10 @@ it: load_data: Carica dati loading: Caricamento in corso... tag_details: - tags: Tag + tags: Etichette wiki_link: - key: La pagina wiki per la descrizione del tag %{key} - tag: La pagina wiki per la descrizione del tag %{key}=%{value} + key: La pagina wiki per la descrizione dell'etichetta %{key} + tag: La pagina wiki per la descrizione dell'etichetta %{key}=%{value} wikidata_link: L'elemento %{page} su Wikidata wikipedia_link: La voce di Wikipedia su %{page} telephone_link: Chiama %{phone_number} @@ -235,9 +235,9 @@ it: title: 'Nota: %{id}' new_note: Nuova nota description: Descrizione - open_title: 'Nota irrisolta: %{note_name}' + open_title: 'Nota irrisolta #%{note_name}' closed_title: 'Nota risolta #%{note_name}' - hidden_title: 'Note nascosta #%{note_name}' + hidden_title: 'Nota nascosta #%{note_name}' open_by: Creato da %{user} %{when} fa open_by_anonymous: Creato da anonimo %{when} fa commented_by: Commento da %{user} %{when} fa @@ -273,7 +273,7 @@ it: list: title: Gruppi di modifiche title_user: Gruppi di modifiche di %{user} - title_friend: Insieme di modifiche dei tuoi amici + title_friend: Gruppi di modifiche dei tuoi amici title_nearby: Gruppi di modifiche da parte di utenti nelle vicinanze empty: Nessun gruppo di modifiche trovato. empty_area: Nessun gruppo di modifiche in quest'area. @@ -421,7 +421,6 @@ it: search: title: latlon: Risultati da Internal - us_postcode: Risultati da Geocoder.us uk_postcode: Risultati da NPEMap / FreeThe Postcode ca_postcode: Risultati da Geocoder.CA @@ -1152,11 +1151,11 @@ it: rules: title: Regole! paragraph_1_html: "OpenStreetMap ha poche regole formali, ma ci aspettiamo che - tutti i partecipanti collaborino\ncon, e comunichino con la comunità. Se stai - considerando qualsiasi attività di editing manuale, sei pregato - di leggere e seguire le indicazioni \nLe - importazioni e \nki.openstreetmap.org/wiki/Automated_Edits_code_of_conduct\">Automatizzato - Modifiche." + tutti i partecipanti collaborino e comunichino con la comunità. Se stai considerando + qualsiasi altra attività oltre all'editing manuale, dovresti prima leggere + le linee guida sulle importazioni + e \nmodifiche + automatiche e seguire le loro indicazioni." questions: title: Domande? paragraph_1_html: |- @@ -1165,9 +1164,9 @@ it: start_mapping: Inizia a mappare add_a_note: title: Non hai tempo per editare? Aggiungi una nota! - paragraph_1_html: Se pensi che ci debba essere una piccola correzione, ma non - hai abbastanza tempo da registrarti e imparare a modificare, puoi aggiungere - semplicemente una nota. + paragraph_1_html: Se vuoi fare solo una piccola correzione, ma non hai abbastanza + tempo per registrarti e imparare come modificare, puoi semplicemente aggiungere + una nota. paragraph_2_html: |- Vai alla mappa e clicca sull'icona della nota: . Questo aggiungerà un marker alla mappa, che potrai muovere trascinandolo. Aggiungi il tuo messaggio, quindi fare clic su Salva e altri Mappers daranno un'occhiata. @@ -1444,6 +1443,7 @@ it: date: Data reply_button: Rispondi unread_button: Segna come non letto + delete_button: Cancella back: Indietro to: A wrong_user: Hai effettuato l'accesso come '%{user}', ma il messaggio che hai @@ -2358,7 +2358,7 @@ it: out: Zoom indietro locate: title: Mostra la mia posizione - popup: Ti trovi a {distanza} {unità} da questo punto + popup: Ti trovi a {distance} {unit} da questo punto base: standard: Standard cycle_map: Mappa ciclabile @@ -2411,6 +2411,7 @@ it: ascend: Salita engines: graphhopper_bicycle: Bicicletta (GraphHopper) + graphhopper_car: Auto (GraphHopper) graphhopper_foot: A piedi (GraphHopper) mapquest_bicycle: Bicicletta (MapQuest) mapquest_car: Auto (MapQuest) diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 6a3119eb3..c398ddd1a 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -19,6 +19,7 @@ # Author: Nyampire # Author: OKANO Takayoshi # Author: Omotecho +# Author: Otokoume # Author: Ruila # Author: Rxy # Author: Schu @@ -394,7 +395,6 @@ ja: search: title: latlon: Internalからの結果 - us_postcode: Geocoder.usからの結果 uk_postcode: NPEMap / FreeThe Postcodeからの結果 ca_postcode: Geocoder.CAからの結果 osm_nominatim: OpenStreetMap @@ -1297,6 +1297,7 @@ ja: date: 日付 reply_button: 返信 unread_button: 未読にする + delete_button: 削除 back: 戻る to: 宛先 wrong_user: あなたは「%{user}」としてログインしていますが、閲覧しようとしたメッセージは、この利用者が送信したものでも、この利用者宛てのものでもありません。メッセージを閲覧するには、正しいユーザーとしてログインしてください。 diff --git a/config/locales/ka.yml b/config/locales/ka.yml index 34ba51a6a..c9d5e07d5 100644 --- a/config/locales/ka.yml +++ b/config/locales/ka.yml @@ -289,7 +289,6 @@ ka: search: title: latlon: შიდა შედეგები - us_postcode: Geocoder.us–ის შედეგები uk_postcode: NPEMap / FreeThe Postcode–ის შედეგები ca_postcode: Geocoder.CA–ს შედეგები diff --git a/config/locales/kab.yml b/config/locales/kab.yml new file mode 100644 index 000000000..4c10058b3 --- /dev/null +++ b/config/locales/kab.yml @@ -0,0 +1,1480 @@ +# Messages for Kabyle (Taqbaylit) +# Exported from translatewiki.net +# Export driver: phpyaml +# Author: Belkacem77 +# Author: Mastanabal +# Author: Mhenni +# Author: Sayem AtVkm +# Author: SlimaneAmiri +--- +kab: + time: + formats: + friendly: '%e %B %Y É£ef %H:%M' + activerecord: + models: + acl: Tabdart n usenqed n inekcam + changeset: Agraw n ibeddilen + changeset_tag: Imyerr n ugraw n ibeddilen + country: Tamurt + diary_comment: Awennit n uÉ£mis + diary_entry: Anekcam n uÉ£mis + friend: Amdakkel + language: Tutlayt + message: Izen + node: Tikerrist + node_tag: Imyerr n tkerrist + notifier: LÉ£u + old_node: Tikerrist taqburt + old_node_tag: Imyerr n tkerrist taqburt + old_relation: AssaÉ£ aqbur + old_relation_member: Amedraw n ussaÉ£ aqbur + old_relation_tag: Tikerrist n ussaÉ£ aqbur + old_way: Abrid aqbur + old_way_node: Tikerrist n ubrid aqbuṛ + old_way_tag: Imyerr n ubrid aqbuṛ + relation: AssaÉ£ + relation_member: Amedraw n ussaÉ£ + relation_tag: Tikerrist n ussaÉ£ + session: TiÉ£imit + trace: Adsil + tracepoint: Taneqqiḍt n udsil + tracetag: Imyerr n udsil + user: Aseqdac + user_preference: Ismenyifen n useqdac + user_token: Tiddest n useqdac + way: Abrid + way_node: Tikerrist n ubrid + way_tag: Imyerr n ubrid + attributes: + diary_comment: + body: Tafekka + diary_entry: + user: Aseqdac + title: Asentel + latitude: Tarrut + longitude: Tazegrart + language: Tutlayt + friend: + user: Aseqdac + friend: Amdakkel + trace: + user: Aseqdac + visible: Uman + name: Isem + size: TeÉ£zi + latitude: Tarrut + longitude: Tazegrart + public: Azayez + description: Aglam + message: + sender: Amazan + title: Asentel + body: Tafekka + recipient: AÉ£erwaḍ + user: + email: Imayl + active: Urmid + display_name: Mefffer isem + description: Aglam + languages: Tutlayin + pass_crypt: Awal uffir + editor: + default: Amezwer (tura %{name}) + potlatch: + name: Potlatch 1 + description: Potlatch 1 (amaẓrag ineṭḍen deg iminig) + id: + name: iD + description: iD (yeddan deg iminig) + potlatch2: + name: Potlatch 2 + description: Potlatch 2 (amaẓrag ineṭḍen deg iminig) + remote: + name: Amaẓrag azÉ£aray + description: Amaẓrag azÉ£aray (JOSM neÉ£ Merkaartor) + browse: + created: Yettwarna + closed: Yemdel + created_html: Yettwarna deg %{time} aya + closed_html: Yettwamdek deg %{time} aya + created_by_html: Yettwarna deg %{time} aya sÉ£ur + %{user} + deleted_by_html: Yettwarna deg %{time} aya sÉ£ur + %{user} + edited_by_html: Yettwabdel deg %{time} aya sÉ£uṛ + %{user} + closed_by_html: Yettwamdel deg %{time} aya sÉ£ur + %{user} + version: Lqem + in_changeset: Agraw n usnifel + anonymous: udrig + no_comment: (ulac awennit) + part_of: D ayla n + download_xml: Sider XML + view_history: Sken amazray + view_details: Wali talqayt + location: 'Adig:' + changeset: + title: 'Agraw n usnifel: %{id}' + belongs_to: Ameskar + node: Tikerras (%{count}) + node_paginated: Tikerras (%{x}-%{y} si %{count}) + way: Iberdan (%{count}) + way_paginated: Iberdan (%{x}-%{y} si %{count}) + relation: AssaÉ£en (%{count}) + relation_paginated: AssaÉ£en (%{x}-%{y} si %{count}) + comment: Iwenniten (%{count}) + hidden_commented_by: Awennit yeffren n %{user} %{when} + aya + commented_by: Awennit n %{user} %{when} aya + changesetxml: XML n ugraw n ibeddilen + osmchangexml: XML osmChange + feed: + title: Agraw n usnifel %{id} + title_comment: Agraw n ubeddel %{id} - %{comment} + join_discussion: Qqen akken ad tedduḍ ar usqerdec + discussion: Asqerdec + node: + title: 'Takerrist: %{name}' + history_title: 'Amazray n tkerrist: %{name}' + way: + title: 'Abrid: %{name}' + history_title: 'Amazray n ubrid: %{name}' + nodes: Tikerras + also_part_of: + one: Aḥric n ubrid %{related_ways} + other: Aḥric n iberdan %{related_ways} + relation: + title: 'AssaÉ£: %{name}' + history_title: 'Amazray n wassaÉ£: %{name}' + members: Imedrawen + relation_member: + entry_role: '%{type} %{name} s %{role}' + type: + node: Tikerrist + way: Abrid + relation: AssaÉ£ + containing_relation: + entry: AssaÉ£ %{relation_name} + entry_role: AssaÉ£ %{relation_name} (am %{relation_role}) + not_found: + sorry: 'Suref-aÉ£, %{type} #%{id} ulac-it.' + type: + node: tikerrist + way: abrid + relation: assaÉ£ + changeset: agraw n usnifel + note: tazmilt + timeout: + sorry: Suref-aÉ£, isefka n wanaw %{type} s usulay %{id} ttwin ddeqs n wakud akken + ad d-uÉ£alen. + type: + node: tikerrist + way: abrid + relation: assaÉ£ + changeset: agraw n usnifel + note: tazmilt + redacted: + redaction: Tuffra %{id} + message_html: Lqem %{version} n %{type} agi ur yezmir ara ad yettwasken acku + yeffer. wali %{redaction_link} i ugar n isallen. + type: + node: tikerrist + way: abrid + relation: assaÉ£ + start_rjs: + feature_warning: Asali n %{num_features} n tÉ£awsiwin yezmer ad yerr iminig-ik + ẓẓay neÉ£ ahat ad t-isewḥel. TebÉ£iḍ ad tsekneḍ isefka-agi? + load_data: Sali-d isefka + loading: Asali... + tag_details: + tags: Imyerren + wiki_link: + key: Aglam n imyerr %{key} É£ef uwiki + tag: Aglam n imyerr %{key}=%{value} É£ef uwiki + wikidata_link: Aferdis %{page} di Wikidata + wikipedia_link: Amagrad %{page}di Wikipedia + telephone_link: Siwel ar %{phone_number} + note: + title: 'Tazmilt: %{id}' + new_note: Tazmilt tamaynut + description: Aglam + open_title: 'Tazmilt ur yefrin ara #%{note_name}' + closed_title: 'Tazmilt ur yefrin ara #%{note_name}' + hidden_title: 'Tazmilt yeffren #%{note_name}' + open_by: Yerna-t %{user} %{when} aya + open_by_anonymous: Yernat useqdac udrig %{when} + aya + commented_by: Awennit sÉ£ur %{user} %{when} aya + commented_by_anonymous: Awennit n useqdac udrig %{when} + aya + closed_by: Yefra-t %{user} %{when} aya + closed_by_anonymous: YEfra-t useqdac udrig %{when} + aya + reopened_by: Irmed-it %{user} %{when} aya + reopened_by_anonymous: Irmed-it useqdac udrig %{when} + aya + hidden_by: Yeffer-it %{user} %{when} aya + query: + title: Tuttriwin É£ef tÉ£awsiwin + introduction: Sit É£ef tkarḍa allen ad tafeḍ tiÉ£awsiwin iqeṛben. + nearby: TiÉ£awsiqin iqeṛben + enclosing: TiÉ£awsiwin timagbarin + changeset: + changeset_paging_nav: + showing_page: Asebter %{page} + next: Ar zdat» + previous: « ar deffir + changeset: + anonymous: Udrig + no_edits: (ulac abeddel) + view_changeset_details: Sken talqayt n ugraw n usnifel + changesets: + id: Asulay + saved_at: Yettwasekles di + user: Aseqdac + comment: Awennit + area: Tamnaḍt + list: + title: Agraw n usnifel + title_user: Igrawen n usnifel sÉ£ur %{user} + title_friend: Igrawen n usnifel n imdukal-ik + title_nearby: Igrawen n usnifel n iseqdacen iqeṛben + empty: Ulac agraw n usnifel yettwafen. + empty_area: Ulac agraw n usnifel yettwafen di temnaḍt-agi. + empty_user: Ulac agraw n usnifel n useqdac-agi. + no_more: Ulac agraw-nniḍen n usnifel yettwafen. + no_more_area: Ulac agraw-nniḍen n usnifel yettwafen di temnaḍt-agi. + no_more_user: Ulac agraw-nniḍen n usnifel n useqdac-agi. + load_more: Sali ugar + timeout: + sorry: Suref-aÉ£, tabdart n igrawen n usnifel i d-sutreḍ tettwai ddeqs n wakud + akkena d d-ali. + rss: + title_all: Asqerdec deg ugraw n usnifel OpenStreetMap + title_particular: Asqerdec deg ugraw n usnifel OpenStreetMap uá¹­á¹­ %{changeset_id} + comment: Awennit amaynut deg ugraw n usnifel uá¹­á¹­ %{changeset_id} par %{author} + commented_at_html: Yettwalqem %{when} aya + commented_at_by_html: Yettwalqem %{when} aya sÉ£ur %{user} + full: Asqerdec ummid + diary_entry: + new: + title: Anekcam amaynut n uÉ£mis + publish_button: SuffeÉ£-d + list: + title: IÉ£misen n useqdac + title_friends: IÉ£misen n imdukal + title_nearby: IÉ£misen n iseqdacen iqeṛben + user_title: AÉ£mis n %{user} + in_language_title: Inekcam n uÉ£mis s %{language} + new: Anekcam amaynut n uÉ£mis + new_title: Aru anekcam amaynut deg uÉ£mis-ik n useqdac + no_entries: Ulac amagrad n uÉ£mis + recent_entries: Imagraden n melmi kan n uÉ£mis + older_entries: Inekcam iqbuṛen + newer_entries: Inekcam n melmi kan + edit: + title: Ẓreg anekcam n uÉ£mis + subject: 'Asentel:' + body: 'Tafekka:' + language: 'Tutlayt:' + location: 'Adig:' + latitude: 'Tarrut:' + longitude: 'Tazegrart:' + use_map_link: seqdec takarḍa + save_button: Sekles + marker_text: Adig n unekcam n uÉ£mis + view: + title: AÉ£mis n %{user} | %{title} + user_title: AÉ£mis n %{user} + leave_a_comment: Eǧǧ-d awennit + login_to_leave_a_comment: '%{login_link} akken ad teǧǧeḍ awennit' + login: Aseqdac + save_button: Sekles + no_such_entry: + title: Ulac ula d yiwen n unekcam n uÉ£mis yettwafen + heading: 'Ula d yiwen n unekcam s usulay: %{id}' + body: Suref-aÉ£, ulac ula d yiwen n unekcam deg uÉ£mis neÉ£ deg uwennit s usulay + %{id}. Senqed tira-ik neÉ£ aseÉ£wen fiÉ£ef i tsiteḍ ma d ameÉ£tu. + diary_entry: + posted_by: Yuzen-it-id %{link_user} af %{created} s %{language_link} + comment_link: Rnu awennit i unekcam-agi + reply_link: Err i unekcam-agi + comment_count: + zero: Ulac awennit + one: '%{count} n uwennit' + other: '%{count} n iwenniten' + edit_link: Ẓreg anekcam-agi + hide_link: Ffer anekcam-agi + confirm: Sentem + diary_comment: + comment_from: Awennit n %{link_user} di %{comment_created_at} + hide_link: Ffer awennit-agi + confirm: Sentem + location: + location: 'Adig:' + view: Sken + edit: Ẓreg + feed: + user: + title: Imagraden n uá¹£mis OpenStreetMap i %{user} + description: Imagraden ineggura n uÉ£mis OpenStreetMap sÉ£uṛ %{user} + language: + title: Imagraden n iÉ£misen OpenStreetMap s %{language_name} + description: Imagraden ineggura n iÉ£misen n iseqdacen OpenStreetMap s %{language_name} + all: + title: Imagraden n iÉ£misen OpenStreetMap + description: Imagraden inegguran n iÉ£misen n iseqdacen OpenStreetMap + comments: + has_commented_on: '%{display_name} yerna awennit ar inekcamen-agi n iÉ£misen' + post: Amagrad + when: Melmi + comment: Awennit + ago: '%{ago} aya' + newer_comments: Iwenniten ineggura + older_comments: Iwenniten iqbuṛen + export: + title: Sifeḍ + start: + area_to_export: Tamnaḍt n usifeḍ + manually_select: Fren s ufus tamnadt-nniḍen + format_to_export: Amasal n usifeḍ + osm_xml_data: Isefka XML OpenStreetMap + map_image: Tugna n tkarḍa (ad tesken akalku n tegnut) + embeddable_html: HTML yettwaslaÉ£en + licence: Turagt + export_details: Isefka n OpenStreetMap ffÉ£en-d ddaw n Turaft + Open Data Commons Open Database (ODbL). + too_large: + advice: 'Ma yella asifed ddaw-a yeÉ£li, seqdec ma ulac aÉ£ilif tiÉ£bula yettwabedren + ddaw-a:' + body: Tamnadt-agi hrawet aá¹­as akken ad tettwasifeḍ ar umasal OpenStreetMap + XML SenÉ£es ma ulac aÉ£ilif temÉ£er neÉ£ fren tamnaḍt meẓẓiyen, neÉ£ seqdec yiwen + seg iÉ£bula-agi i usider n isefka s uqettun. + planet: + title: Amtiweg OSM + description: Ad yenÉ£el si sya ar da lqem n taffa n isefka yemmden n OpenStreetMap + overpass: + title: API Overpass + description: Sider akatar-agi amagbar seg temrayt n taffa n isefka OpenStreetMap + geofabrik: + title: Isidar Geofabrik + description: Ad d-yessuffeÉ£ si sya ar da ileqman n imeẓawen, timura akked + timdinin yettwafernen + metro: + title: AsuffeÉ£ n umiá¹­ru + description: AsuffeÉ£ n temdinin tigejdanin n umadal akked lquṛub-nsent + other: + title: IÉ£bula-nniḍen + description: Ibula-nniḍen yettwabedren deug uwiki OpenStreetMap + options: IÉ£ewwaṛen + format: Amasal + scale: Sellum + max: afellay + image_size: TeÉ£zi n tugna + zoom: SemÉ£eṛ + add_marker: Rnu taṛekkizt É£ef tkarḍa + latitude: 'Tarrut:' + longitude: 'Tazegrart:' + output: TuffÉ£a + paste_html: Senteḍ tangalt HTML deg usmel Web + export_button: Sifeḍ + geocoder: + search: + title: + latlon: Igmaḍ igensanen + uk_postcode: Igmaḍ si NPEMap / FreeThe + Postcode + ca_postcode: Igmaḍ si Geocoder.CA + osm_nominatim: Igmaḍ si OpenStreetMap + Nominatim + geonames: Igmaḍ si GeoNames + osm_nominatim_reverse: Igmaḍ si OpenStreetMap + Nominatim + geonames_reverse: Igmaḍ si GeoNames + search_osm_nominatim: + prefix: + aerialway: + cable_car: Tilifirik + chair_lift: TilisÉ£imt + drag_lift: Tiliski + gondola: TilituzdiÉ£t + station: TaÉ£sert n tilituzdiÉ£t + aeroway: + aerodrome: Anafag + apron: Tamnaḍt n usseÉ£ser + gate: Tabburt + helipad: Anafag n ukuptir + runway: TafuÉ£alt + taxiway: Abrid n tkeṛṛust n unafag + terminal: Anemdu + amenity: + animal_shelter: Aglat n yiÉ£arsiwen + arts_centre: Almus aẓuṛan + atm: Asedgar awurman n yidrimen + bank: Tabanka + bar: Ttberna + bbq: Taseknaft + bench: AÉ£alad + bicycle_parking: AneÉ£sar n iviluten + bicycle_rental: Asekru n iviluten + biergarten: Ttberna di beṛṛa + boat_rental: Asekru n iÉ£erruba + brothel: Axxam n wuqqu + bureau_de_change: Tanarit n ubeddel n yidrimen + bus_station: TaÉ£sert n yisakacen + cafe: Lqehwa + car_rental: Kerru n tkerrust + car_sharing: Beá¹­á¹­u n tkeryas + car_wash: Tarda n tkeryas + casino: Akazinu + charging_station: taÉ£sert n uɛemmeṛ + childcare: Aqareɛ n warrac + cinema: Sinima + clinic: Taklinit + clock: Tamrilt + college: AÉ£erbaz + community_centre: Taxxamt tagtazalt + courthouse: AneÉ£ n teÉ£demt + crematorium: TanerÉ£ut + dentist: Amejjay n tuÉ£mas + doctors: Imejjayen + dormitory: Anaḍḍas + drinking_water: Aman n tissit + driving_school: AÉ£erbaz n uselmed n tenheṛt + embassy: Tamahelt + emergency_phone: TiliÉ£ri n utrab + fast_food: Učči arurad + ferry_terminal: Anemdu n ufirri + fire_hydrant: Amsexsay n tmes + fire_station: Taqcelt n isexsayen + food_court: Tamnaḍt n wučči + fountain: Tala + fuel: AserÉ£u + gambling: Uraren yidrimen + grave_yard: Tajebbant + gym: Fitness / tajimnastikt + health_centre: Almus n tdawsa + hospital: Sbiá¹­ar + hunting_stand: Tanefsart n uselfeÉ£ + ice_cream: Tamagrist + kindergarten: Tibḥirt n warrac + library: Tanedlist + market: Alzuz + marketplace: Ssuq + monastery: Amunastiṛ + motorcycle_parking: AneÉ£sar n imuá¹­uten + nightclub: Tazeqqa n yiḍ + nursery: Tanectalt + nursing_home: Axxam n tastaÉ£t s udawi + office: Tanarit + parking: AneÉ£sar + parking_entrance: Tabburt n uneÉ£sar + pharmacy: Tansafart + place_of_worship: Amḍiq n weɛbad + police: Tamsulta + post_box: Tanaka n tebṛatin + post_office: Tanarit n lpusá¹­a + preschool: AÉ£erbaz uzwir + prison: Lḥebs + pub: Ttberna + public_building: AzadaÉ£ azayez + reception_area: Tamnaḍt n usiweḍ + recycling: Point de wallus n usseqdec + restaurant: Asečču + retirement_home: Axxam n testaÉ£t + sauna: Sauna + school: AÉ£erbaz + shelter: Aglat + shop: Taḥanut + shower: Tasnuceft + social_centre: Almus amettan + social_club: Aqusis amettan + social_facility: Ameẓlu amettan + studio: Astudyu + swimming_pool: Tanerdabt + taxi: Aá¹­aksi + telephone: Tilifun azayez + theatre: Amezgun + toilets: Ibduzen + townhall: Asensu n temdint/taÉ£iwant + university: Tasdawit + vending_machine: Asedgar awurman + veterinary: Tafettakt tabiḍart + village_hall: Tazeqqa taÉ£iwant + waste_disposal: Affas n yiḍuman + youth_centre: Axxam n yilemẓiyen + boundary: + census: Talast taddadant + bridge: + swing: Tillegwit yeddawaren + "yes": Tiqená¹­ert + building: + "yes": Akerrus + craft: + carpenter: Amekras + electrician: Amesliktri + gardener: Abeḥḥar + painter: Abeyyaá¹­ + photographer: Asewlaf + plumber: Amsaldun + shoemaker: Axerraz + tailor: Axeggaḍ + "yes": Taḥanutt n Tinḍi + highway: + bridleway: AÉ£aras n yimnayen + footway: AÉ£aras n uḍar + path: AÉ£aras + pedestrian: AÉ£lad n uḍar + platform: TiÉ£erÉ£ert + primary: Abrid agejdan + primary_link: Abrid agejdan + raceway: Amnenniḍ + road: Abrid + secondary: Abrid asnawan + secondary_link: Abrid asnawan + service: Abrid n umeẓlu + speed_camera: Aṛadaṛ n tazzla + steps: Sellum + street_lamp: Tasafut n ubrid + track: Abrid + "yes": Abrid + historic: + archaeological_site: Adig Asenzikan + battlefield: Amraḥ n Tamiwta + boundary_stone: Aẓru n talast + building: AzadaÉ£ amazray + castle: TiÉ£remt + church: Taglizt + city_gate: Tabburt n temdint + citywalls: IÉ£raben n temdint + house: Axxam + icon: Tignit + stone: Ablaḍ + landuse: + farm: Tibḥirt + farmland: Akal n tkerrazt + forest: Tiẓgi + leisure: + stadium: Annar + natural: + beach: Taftist + forest: Tiẓgi + hill: Awrir + island: Tigzirt + land: Akal + marsh: Alma + mud: Ixmiṛ + peak: Taqacuct + rock: Aẓru + sand: Ijdi + stone: Ablaḍ + tree: Aseklu + valley: Talat + water: Aman + wood: AmadeÉ£ + office: + accountant: Amessiḍan + administrative: Tadbelt + architect: Amasgad + company: Taṛmist + employment_agency: Tanegga n uxeddim + government: Tadbelt tazayezt + insurance: Tanegga n usenkid + lawyer: Abugaá¹­u + "yes": Tanarit + place: + allotments: Talmat n twacult + block: Iḥder + airport: Anafag + city: TiÉ£remt + country: Tamurt + county: Tamurt + farm: Tibḥirt + hamlet: Aḥriq + house: Axxam + houses: Ixxamen + island: Tigzirt + islet: Tigzirt meẓẓiyen + isolated_dwelling: Axxam awḥid + locality: Amḍiq + municipality: TaÉ£iwant + neighbourhood: Agmam + postcode: Tangalt n lpusá¹­a + region: Tamnaḍt + sea: Ilel + state: AÉ£ir + town: tiÉ£remt + village: Taddart + "yes": Amḍiq + shop: + bicycle: Taḥanutt n iviluten + books: Tahanutt n yidlisen + boutique: Tahanutt n umaynut + butcher: Agezzar + car: Tahanutt n tkeryas + car_parts: Ticeqqufin n ubeddel n tkeryas + tourism: + hostel: Azebriz + hotel: Asensu + information: TalÉ£ut + museum: Asalay + waterway: + river: Asif + stream: IÉ£zeṛ + wadi: Asif + waterfall: Acercuṛ n waman + weir: Uggug + "yes": Targa n waman + admin_levels: + level2: Talast n tmurt + level4: Talast n waÉ£irneÉ£ tawilayt + level5: Talast n temnaḍt + level6: Talast n waÉ£ir + level8: Talast n temdint + level9: Talast n taddart + level10: Talast n ugmama + description: + title: + osm_nominatim: Asideg si OpenStreetMap + Nominatim + geonames: Adig si GeoNames + types: + cities: Timdinin + towns: Tuddar + places: Idigen + results: + no_results: Ulac igmaḍ + more_results: Ugar n igmaḍ + layouts: + logo: + alt_text: Alugu n OpenStreetMap + home: Duu ar uxxam-ik + logout: FfeÉ£ + log_in: Qqen + log_in_tooltip: Qqen s umiḍan yellan + sign_up: Jerred + start_mapping: Bdu asgertel + sign_up_tooltip: Rnu amiḍan n teẓrigt + edit: Ẓreg + history: Amazray + export: Sifeḍ + data: Isefka + export_data: Sifeḍ isefka + gps_traces: Lǧerrat GPS + gps_traces_tooltip: Sefrek lǧerrat GPS + user_diaries: IÉ£misen n iseqdacen + user_diaries_tooltip: Sken iÉ£misen n iseqdacen + edit_with: Ẓreg s %{editor} + tag_line: Takarḍa n uwiki ilelli n umaḍal + intro_header: Aná¹£uf ar OpenStreetMap! + intro_text: OpenStreetMap d takarḍa n umadal, rnna-tt yemdanen am kečč d tilellit + i useqdec ddaw n turagt tilellit. + intro_2_create_account: Rnu amiḍan n useqdac + partners_html: TanezduÉ£t tmudd-itt %{ucl}, %{ic}, %{bytemark} d %{partners} nniḍen. + partners_ucl: UCL + partners_partners: imendiden + osm_offline: Taffa n isefka n OpenStreetMap ur teqqin ara yakan tura imi aseǧǧem + ilaqen yettwaselkam akken ad teddu akken iwata. + osm_read_only: Taffa n isefka n OpenStreetMap tella deg uskar n tÉ£uri kan akka + tura, imi aseǧǧem ilaqen yettwaselkam akken ad teddu akken iwata. + donate: Mudd afus i OpenStreetMap s %{link}i usali n uswir n warrum-is. + help: Tallelt + about: Ɣef + copyright: Izerfan n umeskar + community: Tamezdagnut + community_blogs: Iblugen n tmezdagnut + community_blogs_title: Iblugen n iɛeggalen n tmezdagnut OpenStreetMap + foundation: Tasbeddit + foundation_title: Tasbeddit OpenStreetMap + make_a_donation: + title: Mudd afus i OpenStreetMap s tewsa n yidirem + text: Mudd tawsa + learn_more: Issin ugar + more: Ugar + license_page: + foreign: + title: Ɣef tsuqilt-agi + english_link: Aneá¹£li s teglizit + native: + title: Ɣef usebter-agi + native_link: Tasuqilt s teqbaylit + mapping_link: Bdu attekki + legal_babble: + title_html: Izerfan n umeskar d turagt + intro_1_html: |- + OpenStreetMap d tagrumma n isefka yeldin, yellan ddaw n turagt Open Data Commons Open Database License (ODbL). + credit_title_html: Amek ara ternuḍ asmad i OpenStreetMap + attribution_example: + alt: AmedÉ£a É£ef wamek ara tettekkiḍ di OpenStreetMap s usebter web + title: Amedya n uttekki + more_title_html: Akken ad tafeḍ ugar n telÉ£ut + contributors_title_html: Iwiziwen-nneÉ£ + contributors_at_html: 'Utric : tegber isefka É£ef Tamdint + n Viyan (ddaw n turagt CC + BY), tamnaḍt + n Vorarlberg akked temnadt n Tyrol (ddaw n turagt CC + BY AT avec amendements).' + contributors_ca_html: 'Canada : yegber isefka n GeoBase®, + GeoGratis (© Agezdu n tiÉ£bula n ugama n Kanada), CanVec + (© Agezdu n tiqbula n ugama n Kanada) et StatCan (Agezdu n tirakalt, + Tidaddanin n Kanada).' + contributors_nl_html: 'Huland : yegber isefka © AND, 2007 (www.and.com).' + welcome_page: + title: Aná¹£uf! + whats_on_the_map: + title: Ayen yellan di tkarḍa + rules: + title: Ilugan! + questions: + title: Asteqsi? + paragraph_1_html: |- + OpenStreetMap tsumur ddeqs n tiÉ£bula ara t-issineḍ ad tesxedmeḍ deg usenfaṛ, akken ad testeqsiḍ neÉ£ ad t-muddeḍ tiririt, udiÉ£ ad tmeslayeḍ neÉ£ ad teÉ£reḍ tasemlit É£ef isental n tira n tkarḍiwin d iseqdacen nniḍen. + Wali afus dagi. + fixthemap: + how_to_help: + title: Amek ara d-muddeḍ afus + join_the_community: + title: Ddu ar tmezdagnut + other_concerns: + title: Uguren-nniḍen + help_page: + title: Awi tallelt + introduction: OpenStreetMap tsumur ddeqs n tiÉ£bula ara t-issineḍ ad tesxedmeḍ + deg usenfaṛ, akken ad testeqsiḍ neÉ£ ad t-muddeḍ tiririt, udiÉ£ ad tmeslayeḍ neÉ£ + ad teÉ£reḍ tasemlit É£ef isental n tira n tkarḍiwin d iseqdacen nniḍen. + welcome: + url: /welcome + title: AnÉ£uf ar OSM + description: Bdu s uminir-agi arurad yettmeslayen É£ef udasil n OpenStreetMap. + beginners_guide: + url: http://wiki.openstreetmap.org/wiki/Beginners%27_guide + title: Amnir n ulemad + description: Aminir i yinelmaden imaynuten i t-xeddem tmezdagnut. + help: + url: https://help.openstreetmap.org/ + title: help.openstreetmap.org + description: Steqsi neÉ£ nadi tiririyin deg usmel akked isteqsiyen n OSM. + mailing_lists: + title: Tabraá¹­á¹­ n tnezwit + forums: + title: Inmagaren + irc: + title: IRC + switch2osm: + title: switch2osm + wiki: + url: http://wiki.openstreetmap.org/ + title: wiki.openstreetmap.org + about_page: + next: Ar zdat + copyright_html: ©imttekkiyen
      n OpenStreetMap + open_data_title: Isefka ilelliyen + legal_title: Asaḍuf + partners_title: Imendiden + notifier: + diary_comment_notification: + subject: '[OpenStreetMap] %{user} yuzen-d awennit ar umagrad n uÉ£mis' + hi: Azzul %{to_user}, + header: '%{from_user} yuzen-ad awennit ar umagrad n uÉ£mis OpenStreetMap s usentel + %{subject} :' + message_notification: + hi: Azul %{to_user}, + header: '%{from_user} yuzen-ak-d izen si OpenStreetMap s usentel %{subject} :' + footer_html: Tzemreḍ daÉ£en ad teÉ£reḍ izen di %{readurl} sakin ad tizmireḍ ad + terreḍ i %{replyurl} + friend_notification: + hi: Azul %{to_user}, + subject: '[OpenStreetMap] %{user} yerna-k d amdakkel' + had_added_you: '%{user} yerna-k d amdakkel di OpenStreetMap.' + see_their_profile: 'Tzemred ad twaliḍ amaÉ£nu-is dagi : %{userurl}.' + befriend_them: 'Tzemred daÉ£ed ad tt-rnuḍ-t d amdakkel dagi : %{befriendurl}.' + gpx_notification: + greeting: Azul, + your_gpx_file: Ittemcabi ar ufayli-ik GPX + with_description: s uglam + and_the_tags: 'akked wawalen-agi n tsura:' + and_no_tags: s war awalen n tsura + failure: + subject: '[OpenStreetMap] Akter GPX ur yeddi ara' + failed_to_import: 'ur d-yettwakter ara. Hatta tuccḍa:' + more_info_1: Ugar n telÉ£ut É£ef tuccḍiwin n ukter GPX akked wamek ur ḍerrunt + ara + more_info_2: 'zemren ad ttwafen di:' + success: + subject: '[OpenStreetMap] Akter GPX yedda' + loaded_successfully: yuli-d akken iwata s %{trace_points} n %{possible_points} + n tneqqiḍin izemren ad ilint. + signup_confirm: + subject: '[OpenStreetMap] Aná¹£uf ar OpenStreetMap' + greeting: Azul din! + created: Yella win (nessaram d kečč) yernan amiḍan É£ef %{site_url}. + email_confirm: + subject: '[OpenStreetMap] Sentem tansa-ik imayl' + email_confirm_plain: + greeting: Azul, + email_confirm_html: + greeting: Azul, + lost_password: + subject: '[OpenStreetMap] Asuter n tulsa n uwennez n wawal uffir' + lost_password_plain: + greeting: Azul, + click_the_link: Ma d kečč, sit É£ef useÉ£wen akken ad talseḍ awennez n wawal uffir. + lost_password_html: + greeting: Azul, + note_comment_notification: + anonymous: Aseqdac udrig + greeting: Azul, + commented: + subject_own: '[OpenStreetMap] %{commenter} yerna awennit ar yiwet si tezmilin-ik' + subject_other: '[OpenStreetMap] %{commenter} yerna awennit ar yiwet n tezmilt + anida telliḍ' + your_note: '%{commenter} yerna awennit É£ef yiwet si tezmilin-ik n tkarḍa rrif + n %{place}.' + commented_note: '%{commenter} yerna awennit É£ef yiwet n tezmilt n tkarḍa anida + terniḍ awennit. Tazmilt teqṛeb ar %{place}.' + closed: + subject_own: '[OpenStreetMap] %{commenter} yefra yiwet si tezmilin-ik' + subject_other: '[OpenStreetMap] %{commenter} yefra yiwet n tezmilt anida telliḍ' + your_note: '%{commenter} yefra yiwet si tezmilin-ik n tkarḍa rrif n %{place}.' + commented_note: '%{commenter} yefra yiwet n tezmilt n tkarḍa anida terniḍ + awennit. Tazmilt teqṛeb ar %{place}.' + reopened: + subject_own: '[OpenStreetMap] %{commenter} yermed yiwet si tezmilin-ik' + subject_other: '[OpenStreetMap] %{commenter} yermed yiwet n tezmilt anida + telliḍ' + your_note: '%{commenter} yermed yiwet si tezmilin-ik n tkarḍa rrif n %{place}.' + commented_note: '%{commenter} yermed yiwet n tezmilt n tkarḍa anida terniḍ + awennit. Tazmilt teqṛeb ar %{place}.' + details: Ugar n telÉ£ut É£ef yezmilt ad tettwaf di %{url} + changeset_comment_notification: + hi: Azul %{to_user}, + greeting: Azul, + commented: + subject_own: '[OpenStreetMap] %{commenter} yerna awennit ar yiwet si tezmilin-ik + n tagrumma n usnifel' + subject_other: '[OpenStreetMap] %{commenter} yerna awennit ar yiwet n tagrumma + n usnifel anida telliḍ' + your_changeset: '%{commenter} yerna awennit É£ef yiet si tegrummiwin-ik n usenifel + yettwarnan di %{time}' + partial_changeset_with_comment: s uwennit '%{changeset_comment}' + partial_changeset_without_comment: S war awennit + message: + inbox: + title: Tanaka n urmas + my_inbox: Tanaka-iw n urmas + outbox: tanaka n tuzna + messages: Ɣur-k %{new_messages} akked %{old_messages} + from: Seg + subject: Asentel + date: Azemz + message_summary: + unread_button: Creḍ ur yettwaÉ£ra ara + read_button: Creḍ yettwaÉ£ra + reply_button: Err + delete_button: Kkes + new: + title: Azen izen + subject: Asentel + body: Tafekka + send_button: Azen + message_sent: Izen yettwazen + no_such_message: + title: Ulac izen + heading: Ulac izen + body: Suref-aÉ£, ulac izen s usulay-agi. + outbox: + title: Tanaka n tuzna + my_inbox: '%{inbox_link}-iw' + inbox: tanaka n urmas + outbox: tanaka n tuzna + to: I + subject: Asentel + date: Azemz + read: + title: Ɣeṛ izen + from: Seg + subject: Asentel + date: Azemz + reply_button: Err + unread_button: Creḍ yettwaÉ£ra + delete_button: Kkes + back: UÉ£al + to: I + sent_message_summary: + delete_button: Kkes + mark: + as_read: Izen yettwacred yettwaÉ£ra + as_unread: Izen yettwacred ur yettwaÉ£ra ara + delete: + deleted: Izen yettwakkes + site: + index: + permalink: AseÉ£wen yezgan + shortlink: AseÉ£wen awezlan + createnote: Rnu tazmilt + edit: + user_page_link: asebter n useqdac + sidebar: + search_results: Igmad n unadi + close: Mdel + search: + search: Nadi + get_directions: Awi iwellihen + from: Seg + to: I + where_am_i: Anida lliÉ£? + submit_text: Ddu + key: + table: + entry: + school: + - AÉ£erbaz + - Tasdawit + richtext_area: + edit: Ẓreg + markdown_help: + title_html: Yettwasleḍ s Markdown + headings: Izwal + heading: Azwel + subheading: Azwel asnawan + first: Aferids amezwaru + second: Aferdis wis sin + link: AseÉ£wen + text: Aḍris + image: Tugna + alt: Aḍris-nniḍen + url: Tansa URL + trace: + edit: + title: Ẓreg lǧeṛṛa %{name} + filename: 'Isem n ufaylu:' + download: sider + uploaded_at: 'Yuli:' + points: 'Tineqqiḍin:' + map: takarḍa + edit: ẓreg + owner: 'Bab:' + description: 'Aglam:' + tags: 'Ticraḍ:' + trace_form: + description: 'Aglam:' + tags: 'Ticraḍ:' + upload_button: Sali + help: Tallelt + trace_header: + upload_trace: Azen lǧerra + see_all_traces: Wali akk lǧerrat + see_your_traces: Wali lǧerrat-ik + trace_optionals: + tags: Ticraḍ + view: + pending: YETTRAǦU + filename: 'Isem n ufaylu :' + download: sider + uploaded: 'Yuli:' + points: 'Tineqqiḍin:' + map: takarḍa + edit: ẓreg + owner: 'Bab:' + description: 'Aglam:' + tags: 'Ticraḍ:' + none: Ulac + edit_track: Ẓreg lǧerra-agi + delete_track: Kkes lǧerra-agi + trace_not_found: Ulac lǧeṛṛa! + trace_paging_nav: + showing_page: Asebter %{page} + newer: LÉ£errat timaynutin + trace: + pending: YETTRAǦU + count_points: '%{count} n tneqqiḍin' + ago: '%{time_in_words_ago} aya' + more: ugar + trace_details: Sken talqayt n lǧerra + view_map: Sken takarḍa + edit: ẓreg + edit_map: Ẓreg takarḍa + public: AZAYEZ + private: USLIG + by: sÉ£uṛ + in: di + map: takarḍa + list: + public_traces: Lǧerrat GPS tizuyaz + your_traces: Lǧerrat-ik GPS + public_traces_from: Lǧerrat tizuyaz tizuyza n %{user} + description: Snirem lǧ€rrat GPS tineggura i yilin + tagged_with: yettwaṛekkez s %{tags} + empty_html: Ulac acu yella dagi. Sali lǧeṛṛa tamaynut + neÉ£ issin ugar É£ef lǧerra GPR, Wali asebter + awiki. + delete: + scheduled_for_deletion: TafuÉ£alt yettwaheggan i tukksa + make_public: + made_public: Lǧerra GPS yuÉ£alen d tazayezt + offline_warning: + message: Anagraw n tuzna n ifuyla GPX ulac-it tura + offline: + heading: Asekles GPX n war tuqqna + message: Anagraw n usekles d tuzna n ifuyla GPX ulac-it tura. + georss: + title: Lǧerrat GPS n OpenStreetMap + description: + description_with_count: + one: Afaylu GPX s %{count} n tneqqiḍt n %{user} + other: Afaylu GPX s %{count} n tneqqiḍin n %{user} + description_without_count: Afaylu GPX n %{user} + application: + require_cookies: + cookies_needed: Yettban d akken inagan n tuqqna nsan É£ef iminig-ik. Rmed-iten + send ad tkemmleḍ. + setup_user_auth: + blocked_zero_hour: Ɣur-k izen utrib É£ef usmel Web OpenStreetMap. Yessef ad t-É£reḍ-t + send ad tizmireḍ ad teskelseḍ asnifel-ik. + blocked: Anekcum-ik API yewḥel. Qqen ar ugrudem Web i ugar n isallen. + oauth: + oauthorize: + title: Sireg anekcum ar umiḍan-ik + allow_to: 'Sireg asnas amsaÉ£ i:' + allow_read_prefs: É£eṛ ismenyifen-ik n useqdac. + allow_write_prefs: Ẓreg ismenyifen-ik n useqdac. + allow_write_diary: rnu inekcam deg uÉ£mis, iwenniten akked imdukkal. + allow_write_api: snifel takarḍa + allow_read_gpx: É£eṛ lǧerrat-ik GPS usligen. + allow_write_gpx: azen lǧerrat GPS + allow_write_notes: snifel tizmilin. + grant_access: Mudd tasiregt + oauthorize_success: + title: Asuter n tsiregt tettwaqbel + allowed: Yessefk ad tmuddeḍ tasiregt ar umiḍan-ik i usnas %{app_name}. + verification: Asenqed n tengalt d %{code}. + oauthorize_failure: + title: Asuter n tsiregt ur yeddi ara + denied: Tugwiḍ tasiregt n unekcu ar umiḍan-ik i usnas %{app_name}. + invalid: Ajiá¹­un n tsiregt mačči d ameÉ£tu. + revoke: + flash: Teḥwiḍ ajiá¹­un i %{application} + permissions: + missing: Ur teǧǧiḍ ara asnas akken ad yeqqen ar usebdded-agi + oauth_clients: + new: + title: Sekles asnas amaynut + submit: Sekles + edit: + title: Ẓreg asnas-ik + submit: Ẓreg + show: + title: Talqayt OAuth i %{app_name} + key: 'Tasarutt n useqdac:' + secret: 'Tabadnit n useqdac:' + url: 'Tansa n ujiá¹­un n tuttra:' + access_url: 'Tansa n ujiá¹­un n unelcum:' + authorize_url: 'Tansa URL n tsiregt:' + support_notice: Nsefrak izmulen HMAC-SHA1 (yelha) akked RSA-SHA1 + edit: Ẓreg talqayt + delete: Kkes amsaÉ£ + confirm: TebÉ£iḍ? + requests: 'Asuter n tsirag-agi i useqdac:' + allow_read_prefs: É£eṛ ismenyifen n useqdac. + allow_write_prefs: snifel ismenyifen n useqdac. + allow_write_diary: rnu inekcam deg uÉ£mis, iwenniten akked imdukkal. + allow_write_api: snifel takarḍa. + allow_read_gpx: É£eṛ lǧerrat GPS usligen. + allow_write_gpx: azen lǧerrat GPS. + allow_write_notes: snifel tizmilin. + index: + title: Talqayt-iw OAuth + my_tokens: Isnasen-iw yettwaskelsen + application: Isem n usnas + issued_at: YeffeÉ£-d di + revoke: Ḥwi! + my_apps: Isnasen-iw imsaÉ£en + register_new: Sekles asnas-il + form: + name: Isem + required: Ilaq + url: Tansa URL tagejdant n usnas + callback_url: Tansa URL n usmekti + support_url: Tansa URL n tallelt + allow_read_prefs: É£eṛ ismenyifen n useqdac. + allow_write_prefs: snifel ismenyifen n useqdac. + allow_write_api: snifel takarḍa + allow_read_gpx: É£eṛ lǧerrat GPS usligen. + allow_write_gpx: azen lǧerrat GPS. + allow_write_notes: snifel tizmilin. + user: + login: + title: Qqen + heading: Qqen + email or username: 'Tansa imayl neÉ£ isem n useqdac:' + password: 'Awal uffir:' + openid: '%{logo} OpenID:' + remember: Cfu fell-i + lost password link: Tweddreḍ awal-ik uffir? + login_button: Qqen + register now: Jerred tura + new to osm: D amaynut ar OpenStreetMap? + no account: Ur tesɛiḍ ara amiḍan? + openid_logo_alt: Qqen s OpenID + auth_providers: + openid: + title: Qqen s OpenID + alt: Qqen s tensa URL OpenID + google: + title: Qqen s Google + alt: Qqen s Google OpenID + facebook: + title: Qqen s Facebook + alt: Qqen s umidan Facebook + windowslive: + title: Qqen s Windows Live + alt: Qqen s umiḍan Windows Live + github: + title: Qqen s GitHub + alt: Qqen s umiḍan GitHub + wikipedia: + title: Qqen s Wikipedia + alt: qqes s umiḍan Wikipedia + yahoo: + title: Qqen s Yahoo + alt: Qqen s Yahoo OpenID + wordpress: + title: Qqen s Wordpress + alt: Qqen s OpenID + aol: + title: Qqen s AOL + alt: Qqen s AOL OpenID + logout: + title: TuffÉ£a + heading: TuffÉ£a si OpenStreetMap + logout_button: TuffÉ£a + lost_password: + title: Awal uffir iṛuḥ + heading: Tettuḍ awal uffir? + email address: 'Tansa imayl:' + new password button: Ales awennez n wawal uffir + reset_password: + title: Ales awennez n wawal uffir + heading: Ales awennez n wawal uffir i %{user} + password: 'Awal uffir:' + confirm password: Sentem awal uffir + reset: Ales awennez n wawal uffir + flash changed: Awal-ik uffir ibeddel. + flash token bad: Ajiá¹­un-agi ulac-it, ahat tuccḍa di tansa URL? + new: + title: Jerred + email address: 'Tansa imayl:' + confirm email address: 'Sentem tansa n e-mail:' + password: 'Awal uffir:' + confirm password: 'Sentem awal uffir:' + continue: Jerred + terms: + title: Tiwtilin n iwiziw + heading: Tiwtilin n iwiziw + consider_pd_why: d acu-t wa? + agree: QqebleÉ£ + decline: Agwi + legale_select: 'Tamurt n tnezduÉ£t:' + legale_names: + france: Fṛansa + italy: Ṭelyan + no_such_user: + title: Ulac aseqdac + deleted: yettwakkes + view: + my diary: AÉ£mis-iw + new diary entry: anekcam amaynut n uÉ£mis + my edits: Tiẓrigin-iw + my traces: Lǧerrat-iw + my notes: Tizmilin-iw + my messages: Iznan-iw + my profile: AmaÉ£nu-iw + my settings: IÉ£ewwaṛen-iw + my comments: Iwenniten-iw + oauth settings: iÉ£ewwaṛen oauth + blocks on me: Asewḥel i y-iɛnan + blocks by me: Asewḥel sÉ£ur-i + send message: Azen izen + diary: AÉ£mis + edits: Tiẓrigin + traces: Lǧeṛṛat + notes: Tizmilin n tkarḍa + remove as friend: Kkes seg imdukkal + add as friend: Rnu amdakkel + ago: (%{time_in_words_ago} aya) + ct status: 'Tiwtilin n iwiziw:' + ct declined: Yettwagi + ct accepted: Yettwaqbel %{ago} aya + latest edit: 'Asnifel aneggaru %{ago} :' + email address: 'Tansa imayl:' + created from: 'Yettwarna seg:' + status: 'Addad:' + spam score: 'Amatar n uspam:' + description: Aglam + user location: Adig n useqdac + settings_link_text: IÉ£ewwaṛen + your friends: Imdukkal-ik + km away: '%{count} km' + m away: yebɛed s %{count} m + nearby users: Iseqdacen-nniḍen iqeṛben + role: + administrator: Aseqdac-agi d anedbal + grant: + administrator: Mudd izerfan n unedbal + revoke: + administrator: Kkes izerfan n unedbal + block_history: Asewḥel urmid + moderator_history: Asewḥel yettunefken + comments: Iwenniten + create_block: Sewḥel aseqdac-agi + activate_user: Rmed aseqdac-agi + deactivate_user: Sens aseqdacèagi + confirm_user: Sentem aseqdac-agi + hide_user: Ffer aseqdac-agi + unhide_user: Sken aseqdac-agi + delete_user: Kkes aseqdac-agi + confirm: Sentem + friends_changesets: Igrawen n usnifel n yidukkal + friends_diaries: Inekcam n uÉ£mis n yimdukkal + nearby_changesets: Ihrawen n usnifel n iseqdacen iqeṛben + nearby_diaries: Inekcam n uÉ£mis n iseqdacen iqeṛben + popup: + your location: Adig-ik + friend: Amdakkel + account: + title: Ẓreg amiḍan + my settings: IÉ£ewwaṛen-iw + current email address: Tansa imayl n tura + new email address: Tansa imayl tamaynut + email never displayed publicly: (werǧin ad d-iban s wudem azayez) + openid: + link: http://wiki.openstreetmap.org/wiki/OpenID + link text: d acu-t wa? + public editing: + heading: Taẓrigt tazayezt + enabled link: http://wiki.openstreetmap.org/wiki/Anonymous_edits + enabled link text: d acu-t wa? + disabled link text: Acu zemreÉ£ ad beddleÉ£? + public editing note: + heading: Taẓrigt tazayezt + contributor terms: + heading: 'Tiwtilin n iwiziw:' + link text: what is this? + profile description: 'Aglam n umaÉ£nu:' + preferred languages: 'Tutlayin tebÉ£iḍ:' + preferred editor: 'Amaẓrag tebÉ£iḍ:' + image: 'Tugna:' + gravatar: + gravatar: Seqdec Gravatar + link text: d acu-t wa? + new image: Rbu tugna + delete image: Kkes tugna tamirant + replace image: Semselsi tugna tamirant + home location: 'Adig n uxxam:' + no home location: Ur tsekcemeḍ ara adig n uxxam-ik. + latitude: 'Tarrut:' + longitude: 'Tazegrart:' + update home location on click: Snifel adig n uxxam-ik ticki siteÉ£ É£ef tkarḍa? + save changes button: Sekles asnifel + make edits public button: Err akk tiẓrigin-iw s tizuyaz + return to profile: UÉ£al ar umaÉ£nu + flash update success: TalÉ£ut n useqdac tettwasnifel akken iwata + confirm: + heading: Senqed tansa-ik imayl! + introduction_1: Nuzen-ak-d imayl n usentem. + press confirm button: Senned É£ef tqeffalt Sentem ddaw-a akken ad tremdeḍ amiḍan-ik. + button: Sentem + success: Amiḍan yettwasentem, tanemmirt É£ef ujerred! + already active: Amiḍan-agi yettwasentem yakan. + unknown token: Tangalt n usentem tezri neÉ£ ulac-itt. + confirm_resend: + failure: Aseqdac %{name} ulac-it. + confirm_email: + heading: Sentem abeddel n tensa-ik imayl + button: Sentem + success: Sentem abeddel n tensa-ik imayl! + unknown_token: Tangalt n usentem tenfer neÉ£ ulac-itt. + set_home: + flash success: Adig n uxxam yettwasekles akken iwata + make_friend: + heading: Rnu %{user} d amdakkel? + button: Rnu d aseqdac + success: '%{name} d amdakkel-ik tura!' + already_a_friend: Telliḍ yakan d amdakul n %{name}. + remove_friend: + heading: Kkes %{user} seg yimdukkal? + button: Kkes seg imdukkal + success: '%{name} yettwakkes seg yimdukkal.' + not_a_friend: '%{name} ur yelli ara d amdakkel.' + filter: + not_an_administrator: Teriḍ ad tiliḍ d anedbal akken ad teggeḍ tigawt-agi. + list: + title: Iseqdacen + heading: Iseqdacen + showing: + other: Asebter %{page} (%{first_item}one= É£ef %{items}) + summary: '%{name} yettwarna si %{ip_address} di %{date}' + summary_no_ip: '%{name} yettwarna di %{date}' + confirm: Sentem iseqdacen yettwafernen + hide: Ffer iseqdacen yettwafernen + empty: Ulac aseqdac d-yefÉ£en deg unadi + suspended: + title: Amiḍan yettwaseḥbes + heading: Amiḍan yettwaseḥbes + auth_failure: + no_authorization_code: Ulac tangalt n wurag + auth_association: + option_1: Ma yella d amaynut i d-tusiḍ É£er OpenStreetMap, ttxil-ek(m) seÉ£new + amiḍan amaynut s tallalt n tferkit adda-ya. + user_role: + grant: + confirm: Sentem + revoke: + confirm: Sentem + user_block: + partial: + show: Sken + edit: Ẓreg + revoke: Ḥwi! + confirm: TebÉ£iḍ? + display_name: Aseqdac iweḥlen + creator_name: Amernay + reason: TaÉ£zint n usewḥel + status: Addad + revoker_name: Isewḥel-it + showing_page: Asebter %{page} + next: Ar zdat» + previous: « ar deffir + helper: + time_future: Ad ifak di %{time}. + until_login: D urmid arama yeqqen useqdac + time_past: Ifuk %{time} aya. + blocks_on: + title: Asewḥel n %{name} + empty: '%{name} ur yewḥil ara yakan.' + blocks_by: + title: Asewḥel sÉ£uṛ %{name} + heading: Tabdart n usewḥel sÉ£uṛ %{name} + empty: '%{name} ur isewḥel kra ar tura.' + show: + title: '%{block_on} isewḥel-it %{block_by}' + heading: '%{block_on} isewḥel-it %{block_by}' + time_future: Ad ifak di %{time} + time_past: Ifuk %{time} aya + created: Yettwarna + ago: '%{time} aya' + status: Addad + show: Sken + edit: Ẓreg + revoke: Ḥwi! + confirm: TebÉ£iḍ? + reason: 'TaÉ£zint n usewḥel:' + back: Sken akk isewḥal + needs_view: Aseqdac-agi yesra ad yeqqen send ad yettwakkes u sewḥel. + note: + description: + opened_at_html: Yattwarna %{when} aya + opened_at_by_html: Yettwarna %{when} aya sÉ£ur %{user} + commented_at_html: Yettwalqem %{when} aya + commented_at_by_html: Yettwalqem %{when} aya sÉ£ur %{user} + closed_at_html: Yefra %{when} aya + closed_at_by_html: Yefra %{when} aya sÉ£ur %{user} + reopened_at_html: Yettwarmed %{when} aya + reopened_at_by_html: Yettwarmed %{when} aya sÉ£ur %{user} + rss: + title: Tizmilin n OpenStreetMap + opened: tazmilt tamaynut (qrib ar %{place}) + commented: awennit amawut (qrib ar %{place}) + closed: tazmilt temdel (qrib ar %{place}) + reopened: tazmilt termed (qrib ar %{place}) + entry: + comment: Awennit + full: Tazmilt tummiḍt + mine: + heading: Tizmilin n %{user} + id: Asulay + creator: Amernay + description: Aglam + created_at: Yettwarna di + last_changed: Asnifel aneggaru + ago_html: '%{when} aya' + javascripts: + close: Mdel + share: + title: Bḍu + cancel: Sefsex + image: Tugna + link: AseÉ£wen neq HTML + long_link: AseÉ£wen + short_link: AseÉ£wen awezlan + geo_uri: URI arakal + embed: HTML + format: 'Amasal:' + scale: 'Sellum:' + download: Sider + short_url: URL awezlan + include_marker: Seddu anabraz + map: + locate: + title: Sken adig-iw + copyright: © Iwiziwen n OpenStreetMap + donate_link_text: + site: + edit_tooltip: Ẓreg takarḍa + createnote_tooltip: Rnu tazmilt ar tkarḍa + queryfeature_tooltip: isitar É£ef tmahilin + changesets: + show: + comment: Awennit + subscribe: Jerred + unsubscribe: FfeÉ£ seg ujerred + hide_comment: ffer + unhide_comment: sken + notes: + new: + add: Rnu tazmilt + show: + hide: Ffer + resolve: Fru + reactivate: Rmed + comment_and_resolve: Rnu awennit & Fru + comment: Awennit + directions: + engines: + graphhopper_car: S tkerrust(GraphHopper) + graphhopper_foot: Ɣef uḍaṛ (GraphHopper) + mapquest_bicycle: S uvilu(MapQuest) + mapquest_car: S tkerrust (MapQuest) + mapquest_foot: Ɣef uḍaṛ (MapQuest) + osrm_car: S tkeṛṛust (OSRM) + mapzen_bicycle: S uvilu (Mapzen) + mapzen_car: S tkeṛṛust (Mapzen) + mapzen_foot: Ɣef uḍaṛ (Mapzen) + instructions: + continue_without_exit: Kemmel É£ef %{name} + time: Akud + query: + node: Tikerrist + way: Abrid + relation: AssaÉ£ + nothing_found: Ulac taÉ£awsa yettwafen + error: 'Tuccḍa deg unermes n %{server} : %{error}' + timeout: Tanzagt tezri deg unermes n %{server} + context: + add_note: Rnu tazmilt dagi + show_address: Sken tansa + query_features: Suter tiÉ£awsiwin + redaction: + edit: + description: Aglam + new: + description: Aglam + show: + description: 'Aglam:' + user: 'Amernay:' + confirm: TebÉ£iḍ? +... diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 9fe56c3d2..2b25f7f5d 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -4,6 +4,7 @@ # Author: Alex00728 # Author: Asdfqwer51 # Author: B891202 +# Author: CYAN # Author: Freebiekr # Author: Garam # Author: Hym411 @@ -58,7 +59,7 @@ ko: relation_tag: 관계 태그 session: 세션 trace: 궤적 - tracepoint: 궤적 점 + tracepoint: 궤적 지점 tracetag: 궤적 태그 user: 사용자 user_preference: 사용자 환경 설정 @@ -95,7 +96,7 @@ ko: user: email: 이메일 active: 활성 - display_name: 표시 이름 + display_name: 이름 보이기 description: 설명 languages: 언어 pass_crypt: 비밀번호 @@ -150,7 +151,7 @@ ko: feed: title: 바뀜집합 %{id} title_comment: 바뀜집합 %{id} - %{comment} - join_discussion: 토론에 참여하려면 로그인 + join_discussion: 토론에 참여하려면 로그인하세요 discussion: 토론 node: title: '교점: %{name}' @@ -200,7 +201,7 @@ ko: way: 길 relation: 관계 start_rjs: - feature_warning: 브라우저가 느려지거나 응답하지 않을 수 있게 하는 지물 %{num_features}개를 불러오고 있습니다. + feature_warning: 지물 %{num_features}개를 불러오고 있으며, 브라우저가 느려지거나 응답하지 않을 수 있습니다. 정말 이 데이터를 표시하겠습니까? load_data: 데이터 불러오기 loading: 불러오는 중... @@ -383,7 +384,7 @@ ko: scale: 축척 max: 최대 image_size: 그림 크기 - zoom: 확대 + zoom: 확대/축소 add_marker: 지도에 표시 추가 latitude: '위도:' longitude: '경도:' @@ -394,7 +395,6 @@ ko: search: title: latlon: 내부 ê²°ê³¼ - us_postcode: Geocoder.us에서의 ê²°ê³¼ uk_postcode: NPEMap / FreeThe Postcode에서의 ê²°ê³¼ ca_postcode: Geocoder.CA에서의 ê²°ê³¼ @@ -875,7 +875,7 @@ ko: alpine_hut: 산장 apartment: 아파트먼트 artwork: 예술 작품 - attraction: 견인 + attraction: 관광 명소 bed_and_breakfast: 민박 cabin: 오두막 camp_site: 캠프장 @@ -1074,7 +1074,7 @@ ko: National Geo-Spatial Information에서의 데이터를 포함합니다. State가 저작권을 소유합니다. contributors_gb_html: |- - 연합 왕국: 육지 측량 데이터 + 영국: 육지 측량 데이터 © Crown 저작권 및 데이터베이스 권리 2010-12를 포함합니다. contributors_footer_1_html: |- @@ -1376,6 +1376,7 @@ ko: date: 날짜 reply_button: 답글 unread_button: 읽지 않음으로 표시 + delete_button: 삭제 back: 뒤로 to: 받는이 wrong_user: '''%{user}''님으로 로그인하고 있지만 읽기를 요청한 메시지가 해당 사용자에게 보내지지 않았습니다. 읽으려면 @@ -1424,7 +1425,7 @@ ko: to: 도착지 where_am_i: 내가 어디있나요? where_am_i_title: 검색 엔진을 사용하여 현재 위치를 나타냅니다 - submit_text: 가기 + submit_text: 검색 key: table: entry: diff --git a/config/locales/lb.yml b/config/locales/lb.yml index 1fb534e1a..23590aa76 100644 --- a/config/locales/lb.yml +++ b/config/locales/lb.yml @@ -48,6 +48,7 @@ lb: message: sender: Sender title: Sujet + recipient: Empfänger user: email: E-Mail active: Aktiv @@ -62,10 +63,14 @@ lb: id: name: iD browse: + created: Ugeluecht closed: Zou + created_html: Ugeluecht viru(n) %{time} closed_html: Zougemaach viru(n) %{time} + created_by_html: Ugeluecht viru(n) %{time} vum %{user} deleted_by_html: Geläscht viru(n) %{time} vum %{user} edited_by_html: Geännert viru(n) %{time} vum %{user} + closed_by_html: Zougemaach viru(n) %{time} vum %{user} version: Versioun in_changeset: Set vun Ännerungen anonymous: anonym @@ -87,6 +92,7 @@ lb: comment: Bemierkungen (%{count}) hidden_commented_by: Verstoppt Bemierkung vum %{user} viru(n) %{when} + commented_by: Bemierkung vum %{user} viru(n) %{when} changesetxml: XML mam Set vun Ännerungen osmchangexml: osmChange XML feed: @@ -196,6 +202,7 @@ lb: publish_button: Verëffentlechen list: title: Blogge vun de Benotzer + user_title: Blog vum %{user} edit: subject: 'Sujet:' language: 'Sprooch:' @@ -210,6 +217,7 @@ lb: login: Aloggen save_button: Späicheren diary_entry: + posted_by: Vum %{link_user} matgedeelt de(n) %{created} op %{language_link} comment_count: one: '%{count} Bemierkung' zero: Keng Bemierkungen @@ -232,6 +240,7 @@ lb: export: title: Exportéieren start: + area_to_export: Beräich fir den Export manually_select: Sicht manuell eng aner Géigend eraus format_to_export: Format fir z'exportéieren osm_xml_data: OpenStreetMap-XML-Daten @@ -249,12 +258,14 @@ lb: max: max image_size: Gréisst vum Bild zoom: Zoom + latitude: 'Geographesch Breet:' + longitude: 'Geographesch Längt:' + output: Resultat export_button: Exportéieren geocoder: search: title: latlon: Resultater vun Internal - us_postcode: Resultater vu Geocoder.us uk_postcode: Resultater vun NPEMap / FreeThe Postcode ca_postcode: Resultater vu Geocoder.ca @@ -262,12 +273,16 @@ lb: geonames_reverse: Resultater vun GeoNames search_osm_nominatim: prefix: + aerialway: + cable_car: Kabelwon aeroway: aerodrome: Fluchhafen gate: Paart + helipad: Helikopterlandeplaz runway: Start- a Landepist terminal: Terminal amenity: + arts_centre: Konschtzentrum atm: Bancomat bank: Bank bar: Bar @@ -286,9 +301,11 @@ lb: cinema: Kino clinic: Klinik clock: Auer + courthouse: Geriicht crematorium: Crematoire dentist: Zänndokter doctors: Dokteren + dormitory: Studentewunnengen drinking_water: Drénkwaasser driving_school: Fahrschoul embassy: Ambassade @@ -306,6 +323,7 @@ lb: market: Maart marketplace: Maartplaz monastery: Klouschter + nursery: Crèche office: Büro parking: Parking pharmacy: Apdikt @@ -315,6 +333,7 @@ lb: preschool: Spillschoul prison: Prisong pub: Bistro + public_building: Ëffentlecht Gebai reception_area: Rezeptiounsberäich recycling: Recycling-Center restaurant: Restaurant @@ -338,14 +357,19 @@ lb: boundary: national_park: Nationalpark bridge: + aqueduct: Aquädukt suspension: Hänkbréck + swing: Dréibréck viaduct: Viadukt "yes": Bréck building: "yes": Gebai craft: + brewery: Brauerei + carpenter: Zammermann electrician: Elektriker gardener: Gäertner + painter: Usträicher photographer: Fotograf shoemaker: Schouster tailor: Schneider @@ -355,6 +379,7 @@ lb: highway: bridleway: Wee fir Päerd bus_guideway: Busspur + bus_stop: Busarrêt construction: Autobunn (am Bau) elevator: Lift footway: Fousswee @@ -386,6 +411,7 @@ lb: citywalls: Stadmaueren house: Haus memorial: Monument + mine: Minn monument: Monument roman_road: Réimerwee ruins: Ruinen @@ -393,6 +419,8 @@ lb: tomb: Graf tower: Tuerm wreck: Wrack + junction: + "yes": Kräizung landuse: cemetery: Kierfecht farm: Bauerenhaff @@ -403,6 +431,7 @@ lb: grass: Wiss industrial: Industriezone military: Militairegebitt + mine: Minn orchard: Bongert quarry: Steekaul railway: Eisebunn @@ -494,7 +523,9 @@ lb: construction: Eisebunn (am Bau) disused: Fréier Eisebunn historic_station: Historesch Eisebunnsstatioun + junction: Eisebunnskräizung miniature: Miniatur-Eisebunn + platform: Zuchquai proposed: Proposéiert Eisebunnslinn station: Gare (Eisebunn) subway: Metro @@ -557,6 +588,7 @@ lb: "yes": Tunnel waterway: canal: Kanal + dam: Staudamm river: Floss wadi: Wadi waterfall: Waasserfall @@ -636,6 +668,7 @@ lb: title: Wëllkomm bäi OSM beginners_guide: url: http://wiki.openstreetmap.org/wiki/Beginners%27_guide + title: Guide fir nei Benotzer help: url: https://help.openstreetmap.org/ title: help.openstreetmap.org @@ -690,6 +723,8 @@ lb: subject: '[OpenStreetMap] Ufro fir d''Passwuert zréckzesetzen' lost_password_plain: greeting: Salut, + click_the_link: Wann Dir dat sidd da klickt w.e.g. op de Link hei drënner fir + Äert Passwuert zréckzesetzen. lost_password_html: greeting: Salut, click_the_link: Wann Dir dat sidd da klickt w.e.g. op de Link hei drënner fir @@ -701,6 +736,8 @@ lb: changeset_comment_notification: hi: Salut %{to_user}, greeting: Salut, + commented: + partial_changeset_without_comment: ouni Kommentar message: inbox: messages: Dir hutt %{new_messages} a(n) %{old_messages} @@ -734,17 +771,22 @@ lb: date: Datum reply_button: Äntwerten unread_button: Als net geliest markéieren + delete_button: Läschen back: Zréck sent_message_summary: delete_button: Läschen mark: as_read: Message als geliest markéiert + as_unread: Message als net geliest markéiert delete: deleted: Message geläscht site: index: + js_1: Dir hutt entweder e Browser dee JavaScript net ënnerstëtzt oder Dir hutt + JavaScript desaktivéiert. createnote: Eng Notiz derbäisetzen edit: + not_public: Dir hutt net agestallt datt Är Ännerungen ëffentlech sinn. user_page_link: Benotzersäit anon_edits_link_text: Fannt eraus firwat dat de Fall ass. sidebar: @@ -882,6 +924,7 @@ lb: allow_write_api: Kaart änneren index: title: Meng OAuth Detailer + revoke: Ophiewen! form: name: Numm required: Obligatoresch diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 29ff2a56a..54e773e15 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -394,7 +394,6 @@ lt: search: title: latlon: Vidiniai rezultatai - us_postcode: Geocoder.us rezultatai uk_postcode: NPEMap / FreeThe Postcode rezultatai ca_postcode: Geocoder.CA rezultatai diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 8d8f8979e..52c137c45 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -387,7 +387,6 @@ lv: search: title: latlon: Rezultāti no Iekšējās meklēšanas - us_postcode: Rezultāti no Geocoder.us uk_postcode: Rezultāti no NPEMap / FreeThe Postcode ca_postcode: Rezultāti no Geocoder.CA diff --git a/config/locales/mk.yml b/config/locales/mk.yml index a737bd57a..d00352f8a 100644 --- a/config/locales/mk.yml +++ b/config/locales/mk.yml @@ -383,7 +383,6 @@ mk: search: title: latlon: Внатрешни исходни ставки - us_postcode: Исход од Geocoder.us uk_postcode: Исход од NPEMap / FreeThe Postcode ca_postcode: Исход од Geocoder.CA @@ -1407,6 +1406,7 @@ mk: date: Датум reply_button: Одговори unread_button: Означи како непрочитано + delete_button: Избриши back: Назад to: За wrong_user: Најавени сте како „%{user}“, но пораката што побаравте да ја прочитате @@ -1462,7 +1462,7 @@ mk: from: Од to: До where_am_i: Каде сум? - where_am_i_title: Опишете ја моменталната местоположба со помош на пребарувачот + where_am_i_title: Опишете ја тековната местоположба со помош на пребарувачот submit_text: Дај key: table: diff --git a/config/locales/mr.yml b/config/locales/mr.yml index b64ef9c49..67009b6fe 100644 --- a/config/locales/mr.yml +++ b/config/locales/mr.yml @@ -360,7 +360,6 @@ mr: search: title: latlon: निकाल अंतर्गत - us_postcode: निकाल जिओकोडर.यूएस uk_postcode: निकालNPEMap / FreeThe Postcode ca_postcode: निकाल जिओकोडर.सीए osm_nominatim: निकाल ओपनस्ट्रीटमॅप diff --git a/config/locales/ms.yml b/config/locales/ms.yml index ecb0c7bcc..4ba64c820 100644 --- a/config/locales/ms.yml +++ b/config/locales/ms.yml @@ -2,6 +2,7 @@ # Exported from translatewiki.net # Export driver: phpyaml # Author: Anakmalaysia +# Author: Jeluang Terluang # Author: Karmadunya9- # Author: Macofe # Author: Nemo bis @@ -371,7 +372,6 @@ ms: search: title: latlon: Hasil carian dalaman - us_postcode: Hasil carian Geocoder.us uk_postcode: Hasil carian NPEMap / FreeThe Postcode ca_postcode: Hasil carian Geocoder.CA @@ -925,7 +925,7 @@ ms: edit_with: Sunting dengan %{editor} tag_line: Peta Dunia Wiki Bebas intro_header: Selamat datang ke OpenStreetMap! - intro_text: OpenStreetMap adalah peta dunia yang diwujudkan oleh insan seperti + intro_text: OpenStreetMap ialah peta dunia yang diwujudkan oleh insan seperti anda, dan bebas digunakan dengan berlandaskan lesen terbuka. intro_2_create_account: Buka akaun pengguna partners_html: Pengehosan disokong oleh %{ucl}, %{ic} dan %{bytemark}, serta %{partners} @@ -1040,8 +1040,8 @@ ms: atau menerima sebarang tanggungan.' infringement_title_html: Pencabulan hak cipta infringement_1_html: Penyumbang OSM diingatkan supaya tidak sesekali menambah - data dari mana-mana sumber berhak cipta (cth. Google Maps atau peta cetakan) - tanpa izin bersurat dari pemegang hak cipta. + data daripada mana-mana sumber berhak cipta (cth. Peta Google atau peta cetakan) + tanpa izin bersurat daripada pemegang hak cipta. infringement_2_html: "Sekiranya anda percaya bahawa bahan berhak cipta telah dtambahkan secara tidak berpatutan ke dalam pangkalan OpenStreetMap atau tapak ini, sila rujuk prosedur @@ -1067,13 +1067,13 @@ ms: title: Peristilahan Asas Pemetaan paragraph_1_html: OpenStreetMap mempunyai peristilahan tersendiri. Yang berikut ialah kata-kata kunci yang berguna. - editor_html: Editor adalah perisian atau laman web yang boleh + editor_html: Editor ialah perisian atau laman web yang boleh digunakan untuk menyunting peta. - node_html: Nod adalah titik pada peta, seperti sebuah kedai + node_html: Nod ialah titik pada peta, seperti sebuah kedai makan atau sebatang pokok. - way_html: Jalan adalah garis atau kawasan seperti jalan raya, + way_html: Jalan ialah garis atau kawasan seperti jalan raya, sungai, tasik atau bangunan. - tag_html: Teg adalah keterangan ringkas mengenai nod atau jalan, + tag_html: Teg ialah keterangan ringkas mengenai nod atau jalan, seperti nama restoran atau had laju jalan raya. rules: title: Peraturan! @@ -1098,7 +1098,7 @@ ms: join_the_community: title: Sertai komuniti explanation_html: Jika anda mendapati kemusykilan dengan data peta kami, misalnya - jalan raya atau alamat anda tertinggal, cara penyelesaian yang terbaik adalah + jalan raya atau alamat anda tertinggal, cara penyelesaian yang terbaik ialah menyertai komuniti OpenStreetMap dan menambah atau membetulkan data sendiri. add_a_note: instructions_html: |- @@ -1156,9 +1156,12 @@ ms: blog komuniti, dan laman web the OSM Foundation. open_data_title: Data Terbuka - open_data_html: |- - OpenStreetMap adalah data terbuka: anda bebas menggunakannya untuk sebarang tujuan asalkan anda memberikan penghargaan kepada OpenStreetMap dan para penyumbangnya. Jika anda mengubah suai atau menokok tambah datanya - dalam cara-cara tertentu, anda boleh mengedarkan hasilnya di bawah lesen yang sama sahaja. Rujuk halaman Hak Cipta dan Lesen untuk keterangan lanjut. + open_data_html: 'OpenStreetMap ialah data terbuka: anda bebas menggunakannya + untuk sebarang tujuan asalkan anda memberikan penghargaan kepada OpenStreetMap + dan para penyumbangnya. Jika anda mengubah suai atau menokok tambah datanya + dalam cara-cara tertentu, anda boleh mengedarkan hasilnya di bawah lesen yang + sama sahaja. Rujuk halaman Hak Cipta dan Lesen + untuk keterangan lanjut.' partners_title: Rakan Kongsi notifier: diary_comment_notification: diff --git a/config/locales/nb.yml b/config/locales/nb.yml index 2428b5bf8..bfcdda7ac 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -394,7 +394,6 @@ nb: search: title: latlon: Resultat fra Internt - us_postcode: Resultat fra Geocoder.us uk_postcode: Resultat fra NPEMap / FreeThe Postcode ca_postcode: Resultat fra Geocoder.CA @@ -964,7 +963,7 @@ nb: og gratis Ã¥ bruke under en Ã¥pen lisens. intro_2_create_account: Opprett en brukerkonto partners_html: Hosting er støttet av %{ucl}, %{ic}, %{bytemark} og andre %{partners}. - partners_ucl: UCL VR-senteret + partners_ucl: UCL partners_ic: Imperial College London partners_bytemark: Bytemark Hosting partners_partners: partnere @@ -1403,6 +1402,7 @@ nb: date: Dato reply_button: Svar unread_button: Marker som ulest + delete_button: Slett back: Tilbake to: Til wrong_user: Du er logget inn som «%{user}», men meldingen du ønsker Ã¥ lese ble @@ -2345,6 +2345,7 @@ nb: ascend: Tiltagende engines: graphhopper_bicycle: Sykkel (GraphHopper) + graphhopper_car: Bil (GraphHopper) graphhopper_foot: Til fots (GraphHopper) mapquest_bicycle: Sykkel (MapQuest) mapquest_car: Bil (MapQuest) diff --git a/config/locales/ne.yml b/config/locales/ne.yml index 16ba19515..210c65be5 100644 --- a/config/locales/ne.yml +++ b/config/locales/ne.yml @@ -264,7 +264,11 @@ ne: sorry: माफ गर्नुहोला, तपाईंले खोज्नुभएको परिवर्तनहरूको सूची प्राप्त गर्न निकै समय लाग्यो । rss: + title_all: OpenStreetMap परिवर्वतन सूची छलफल + title_particular: 'OpenStreetMap परिवर्तन सूची #%{changeset_id} छलफल' + comment: ' %{author}द्वारा #%{changeset_id}मा नयाँ टिप्पणी' commented_at_html: ' %{when} पहिले अद्यावधि गरिएको' + commented_at_by_html: ' %{user} द्वारा %{when} पहिले अद्यावधिक गरिएको' full: पूरा वार्तालाप diary_entry: new: @@ -364,8 +368,8 @@ ne: title: ओएस्एम ग्रह description: नियमित रूपमा अपडेट गरिएका ओपनस्ट्रीटम्याप तथ्याङ्कका प्रतिहरू overpass: - title: ओभरपास एपिअाई - description: ओपनस्ट्रीटम्याप तथ्याङ्कको अर्को स्रोतबाट यो सिमारेखा प्राप्त + title: ओभरपास एपिअाइ + description: OpenStreetMap तथ्याङ्कको अर्को स्रोतबाट यो सिमारेखा प्राप्त गर्नुहोस् geofabrik: title: Geofabrik डाउनलोडहरू @@ -393,7 +397,6 @@ ne: search: title: latlon: आन्तरिक बाट नतिजाहरू - us_postcode: Geocoder.usबाट नतिजाहरू uk_postcode: NPEMap / FreeThe Postcodeबाट नतिजाहरू ca_postcode: Geocoder.CAintern - us_postcode: Resultaten van Geocoder.us uk_postcode: Resultaten van NPEMap / FreeThe Postcode ca_postcode: Resultaten van Geocoder.CA @@ -1516,7 +1515,7 @@ nl: primary: Primaire weg secondary: Secundaire weg unclassified: Ongeclassificeerde weg - track: Spoor + track: Veld- of bosweg bridleway: Ruiterpad cycleway: Fietspad cycleway_national: Nationale fietsroute diff --git a/config/locales/nn.yml b/config/locales/nn.yml index a74c290e2..a7eeb9663 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -281,7 +281,6 @@ nn: search: title: latlon: Resultat frÃ¥ Internt - us_postcode: Resultat frÃ¥ Geocoder.us uk_postcode: Resultat frÃ¥ NPEMap / FreeThe Postcode ca_postcode: Resultat frÃ¥ Geocoder.CA @@ -1691,7 +1690,7 @@ nn: success: Blokkering oppdatert. index: title: Brukerblokkeringer - heading: Liste over brukerblokkeringer + heading: Liste over brukarblokkeringar empty: Ingen blokkeringar har vorte utførde enno. revoke: title: Tilbakekaller blokkering pÃ¥ %{block_on} diff --git a/config/locales/oc.yml b/config/locales/oc.yml index bc0c4e9bc..692d072be 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -3,6 +3,7 @@ # Export driver: phpyaml # Author: Cedric31 # Author: Macofe +# Author: OpenStreetMap-oc --- oc: time: @@ -381,7 +382,6 @@ oc: search: title: latlon: Resultats intèrnes - us_postcode: Resultats dempuèi Geocoder.us uk_postcode: Resultats dempuèi NPEMap / FreeThe Postcode ca_postcode: Resultats dempuèi Geocoder.CA @@ -753,7 +753,7 @@ oc: sea: Mar state: Estat / província subdivision: Subdivision - suburb: Barri + suburb: Quartier town: Vila unincorporated_area: Luòc pas organizat village: Vilatge @@ -948,7 +948,7 @@ oc: intro_2_create_account: Creatz un compte d'utilizaire partners_html: L'albergament es pres en carga per %{ucl}, %{ic} e %{bytemark}, e d'autres %{partners}. - partners_ucl: lo VR Centre de l'UCL + partners_ucl: UCL partners_ic: lo Collègi Imperial de Londres partners_bytemark: Albergament Bytemark partners_partners: partenaris @@ -1117,6 +1117,7 @@ oc: footer_html: Tanben podètz legir lo messatge a %{readurl} e i podètz respondre a %{replyurl} friend_notification: + hi: Bonjorn %{to_user}, subject: '[OpenStreetMap] %{user} vos a apondut coma amic' had_added_you: '%{user} vos a apondut coma amic dins OpenStreetMap.' see_their_profile: 'Podètz veire son perfil aicí : %{userurl}.' @@ -1261,6 +1262,7 @@ oc: date: Data reply_button: Respondre unread_button: Marcar coma pas legit + delete_button: Suprimir back: Retorn to: A wrong_user: Sètz identificat(-ada) coma « %{user} » mas lo messatge qu'ensajatz @@ -2077,8 +2079,10 @@ oc: comment_and_resolve: Comentar e resòlvre comment: Comentari directions: + ascend: Creissent engines: graphhopper_bicycle: A bicicleta (GraphHopper) + graphhopper_car: En veitura (GraphHopper) graphhopper_foot: A pè (GraphHopper) mapquest_bicycle: A bicicleta (MapQuest) mapquest_car: En veitura (MapQuest) @@ -2087,6 +2091,7 @@ oc: mapzen_bicycle: A bicicleta (Mapzen) mapzen_car: En veitura (Mapzen) mapzen_foot: A pè (Mapzen) + descend: Descreissent directions: Itineraris distance: Distància errors: diff --git a/config/locales/pl.yml b/config/locales/pl.yml index e8d56049c..750b86297 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -427,7 +427,6 @@ pl: search: title: latlon: Wyniki z Internal - us_postcode: Wyniki z Geocoder.us uk_postcode: Wyniki z NPEMap / FreeThe Postcode ca_postcode: Wyniki z Geocoder.CA @@ -593,7 +592,7 @@ pl: ford: Bród living_street: Strefa zamieszkania (znak D-40) milestone: Słupek pikietażowy - motorway: autostrada + motorway: Autostrada motorway_junction: Węzeł autostradowy motorway_link: Autostrada - dojazd path: Ścieżka @@ -983,7 +982,7 @@ pl: sign_up_tooltip: Załóż konto, aby edytować edit: Edycja history: Zmiany - export: Eksportowanie + export: Eksport data: Dane export_data: Eksportuj dane gps_traces: Ślady GPS @@ -997,7 +996,7 @@ pl: i z możliwością użycia pod otwartą licencją. intro_2_create_account: Utwórz konto partners_html: Hosting obsługuje %{ucl}, %{ic}, %{bytemark}, a także inni %{partners}. - partners_ucl: centrum UCL VR + partners_ucl: University College London partners_ic: Imperial College London partners_bytemark: Hosting Bytemark partners_partners: partnerzy @@ -1341,7 +1340,7 @@ pl: subject_other: '[OpenStreetMap] %{commenter} rozwiązał interesującą Cię uwagę' your_note: '%{commenter} rozwiązał jedną z Twoich uwag na mapie w lokalizacji: %{place}.' - commented_note: 'Użytkonik %{commenter} rozwiązał skomentowaną uwagę. Znajduje + commented_note: 'Użytkownik %{commenter} rozwiązał skomentowaną uwagę. Znajduje się ona w położeniu: %{place}.' reopened: subject_own: '[OpenStreetMap] %{commenter} ponownie aktywował jedną z Twoich @@ -1436,6 +1435,7 @@ pl: date: Nadano reply_button: Odpowiedz unread_button: Oznacz jako nieprzeczytaną + delete_button: Usuń back: Cofnij to: Do wrong_user: Jesteś zalogowany jako „%{user}”, ale wiadomość, którą chcesz przeczytać, @@ -2405,6 +2405,7 @@ pl: ascend: W górę engines: graphhopper_bicycle: Rower (GraphHopper) + graphhopper_car: Samochód (GraphHopper) graphhopper_foot: Pieszo (GraphHopper) mapquest_bicycle: Rower (MapQuest) mapquest_car: Samochód (MapQuest) diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 48683c238..1153b7da3 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -36,6 +36,7 @@ # Author: Vitalb # Author: Walesson # Author: Wille +# Author: Willemarcel # Author: 555 --- pt-BR: @@ -51,7 +52,7 @@ pt-BR: changeset_tag: Etiqueta do conjunto de alterações country: País diary_comment: Comentário do diário - diary_entry: Entrada do diário + diary_entry: Publicação do diário friend: Amigo language: Idioma message: Mensagem @@ -291,22 +292,22 @@ pt-BR: full: Discussão completa diary_entry: new: - title: Nova Entrada de Diário + title: Nova Publicação no Diário publish_button: Publicar list: title: Diários dos Usuários title_friends: Diários dos amigos title_nearby: Diários dos usuários próximos user_title: Diário de %{user} - in_language_title: Entradas de Diário em %{language} - new: Nova Entrada no Diário - new_title: Escrever nova entrada em seu diário - no_entries: Sem entradas no diário - recent_entries: Entradas recentes do diário - older_entries: Entradas mais antigas - newer_entries: Entradas mais novas + in_language_title: Publicações de Diário em %{language} + new: Nova Publicação no Diário + new_title: Escrever nova publicação em seu diário + no_entries: Sem publicações no diário + recent_entries: Publicações recentes no diário + older_entries: Publicações mais antigas + newer_entries: Publicações mais novas edit: - title: Editar entrada do diário + title: Editar publicação no diário subject: 'Assunto:' body: 'Texto:' language: 'Idioma:' @@ -315,7 +316,7 @@ pt-BR: longitude: 'Longitude:' use_map_link: usar mapa save_button: Salvar - marker_text: Localização da entrada no diário + marker_text: Localização da publicação no diário view: title: Diário de %{user} | %{title} user_title: Diário de %{user} @@ -324,20 +325,20 @@ pt-BR: login: Entrar save_button: Salvar no_such_entry: - title: Entrada de diário inexistente - heading: 'Não há entrada no diário com o id: %{id}' - body: Não há entrada no diário ou comentário com o id %{id}. Confira a digitação, + title: Publicação de diário inexistente + heading: 'Não há postagens no diário com o id: %{id}' + body: Não há postagens no diário ou comentário com o id %{id}. Confira a digitação, ou talvez o link clicado esteja errado. diary_entry: posted_by: Publicado por %{link_user} em %{created} em %{language_link} - comment_link: Comentar nesta entrada - reply_link: Responder esta entrada + comment_link: Comentar nesta publicação + reply_link: Responder esta publicação comment_count: one: '%{count} comentário' zero: Nenhum comentário other: '%{count} comentários' - edit_link: Editar esta entrada - hide_link: Ocultar essa entrada + edit_link: Editar esta postagem + hide_link: Ocultar essa postagem confirm: Confirmar diary_comment: comment_from: Comentário de %{link_user} em %{comment_created_at} @@ -349,16 +350,17 @@ pt-BR: edit: Editar feed: user: - title: Entradas do diário do OpenStreetMap de %{user} - description: Entradas recentes no diário do OpenStreetMap de %{user} + title: Publicações do diário do OpenStreetMap de %{user} + description: Publicações recentes no diário do OpenStreetMap de %{user} language: - title: Entradas no diário do OpenStreetMap em %{language_name} - description: Entradas de diário recentes de usuários do OpenStreetMap em %{language_name} + title: Publicações no diário do OpenStreetMap em %{language_name} + description: Publicações de diário recentes de usuários do OpenStreetMap em + %{language_name} all: - title: Entradas no diário do OpenStreetMap - description: Entradas no diário recentes de usuários do OpenStreetMap + title: Publicações no diário do OpenStreetMap + description: Publicações no diário recentes de usuários do OpenStreetMap comments: - has_commented_on: '%{display_name} comentou nestas entradas de diário' + has_commented_on: '%{display_name} comentou nestas postagens de diário' post: Publicar when: Quando comment: Comentário @@ -417,7 +419,6 @@ pt-BR: search: title: latlon: Resultados Internos - us_postcode: Resultados do Geocoder.us uk_postcode: Resultados do NPEMap / FreeThe Postcode ca_postcode: Resultados do Geocoder.CA @@ -469,7 +470,7 @@ pt-BR: cinema: Cinema clinic: Clínica médica clock: Relógio - college: Faculdade + college: Escola Técnica community_centre: Centro/Clube Comunitário courthouse: Fórum Jurídico crematorium: Crematório @@ -977,7 +978,7 @@ pt-BR: data: Dados export_data: Exportar Dados gps_traces: Trilhas GPS - gps_traces_tooltip: Gerenciar trilhas GPS + gps_traces_tooltip: Gerenciar trilhas de GPS user_diaries: Diários de Usuário user_diaries_tooltip: Ver os diários dos usuários edit_with: Edite com %{editor} @@ -988,7 +989,7 @@ pt-BR: intro_2_create_account: Criar uma conta de usuário partners_html: A hospedagem é apoiada por %{ucl}, %{ic}, %{bytemark}, e outros %{partners}. - partners_ucl: UCL VR Centre + partners_ucl: UCL partners_ic: Imperial College de Londres partners_bytemark: Hospedagem Bytemark partners_partners: parceiros @@ -1268,8 +1269,8 @@ pt-BR: diary_comment_notification: subject: '[OpenStreetMap] %{user} comentou em uma entrada do diário' hi: Olá %{to_user}, - header: '%{from_user} comentou na entrada do diário do OpenStreetMap com o assunto - %{subject}:' + header: '%{from_user} comentou na publicação do diário do OpenStreetMap com + o assunto %{subject}:' footer: Você pode ler o comentário em %{readurl}, pode comentá-lo em %{commenturl} ou respondê-lo em %{replyurl} message_notification: @@ -1446,6 +1447,7 @@ pt-BR: date: Data reply_button: Responder unread_button: Marcar como não lida + delete_button: Deletar back: Voltar to: Para wrong_user: Você está conectado como `%{user}' mas a mensagem que você quer @@ -1733,7 +1735,7 @@ pt-BR: allow_write_diary: criar entradas de diário, comentários e adicionar amigos. allow_write_api: modificar o mapa. allow_read_gpx: ler suas trilhas de GPS privadas - allow_write_gpx: atualizar trilhas de GPS. + allow_write_gpx: enviar trilhas de GPS. allow_write_notes: alterar notas. grant_access: Dar acesso oauthorize_success: @@ -1799,7 +1801,7 @@ pt-BR: allow_write_prefs: modificar as preferências de usuário dele. allow_write_diary: criar entradas de diário, comentários e adicionar amigos. allow_write_api: modificar o mapa. - allow_read_gpx: ler trilhas de GPS privadas dele. + allow_read_gpx: ler trilhas de GPS privadas deles. allow_write_gpx: enviar trilhas de GPS allow_write_notes: alterar notas. not_found: @@ -1952,7 +1954,7 @@ pt-BR: deleted: excluído view: my diary: Meu Diário - new diary entry: nova entrada de diário + new diary entry: nova publicação no diário my edits: Minhas Edições my traces: Minhas trilhas my notes: Minhas Notas de Mapa @@ -2013,9 +2015,9 @@ pt-BR: delete_user: Excluir este Usuário confirm: Confirmar friends_changesets: conjuntos de alterações dos amigos - friends_diaries: entradas de diário dos amigos + friends_diaries: publicações no diário dos amigos nearby_changesets: conjuntos de alterações de usuários próximos - nearby_diaries: entradas de diário dos usuários próximos + nearby_diaries: publicações no diário dos usuários próximos popup: your location: Sua localização nearby mapper: Mapeador próximo @@ -2366,7 +2368,7 @@ pt-BR: header: Camadas do Mapa notes: Notas de Mapa data: Dados do Mapa - gps: Rastreios públicos de GPS + gps: Trlhas de GPS públicas overlays: Ativar sobreposições para solucionar problemas do mapa title: Camadas copyright: © contribuidores do OpenStreetMap @@ -2382,7 +2384,7 @@ pt-BR: queryfeature_disabled_tooltip: Aproxime para consultar elementos changesets: show: - comment: Comentário + comment: Comentar subscribe: Inscrever unsubscribe: Cancelar inscrição hide_comment: esconder @@ -2408,6 +2410,7 @@ pt-BR: ascend: Ascender engines: graphhopper_bicycle: Bicicleta (GraphHopper) + graphhopper_car: Carro (GraphHopper) graphhopper_foot: Pedestre (GraphHopper) mapquest_bicycle: Bicicleta (MapQuest) mapquest_car: Carro (MapQuest) diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 8aaf8bc13..e81c4ae1d 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -404,7 +404,6 @@ pt-PT: search: title: latlon: Resultados Internos - us_postcode: Resultados de Geocoder.us uk_postcode: Resultados de NPEMap / FreeThe Postcode ca_postcode: Resultados de Geocoder.CA @@ -971,7 +970,7 @@ pt-PT: intro_2_create_account: Crie uma conta de utilizador partners_html: O alojamento é suportado por %{ucl}, %{ic}, %{bytemark} e outros %{partners}. - partners_ucl: UCL VR Centre + partners_ucl: UCL partners_ic: Imperial College London partners_bytemark: Bytemark Hosting partners_partners: parceiros @@ -1047,9 +1046,9 @@ pt-PT: href="http://wiki.openstreetmap.org/wiki/Legal_FAQ">Perguntas frequentes - Legais (em inglês). more_2_html: Apesar do OpenStreetMap ser uma plataforma de dados abertos, não podemos fornecer a terceiros uma API de mapas, livre de encargos. Veja a Política de Utilização - da API, Política - de Utilização de Telas e Política + href="https://operations.osmfoundation.org/policies/api/">Política de Utilização + da API, Política + de Utilização de Telas e Política de Utilização do Nominatim. contributors_title_html: Os nossos contribuidores contributors_intro_html: 'Os contribuidores do OpenStreetMap são milhares. Também @@ -1260,6 +1259,7 @@ pt-PT: assunto %{subject}:' footer_html: Também pode ler a mensagem em %{readurl} e pode responder em %{replyurl} friend_notification: + hi: Olá %{to_user}, subject: '[OpenStreetMap] %{user} adicionou-o como amigo' had_added_you: '%{user} adicionou-o como amigo no OpenStreetMap.' see_their_profile: Pode ver o perfil do editor em %{userurl}. @@ -1348,6 +1348,7 @@ pt-PT: O erro encontra-se perto de %{place}.' details: Ver mais detalhes sobre o erro reportado em %{url}. changeset_comment_notification: + hi: Olá %{to_user}, greeting: Olá, commented: subject_own: '[OpenStreetMap] %{commenter} comentou uma das suas edições' @@ -1360,6 +1361,8 @@ pt-PT: partial_changeset_with_comment: com o comentário '%{changeset_comment}' partial_changeset_without_comment: sem comentários details: Pode encontrar mais informações sobre a edição em %{url}. + unsubscribe: Para deixar de seguir as atualizações deste conjunto de alterações, + aceda a %{url} e clique em "Anular subscrição". message: inbox: title: Caixa de Entrada @@ -1422,6 +1425,7 @@ pt-PT: date: Data reply_button: Responder unread_button: Marcar como não lida + delete_button: Eliminar back: Voltar to: Para wrong_user: Está autenticado com a conta `%{user}', mas a mensagem que pediu @@ -1490,6 +1494,9 @@ pt-PT: track: Carreiro florestal ou agrícola bridleway: Via para cavaleiros cycleway: Ciclovia + cycleway_national: Ciclovia nacional + cycleway_regional: Ciclovia regional + cycleway_local: Ciclovia local footway: Via pedonal rail: Ferrovia subway: Metropolitano @@ -1542,6 +1549,9 @@ pt-PT: private: Acesso restrito (propriedade privada) destination: Acesso a clientes / fornecedores construction: Estradas em construção + bicycle_shop: Loja de Bicicletas + bicycle_parking: Estacionamento de bicicletas + toilets: Casas de banho richtext_area: edit: Editar preview: Mostrar previsão @@ -1684,6 +1694,8 @@ pt-PT: require_moderator: not_a_moderator: Tem de ser um moderador para poder fazer essa ação. setup_user_auth: + blocked_zero_hour: Tem uma mensagem urgente no site do OpenStreetMap. Tem de + ler a mensagem antes de poder gravar as suas edições. blocked: O seu acesso à API foi bloqueado. Por favor aceda à página web do OpenStreetMap e entre na sua conta para saber mais. need_to_see_terms: O seu acesso à API está temporariamente suspenso. Por favor @@ -1714,6 +1726,8 @@ pt-PT: invalid: O token de autorização não é válido. revoke: flash: Revogou o Token para %{application} + permissions: + missing: Não deu permissão programa para aceder a esta instalação oauth_clients: new: title: Registar um novo programa @@ -1818,6 +1832,9 @@ pt-PT: github: title: Iniciar sessão com GitHub alt: Iniciar sessão com uma conta GitHub + wikipedia: + title: Iniciar sessão através da Wikipédia + alt: Iniciar a sessão com uma conta da Wikipédia yahoo: title: Iniciar sessão com Yahoo alt: Iniciar sessão com OpenID Yahoo @@ -1910,6 +1927,7 @@ pt-PT: heading: O utilizador %{user} não existe body: Não existe nenhum utilizador com o nome %{user}. Verifique se o endereço está correto ou talvez a hiperligação que clicou esteja errada. + deleted: eliminado view: my diary: Meu diário new diary entry: adicionar entrada no meu diário @@ -2024,6 +2042,8 @@ pt-PT: gravatar: gravatar: Usar imagem do site Gravatar link text: o que é isto? + disabled: O Gravatar foi desativado. + enabled: A visualização do seu avatar de Gravatar foi ativada. new image: Adicionar imagem keep image: Manter a imagem atual delete image: Remover a imagem atual @@ -2229,6 +2249,8 @@ pt-PT: helper: time_future: Termina em %{time}. until_login: Ativo até o utilizador entrar na conta. + time_future_and_until_login: Termina em %{time} e após o utilizador entrar na + conta. time_past: Terminou há %{time} atrás. blocks_on: title: Bloqueios em %{name} @@ -2307,6 +2329,7 @@ pt-PT: center_marker: Centrar o mapa no marcador paste_html: Colar HTML para incorporar na página web view_larger_map: Ver mapa maior + only_standard_layer: Apenas a Camada Padrão pode ser exportada como imagem embed: report_problem: Reportar problema key: @@ -2329,6 +2352,7 @@ pt-PT: header: Camadas do Mapa notes: Erros reportados no mapa data: Dados técnicos do mapa + gps: Trilhos GPS Públicos overlays: Ativar sobreposições para solucionar problemas do mapa title: Camadas copyright: © Colaboradores do OpenStreetMap @@ -2370,8 +2394,10 @@ pt-PT: edit_help: Mova o mapa e amplie a localização que pretende editar e depois clique aqui. directions: + ascend: Ascenção engines: graphhopper_bicycle: Bicicleta (GraphHopper) + graphhopper_car: Carro (GraphHopper) graphhopper_foot: A pé (GraphHopper) mapquest_bicycle: Bicicleta (MapQuest) mapquest_car: Carro (MapQuest) @@ -2380,6 +2406,7 @@ pt-PT: mapzen_bicycle: Bicicleta (Mapzen) mapzen_car: Carro (Mapzen) mapzen_foot: A pé (Mapzen) + descend: Descida directions: Direções distance: Distância errors: @@ -2387,12 +2414,38 @@ pt-PT: no_place: Desculpe - não foi possível encontrar esse local. instructions: continue_without_exit: Continuar em %{name} + slight_right_without_exit: Virar ligeiramente à direita para %{name} + offramp_right_without_exit: Seguir a via de acesso à direita para %{name} + onramp_right_without_exit: Virar à direita na via de acesso para %{name} + endofroad_right_without_exit: No fim da estrada, virar à direita para %{name} + merge_right_without_exit: Encostar à via da direita para %{name} + fork_right_without_exit: Na bifurcação virar à direita para %{name} + turn_right_without_exit: Virar à direita para %{name} + sharp_right_without_exit: Curva acentuada à direita para %{name} + uturn_without_exit: Inversão de marcha em %{name} + sharp_left_without_exit: Curva acentuada à esquerda para %{name} + turn_left_without_exit: Virar à esquerda para %{name} + offramp_left_without_exit: Seguir a via de acesso à esquerda para %{name} + onramp_left_without_exit: Virar à esquerda na via de acesso para %{name} + endofroad_left_without_exit: No fim da estrada virar à esquerda para %{name} + merge_left_without_exit: Encostar à via da esquerda para %{name} + fork_left_without_exit: Na bifurcação virar à esquerda para %{name} + slight_left_without_exit: Virar ligeiramente à esquerda para %{name} + via_point_without_exit: (ponto de passagem) follow_without_exit: Seguir %{name} roundabout_without_exit: Na rotunda seguir %{name} leave_roundabout_without_exit: Saia da rotunda - %{name} stay_roundabout_without_exit: Mantenha-se na rotunda - %{name} + start_without_exit: Começar no final de %{name} destination_without_exit: Chegada ao destino + against_oneway_without_exit: Ir em contra-mão em %{name} + end_oneway_without_exit: Fim do sentido único em %{name} roundabout_with_exit: Na rotunda seguir a saída %{exit} para %{name} + turn_left_with_exit: Na rotunda, virar à esquerda para %{name} + slight_left_with_exit: Na rotunda, virar ligeiramente à esquerda para %{name} + turn_right_with_exit: Na rotunda, virar à direita para %{name} + slight_right_with_exit: Na rotunda, virar ligeiramente à direita para %{name} + continue_with_exit: Na rotunda, continuar em frente para %{name} unnamed: sem nome courtesy: Direções fornecidas por %{link} time: Tempo @@ -2403,6 +2456,13 @@ pt-PT: nothing_found: Nenhum elemento encontrado error: 'Erro ao comunicar com %{server}: %{error}' timeout: Tempo limite excedido ao ligar a %{server} + context: + directions_from: Direções a partir daqui + directions_to: Direções para aqui + add_note: Reportar um erro aqui + show_address: Mostrar endereço + query_features: Consular elementos + centre_map: Centrar mapa aqui redaction: edit: description: Descrição diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 59b0271e4..b0ccdde0f 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -367,13 +367,15 @@ ro: search: title: latlon: Rezultate interne - us_postcode: Rezultate de la Geocoder.us uk_postcode: Rezultate de la NPEMap / FreeThe Postcode ca_postcode: Rezultate de la Geocoder.CA osm_nominatim: Rezultate de la OpenStreetMap Nominatim geonames: Rezultate de la GeoNames + osm_nominatim_reverse: Rezultate de la OpenStreetMap + Nominatim + geonames_reverse: Rezultate de la GeoNames search_osm_nominatim: prefix_format: '%{name}' prefix: @@ -721,6 +723,8 @@ ro: food: Alimentară furniture: Mobilier gallery: Galerie + gift: Magazin de cadouri + greengrocer: Piață de zarzavat grocery: Magazin alimentar hairdresser: Coafor hifi: Hi-Fi @@ -730,6 +734,7 @@ ro: laundry: Spălătorie mall: Mall market: Piață + mobile_phone: Magazin de telefoane newsagent: Chioșc de ziare optician: Optician organic: Magazin de alimente organice @@ -772,6 +777,10 @@ ro: waterfall: Cascadă weir: Stăvilar description: + title: + osm_nominatim: Rezultate de la OpenStreetMap + Nominatim + geonames: Rezultate de la GeoNames types: cities: Orașe towns: Orășele @@ -835,7 +844,7 @@ ro: title: Întrebări? start_mapping: Începeți să cartografiați add_a_note: - title:

      Nu aveți timp pentru editare? Adaugați o notiță

      + title:

      Nu aveți timp pentru editare? Adaugați o notă!

      fixthemap: how_to_help: title:

      Cum poți ajuta

      @@ -855,6 +864,8 @@ ro: next: Înainte partners_title: Parteneri notifier: + diary_comment_notification: + hi: Salut %{to_user}, message_notification: hi: Salut, %{to_user}, friend_notification: @@ -922,6 +933,7 @@ ro: edit: user_page_link: pagină de utilizator sidebar: + search_results: Rezultatele căutării close: Închide search: search: Căutare @@ -980,6 +992,8 @@ ro: login: email or username: 'Adresa de e-mail sau numele de utilizator:' password: 'Parolă:' + logout: + heading: Deconectare din OpenStreetMap reset_password: password: 'Parola:' confirm password: 'Confirmați parola:' @@ -1026,6 +1040,9 @@ ro: title: Arată locația mea site: edit_disabled_tooltip: Măriți pentru a edita harta + createnote_tooltip: Adaugă o notă pe hartă context: + directions_from: Direcția de aici + add_note: Adaugă aici o observație show_address: Arată adresa ... diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 7db50d123..2a9d50716 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -27,6 +27,7 @@ # Author: Facenapalm # Author: FreeExec # Author: G0rn +# Author: Helpau # Author: Ignatus # Author: Iluvatar # Author: Irus @@ -96,7 +97,7 @@ ru: tracetag: Тег маршрута user: Пользователь user_preference: Настройки пользователя - user_token: Маркер пользователя + user_token: Токен пользователя way: Линия way_node: Точка линии way_tag: Тег линии @@ -443,7 +444,6 @@ ru: search: title: latlon: Внутренние результаты - us_postcode: Результаты от Geocoder.us uk_postcode: Результаты от NPEMap / FreeThe Postcode ca_postcode: Результаты от Geocoder.CA @@ -1465,6 +1465,7 @@ ru: date: Дата reply_button: Ответить unread_button: Пометить как непрочитанное + delete_button: Удалить back: Назад to: 'Кому:' wrong_user: Вы вошли как пользователь `%{user}', но ответ на ваш вопрос был @@ -2443,6 +2444,7 @@ ru: ascend: По возврастанию engines: graphhopper_bicycle: На велосипеде (GraphHopper) + graphhopper_car: На машине (GraphHopper) graphhopper_foot: Пешком (GraphHopper) mapquest_bicycle: На велосипеде (MapQuest) mapquest_car: На машине (MapQuest) diff --git a/config/locales/scn.yml b/config/locales/scn.yml index 695d3d29f..60573e3fc 100644 --- a/config/locales/scn.yml +++ b/config/locales/scn.yml @@ -382,7 +382,6 @@ scn: search: title: latlon: Risurtati di Nternu - us_postcode: Risurtati di Geocoder.us uk_postcode: Risurtati di NPEMap / FreeThe Postcode ca_postcode: Risurtati di Geocoder.CA diff --git a/config/locales/sco.yml b/config/locales/sco.yml index d5f25c36f..3fe4afd0e 100644 --- a/config/locales/sco.yml +++ b/config/locales/sco.yml @@ -364,7 +364,6 @@ sco: search: title: latlon: Results frae Internal - us_postcode: Results frae Geocoder.us uk_postcode: Results frae NPEMap / FreeThe Postcode ca_postcode: Results frae Geocoder.CA diff --git a/config/locales/sk.yml b/config/locales/sk.yml index d011e15d6..6c519622b 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -372,7 +372,6 @@ sk: search: title: latlon: Výsledky z internej databázy - us_postcode: Výsledky z Geocoder.us uk_postcode: Výsledky z NPEMap / FreeThe Postcode ca_postcode: Výsledky z Geocoder.CA diff --git a/config/locales/sl.yml b/config/locales/sl.yml index d10bef047..d55798ed8 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -4,6 +4,7 @@ # Author: Damjang # Author: Dbc334 # Author: Eleassar +# Author: HairyFotr # Author: Lesko987 # Author: Macofe # Author: Mateju @@ -388,7 +389,6 @@ sl: search: title: latlon: Interni zadetki - us_postcode: Zadetki iz Geocoder.us uk_postcode: Zadetki iz NPEMap / FreeThe Postcode ca_postcode: Zadetki iz Geocoder.CA @@ -407,7 +407,7 @@ sl: gondola: Kabinska žičnica station: ŽičniÅ¡ka postaja aeroway: - aerodrome: Aerodrom + aerodrome: Letališče apron: LetaliÅ¡ka ploščad gate: Vrata helipad: Heliodrom @@ -557,7 +557,7 @@ sl: motorway_junction: Avtocestno križišče motorway_link: Avtocestni priključek path: Pot - pedestrian: Ulica namenjena peÅ¡cem + pedestrian: Ulica, namenjena peÅ¡cem platform: Platforma primary: Glavna cesta primary_link: Priključek na glavno cesto @@ -621,7 +621,7 @@ sl: construction: Gradbišče farm: Kmetija farmland: Kmetijsko zemljišče - farmyard: Vrt + farmyard: Kmetija forest: Gozd garages: Garaže grass: Trata @@ -953,7 +953,7 @@ sl: vi, brezplačen za uporabo z odprto licenco. intro_2_create_account: Ustvarite uporabniÅ¡ki račun partners_html: Gostovanje podpira %{ucl}, %{ic} in %{bytemark}, ter ostali %{partners}. - partners_ucl: Center UCL VR + partners_ucl: UCL partners_ic: Imperial College v Londonu partners_bytemark: Bytemark Hosting partners_partners: partnerji @@ -998,6 +998,9 @@ sl: Slovenija: Vsebuje javne podatke Geodetske uprave Republike Slovenije in Ministrstva za kmetijstvo, gozdarstvo in prehrano. + contributors_footer_1_html: |- + Za več podrobnosti o teh in drugih virih, ki so bili uporabljeni kot pripomočki pri izboljÅ¡evanju OpenStreetMap, si prosimo oglejte stran sodelujočih na wikiju OpenStreetMap. infringement_title_html: KrÅ¡itev avtorskih pravic welcome_page: title: DobrodoÅ¡li! @@ -1066,6 +1069,13 @@ sl: url: https://help.openstreetmap.org/ description: Zastavite vpraÅ¡anje ali poiščete odgovore v OSM zbirki vpraÅ¡anj in odgovorov. + mailing_lists: + title: PoÅ¡tni seznami + forums: + title: Forumi + irc: + title: IRC + description: Interaktivni klepet v mnogo različnih jezikih in o mnogo temah. wiki: description: Prebrskajte wiki za poglobljeno OSM dokumentacijo. about_page: @@ -1075,10 +1085,10 @@ sl: partners_title: Partnerji notifier: diary_comment_notification: - subject: '[OpenStreetMap] %{user} je komentiral vaÅ¡ vnos v dnevnik' + subject: '[OpenStreetMap] %{user} je komentiral vnos v dnevnik' hi: Pozdravljen, %{to_user}! - header: '%{from_user} je komentiral vaÅ¡ nedavni vnos v OpenStreetMap dnevnik - z naslovom %{subject}:' + header: '%{from_user} je komentiral vnos v dnevnik OpenStreetMap z naslovom + %{subject}:' footer: Komentar lahko preberete tudi na %{readurl}, komentirate lahko na %{commenturl} ali odgovorite na %{replyurl} message_notification: @@ -1256,6 +1266,7 @@ sl: date: Datum reply_button: Odgovori unread_button: Označi kot neprebrano + delete_button: IzbriÅ¡i back: Nazaj to: Za wrong_user: Prijavljeni ste kot '%{user}', ampak sporočilo, ko ga \elite prebrati @@ -1451,7 +1462,7 @@ sl: view: title: Prikaz sledi %{name} heading: Prikaz sledi %{name} - pending: ČAKAJOČA + pending: V ČAKALNI VRSTI filename: 'Datoteka:' download: prenos uploaded: 'Poslano:' @@ -1472,7 +1483,7 @@ sl: older: StarejÅ¡e sledi newer: NovejÅ¡e sledi trace: - pending: ČAKAJOČA + pending: V ČAKALNI VRSTI count_points: '%{count} točk' ago: '%{time_in_words_ago} nazaj' more: več @@ -1540,8 +1551,10 @@ sl: allow_read_gpx: branje zasebnih sledi GPS. allow_write_gpx: nalaganje sledi GPS. allow_write_notes: spreminjanje opomb. + grant_access: Odobri dostop oauthorize_success: title: Zahteva za overovitev uspeÅ¡na + allowed: Aplikaciji %{app_name} ste odobrili zahtevek za dostop do vaÅ¡ega računa. verification: Koda za preverjanje je %{code}. oauthorize_failure: title: Zahteva za overovitev ni uspela @@ -1848,6 +1861,7 @@ sl: gravatar: gravatar: Uporabi Gravatar link text: Kaj je to? + disabled: Gravatar je onemogočen. new image: Dodaj sliko keep image: Obdrži trenutno sliko delete image: Odstrani trenutno sliko diff --git a/config/locales/sq.yml b/config/locales/sq.yml index d1f70234a..53d3639c0 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -399,7 +399,6 @@ sq: search: title: latlon: Rezultatet e brendshme nga - us_postcode: Rezultatet nga Geocoder.us uk_postcode: Rezultatet nga NPEMap / FreeThe Postcode ca_postcode: Rezultatet nga Geocoder.ca diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index c2267a4e6..192b53287 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -270,7 +270,6 @@ sr-Latn: search: title: latlon: Rezultati iz Internala - us_postcode: Rezultati iz Geokodera uk_postcode: Rezultati iz NPEMap-a ca_postcode: Rezultati iz Geokodera osm_nominatim: Rezultati iz Nominatima diff --git a/config/locales/sr.yml b/config/locales/sr.yml index d5fcfa084..ba3d58d7f 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -8,6 +8,7 @@ # Author: Nemo bis # Author: Nikola Smolenski # Author: Obsuser +# Author: Prevodim # Author: Rancher # Author: Sawa # Author: Srdjan m @@ -386,7 +387,6 @@ sr: search: title: latlon: Унутрашњи резултати - us_postcode: Резултати са сајта Geocoder.us uk_postcode: Резултати са сајта NPEMap/FreeThe Postcode ca_postcode: Резултати са сајта Geocoder.ca @@ -1031,10 +1031,10 @@ sr: href="http://wiki.openstreetmap.org/wiki/Legal_FAQ">честим правним питањима. more_2_html: |- Иако OpenStreetMap ради с отвореним подацима, не можемо - понудити бесплатан АПИ за мапе независним програмерима. - Погледајте правила о употреби АПИ-ја, - правила о употреби поља - и Номинатим. + трећим странама понудити бесплатан API за мапе. + Погледајте правила о употреби API-ја, + правила о употреби поља + и Номинатим. contributors_title_html: Наши сарадници contributors_intro_html: |- У нашем пројекту учествује на хиљаде појединаца. Користимо и @@ -1052,6 +1052,11 @@ sr: ресурсе Канаде), Канвек (© Одељење за природне ресурсе Канаде) и Статкан (Географски одсек, Завод за статистику Канаде). + contributors_fi_html: |- + Финска: Садржи податке са + Топографске базе података Националног геодетског завода Финске + те друге сетове података, под + NLSFI лиценцом. contributors_fr_html: |- Француска: садржи податке који потичу од Генералне дирекције за опорезивање. @@ -1061,6 +1066,11 @@ sr: contributors_nz_html: |- Нови Зеланд: садржи податке који потичу од Land Information New Zealand. Крунска ауторска права задржана. + contributors_si_html: |- + Словенија: Садржи податке са + Ауторитета за истраживање и мапирање те од + Министарства за пољопривреду, шумарство и прехрамбену индустрију + (јавне информације Словеније). contributors_za_html: |- Јужноафричка Република: садржи податке из Главне управе: @@ -1081,6 +1091,17 @@ sr: infringement_1_html: ОСМ сарадници се подсећају да никад не додају податке из извора заштићених ауторским правима (нпр. Гугл карте или штампане карте) без изричите дозволе власника ауторских права. + infringement_2_html: |- + Ако верујете да је материјал заштићен ауторским правима био неприкладно + додат у базу података OpenStreetMap или овај сајт, молимо да пратите + нашу процедуру за + скидање или да се директно обратите на + нашој онлајн страници за пријаве. + trademarks_title_html: Робне марке + trademarks_1_html: OpenStreetMap, лого лупе и State of the Map регистроване + су робне марке Фондације OpenStreetMap. Ако имате питања о томе како да користите + марке, пошаљите своја питања Радној + групи за лиценце. welcome_page: title: Добро дошли! introduction_html: Добродошли на ОпенСтритМап, бесплатну изменљиву карту света. @@ -1105,6 +1126,14 @@ sr: језера или грађевине. tag_html: Ознака је јединица којом се описује тачка или линија, нпр. име ресторана или ограничење брзине на одређеном путу. + rules: + title: Правила! + paragraph_1_html: "OpenStreetMap има мало формалних правила, али очекујемо од + свих учесника да сарађују\nи комуницирају са заједницом. Ако разматрате било + какве\nактивности поред ручног уређивања, прочитајте и пратите смернице о + \nувозу + и \nаутоматизованим + изменама." questions: title: Питања? paragraph_1_html: |- @@ -1142,12 +1171,32 @@ sr: и одговарају на питања, и заједнички расправљају и документују картографске теме. welcome: + url: /welcome title: Добродошли на ОСМ description: Почни са овим брзим водичем који покрива основе ОпенСтритМапа + beginners_guide: + url: http://wiki.openstreetmap.org/wiki/Sr:Beginners%27_guide + title: Водич за почетничке + description: Водич за почетнике help: + url: https://help.openstreetmap.org/ + title: help.openstreetmap.org description: Постави питање или нађи одговор на ОСМ страници за питања и одговоре. + mailing_lists: + title: Дописне листе + description: Поставите питање или дискутујте о питањима од значаја која се тичу + широког спектра тематских или регионалних мејлинг листа. forums: title: Форуми + description: Питања и расправе за оне који преферирају интерфејс у стилу билтен + табле. + irc: + title: IRC + description: Интерактивни разговор на многим језицима и на многе теме. + switch2osm: + title: switch2osm + description: Помоћ за компаније и организације које прелазе на мапе засноване + на OpenStreetMap-у и другим алаткама. wiki: url: http://wiki.openstreetmap.org/wiki/Sr:Main_Page title: wiki.openstreetmap.org/wiki/Sr:Main_Page @@ -1165,13 +1214,34 @@ sr: снимке из ваздуха, GPS уређаје и обичне теренске мапе у циљу провере исправности и ажурности OSM-а. community_driven_title: Заједница је покретач + community_driven_html: "Заједница OpenStreetMap-а је разнолика, страствена и расте + сваког дана. \nНаши сарадници су ентузијстични мапери, професионалци за GIS, + инжењери\nкоји покрећу OSM сервере, хуманитарци који мапирају подручја погођена + катастрофама,\nи још многи други.\nДа бисте сазнали више о заједници, погледајте + корисничке дневнике,\nблогове + заједнице и\nвеб-сајт Фондације + OSM." open_data_title: Отцорени подаци + open_data_html: |- + OpenStreetMap је опен дата: слободно можете да га користите за било коју сврху + све док одате заслуге за OpenStreetMap и оне који на њему доприносе. Ако измените или + правите податке на одређене начине, можете да дистрибуишете резултата само + под истом лиценцом. Погледајте страницу о ауторским правима + и лиценцама за детаље. + legal_title: Правни аспекти + legal_html: "Овим сајтом и многим другим повезаним алаткама формално управља\nФондација OpenStreetMap (OSMF) \nу име + заједнице. Употреба свих алатки којима управља OSMF је предмет \nнаше \nполитике + прихватљиве употребе и наше политике + приватности\n
      \nМолимо да контактирате + OSMF \nако имате правна питања или проблеме око лиценцирања, ауторских права + и сл." partners_title: Партнери notifier: diary_comment_notification: - subject: '%{user} је прокоментарисао ваш дневнички запис' + subject: '%{user} је прокоментарисао дневнички запис' hi: Поздрав, %{to_user}, - header: '%{from_user} је прокоментарисао ваш скорашњи дневнички запис под насловом + header: '%{from_user} је прокоментарисао OpenStreetMap дневнички запис под насловом %{subject}:' footer: Можете прочитати коментаре на %{readurl}, прокоментарисати на %{commenturl} или одговорити на %{replyurl} @@ -1179,7 +1249,10 @@ sr: subject_header: '[Опенстритмап] – %{subject}' hi: Поздрав, %{to_user}, header: '%{from_user} вам посла поруку преко Опенстритмапа под насловом %{subject}:' + footer_html: Такође можете да прочитате поруку на %{readurl} и можете да одговорите + на %{replyurl} friend_notification: + hi: Поздрав, %{to_user}, subject: '[OpenStreetMap] %{user} вас је додао као пријатеља' had_added_you: '%{user} вас је додао као пријатеља на Опенстритмапу.' see_their_profile: Можете видети његов/њен профил на %{userurl}. @@ -1204,6 +1277,11 @@ sr: subject: '[OpenStreetMap] Добро дошли на ОпенСтритМап' greeting: Здраво! created: Неко (надамо се ти) је управо отворио налог на %{site_url}. + confirm: 'Пре него што ишта урадимо, морамо да потврдимо да је овај захтев дошао + од вас, тако да ако заиста јесте молимо да кликнете на везу испод да бисте + потврдили свој налог:' + welcome: Након што потврдите свој налог, пружићемо Вам неке додатне информације + о томе како почети. email_confirm: subject: '[OpenStreetMap] Потврдите Вашу имејл адресу' email_confirm_plain: @@ -1220,6 +1298,8 @@ sr: subject: '[OpenStreetMap] Захтев за поништавање лозинке' lost_password_plain: greeting: Поздрав, + hopefully_you: Неко (вероватно ви) затражио је поништавање лозинке за имејл + адресу овог openstreetmap.org налога. click_the_link: Ако си то ти, кликни на везу испод да поништиш лозинку. lost_password_html: greeting: Поздрав, @@ -1228,10 +1308,48 @@ sr: note_comment_notification: anonymous: Анонимни корисник greeting: Поздрав, + commented: + subject_own: '[OpenStreetMap] %{commenter} је коментарисао на једној од Ваших + белешки' + subject_other: '[OpenStreetMap] %{commenter} је коментарисао на белешци за + коју сте заинтересовани' + your_note: '%{commenter} је оставио коментар на једну од Ваших белешка на + мапама у близини места %{place}.' + commented_note: '%{commenter} је оставио коментар на белешки мапе коју сте + Ви коментарисали. Белешка је у близини места %{place}.' + closed: + subject_own: '[OpenStreetMap] %{commenter} је решио једну од Ваших белешки' + subject_other: '[OpenStreetMap] %{commenter} је решио белешу за коју сте заинтересовани' + your_note: '%{commenter} је решио једну од Ваших белешки на мапи у близини + места %{place}.' + commented_note: '%{commenter} је решио белешку мапе коју сте коментарисали. + Белешка је у близини места %{place}.' + reopened: + subject_own: '[OpenStreetMap] %{commenter} је реактивирао једну од Ваших белешки' + subject_other: '[OpenStreetMap] %{commenter} је реактивирао белешку за коју + сте заинтересовани' + your_note: '%{commenter} је реактивирао једну од Ваших белешки мапе у близини + места %{place}.' + commented_note: '%{commenter} је реактивирао белешку мапе коју сте коментарисали. + Белешка је у близини места %{place}.' + details: Више информација о белешци може да се пронађе на %{url}. changeset_comment_notification: + hi: Поздрав, %{to_user}, greeting: Поздрав, commented: + subject_own: '[OpenStreetMap] %{commenter} је коментарисао о једном од Ваших + чејнџсетова' + subject_other: '[OpenStreetMap] %{commenter} је коментарисао о чејнџсету за + који сте заинтересовани' + your_changeset: '%{commenter} је оставио коментар на једном од Ваших чејнџсетова + направљеном %{time}' + commented_changeset: '%{commenter} је оставио коментар на чејнџсету мапе који + надгледате и који је направио %{changeset_author} у %{time}' + partial_changeset_with_comment: са коментаром ’%{changeset_comment}’ partial_changeset_without_comment: без коментара + details: Више информација о чејнџсетовима може да се пронађе на %{url}. + unsubscribe: Да бисте престали пратити апдејте овог чејнџсета, посетите %{url} + и кликните на „Престани пратити”. message: inbox: title: Примљене @@ -1240,10 +1358,10 @@ sr: messages: Имате %{new_messages} и %{old_messages} new_messages: one: '%{count} нова порука' - other: '%{count} нове поруке' + other: '%{count} нових порука' old_messages: one: '%{count} стара порука' - other: '%{count} старе поруке' + other: '%{count} старих порука' from: Од subject: Наслов date: Датум @@ -1293,6 +1411,7 @@ sr: date: Датум reply_button: Одговори unread_button: Означи као непрочитано + delete_button: Обриши back: Назад to: За wrong_user: Пријављени сте као %{user}, али порука коју сте желели да прочитате @@ -1333,6 +1452,7 @@ sr: potlatch2_not_configured: Потлач 2 није подешен. Погледајте http://wiki.openstreetmap.org/wiki/The_Rails_Port potlatch2_unsaved_changes: Нисте сачували измене. Да бисте то урадили, кликните на дугме за чување. + id_not_configured: iD није конфигурисан no_iframe_support: Ваш прегледач не подржава HTML iframes, а они су потребни за ову могућност. sidebar: @@ -1340,6 +1460,10 @@ sr: close: Затвори search: search: Претрага + get_directions: Тражите упутства + get_directions_title: Пронађите навигацију између две тачке + from: Од + to: До where_am_i: Где сам? where_am_i_title: Установите тренутну локацију помоћу претраживача submit_text: Иди @@ -1355,6 +1479,9 @@ sr: track: Макадам bridleway: Коњичка стаза cycleway: Бициклистичка стаза + cycleway_national: Национална бициклистичка стаза + cycleway_regional: Регионална бициклистичка стаза + cycleway_local: Локална бициклистичка стаза footway: Пешачка стаза rail: Железничка пруга subway: Подземна железница @@ -1407,6 +1534,9 @@ sr: private: Приватни посед destination: Приступ одредишту construction: Путеви у изградњи + bicycle_shop: Продавница бицикала + bicycle_parking: Паркинг за бицикле + toilets: Тоалети richtext_area: edit: Уреди preview: Преглед @@ -1519,6 +1649,7 @@ sr: public_traces: Јавни ГПС трагови your_traces: Ваши ГПС трагови public_traces_from: Јавни GPS трагови корисника %{user} + description: Претражите недавне аплоуде GPS путева tagged_with: ' означени са %{tags}' empty_html: Овде још увек нема ништа. Отпремите нови траг или сазнајте више о GPS траговима на вики @@ -1532,6 +1663,13 @@ sr: offline: heading: GPX остава је ван мреже message: GPX остава и отпремање тренутно нису доступни. + georss: + title: OpenStreetMap GPS трасе + description: + description_with_count: + one: GPX датотека са %{count} тачком од %{user} + other: GPX датотека са %{count} тачака од %{user} + description_without_count: GPX датотека од %{user} application: require_cookies: cookies_needed: Изгледа да сте онемогућили колачиће. Омогућите их пре него што @@ -1539,12 +1677,15 @@ sr: require_moderator: not_a_moderator: Да бисте извели ову радњу, треба да будете модератор. setup_user_auth: + blocked_zero_hour: Имате хитну поруку на веб-сајту OpenStreetMap. Морате прочитати + поруку пре него што могнете спремати своје измене. blocked: Ваш приступ АПИ-ју је блокиран. Пријавите се да сазнате више. need_to_see_terms: Ваш приступ АПИ-ју је привремено укинут. Пријавите се да бисте погледали услове уређивања. Не морате да их прихватите, већ само да их видите. oauth: oauthorize: + title: Ауторизујте приступ свом налогу request_access: Програм %{app_name} захтева приступ вашем налогу, %{user}. Одлучите се да ли желите да му га омогућите. Можете изабрати било који програм. allow_to: 'Дозволи програму да:' @@ -1554,8 +1695,20 @@ sr: allow_write_api: мења мапу. allow_read_gpx: чита ваше приватне GPS трагове. allow_write_gpx: отпрема GPS трагове. + allow_write_notes: измени белешке. + grant_access: Додели приступ + oauthorize_success: + title: Омогућен захтев за ауторизацију + allowed: Омогућили сте да апликација %{app_name} приступи Вашем налогу. + verification: Верификациони код је %{code}. + oauthorize_failure: + title: Неуспешан захтев за ауторизацију + denied: Онемогућили сте да апликација %{app_name} приступи Вашем налогу. + invalid: Токен за ауторизацију није валидан. revoke: flash: Опозвали сте новчић за %{application} + permissions: + missing: Нисте дозволили приступ апликације овом одељењу oauth_clients: new: title: Упиши нови програм @@ -1628,6 +1781,7 @@ sr: login_button: Пријави ме register now: Отворите налог with username: 'Већ имате налог? Пријавите се с корисничким именом и лозинком:' + with external: 'Алтернативно, користите трећу страну да се пријавите:' new to osm: Нови сте на сајту? to make changes: Да бисте правили измене, морате имати налог. create account minute: Отворите налог. Потребно је само неколико тренутака. @@ -1643,8 +1797,31 @@ sr: auth_providers: openid: title: Пријавити се са OpenID + alt: Пријава преко OpenID URL-а + google: + title: Пријава преко Гугла + alt: Пријава преко Google OpenID-а facebook: title: Пријавити се са Facebook-ом + alt: Пријава преко Facebook налога + windowslive: + title: Пријава преко Windows Live-а + alt: Пријава преко Windows Live налога + github: + title: Пријава коришћењем GitHub-а + alt: Пријава коришћењем GitHub налога + wikipedia: + title: Пријава преко Википедије + alt: Пријава коришћењем Википедија налога + yahoo: + title: Пријава преко Јахуа + alt: Пријава преко Yahoo OpenID-а + wordpress: + title: Пријава коришћењем Wordpress-а + alt: Пријава преко Wordpress OpenID-а + aol: + title: Пријава преко AOL-а + alt: Пријава преко AOL OpenID-а logout: title: Одјава heading: Одјава @@ -1672,18 +1849,28 @@ sr: налог. contact_webmaster: Контактирајте администратора за отварање новог налога. Обрадићемо захтев што је пре могуће. + about: + header: Слободно и изменљиво + html: |- +

      За разлику од осталих мапа, OpenStreetMap у потпуности стварају људи као Ви, + и бесплатан је за свакога да поправља, ажурира, преузима и користи.

      +

      Пријавите се да бисте почели да доприносите. Послаћемо Вам имејл за потврду Вашег налога.

      license_agreement: Након што потврдите налог, мораћете да прихватите услове уређивања. email address: 'Имејл адреса:' confirm email address: 'Потврдите имејл адресу:' - not displayed publicly: Не приказује се јавно (погледајте политику - приватности) + not displayed publicly: Ваша адреса се не приказује јавно, погледајте политику + приватности за више информација display name: 'Име приказа:' display name description: Јавно приказано корисничко име. Касније га можете променити у поставкама. + external auth: 'Аутентификација треће стране:' password: 'Лозинка:' confirm password: 'Потврдите лозинку:' + use external auth: Алтернативно, користите трећу страну за пријаву + auth no password: Са аутентификацијом треће стране, лозинка није потребна — + али неки додатни алати или сервер можда је ипак буду захтевали. continue: Отвори налог terms accepted: Хвала вам што прихватате нове услове уређивања. terms declined: Жао нам је што сте одлучили да не прихватите нове услове уређивања. @@ -1715,6 +1902,7 @@ sr: heading: Корисник %{user} не постоји body: Не постоји корисник с именом %{user}. Проверите исправност уписа или везе коју сте кликнули. + deleted: обрисано view: my diary: Мој дневник new diary entry: нови дневнички запис @@ -1828,6 +2016,8 @@ sr: gravatar: gravatar: Користи Граватар link text: шта је ово? + disabled: Граватар је онемогућен. + enabled: Приказ Вашег Граватара је омогућен. new image: Додај слику keep image: Задржи тренутну слику delete image: Уклони тренутну слику @@ -1911,6 +2101,21 @@ sr: Ову одлуку ће убрзо размотрити администратор. Такође, можете контактирати %{webmaster}а ако желите да се жалите.

      + auth_failure: + connection_failed: Повезивање до аутентификационог провајдера неуспешно + invalid_credentials: Невалидни аутентификациони акредитиви + no_authorization_code: Нема кода ауторизације + unknown_signature_algorithm: Непознат потписни алгоритам + invalid_scope: Невалидан опсед + auth_association: + heading: Ваш ID још увек није повезан са налогом OpenStreetMap. + option_1: |- + Ако сте нови у OpenStreetMap, молимо да направите нови налог + коришћењем доњег обрасца. + option_2: |- + Ако већ имате налог, можете да се пријавите на свој налог + коришћењем свог корисничког имена и лозинке, а потом да га повежете + са својим ID-ом у корисничким подешавањима. user_role: filter: not_an_administrator: Само администратори могу да управљају улогама корисника, @@ -2007,6 +2212,7 @@ sr: helper: time_future: Завршава се у %{time}. until_login: Активно све док се корисник не пријави. + time_future_and_until_login: Завршава у %{time} и након што се корисник пријави. time_past: Завршено пре %{time}. blocks_on: title: Блокаде за %{name} @@ -2021,6 +2227,8 @@ sr: heading: '%{block_on} је блокиран/а од %{block_by}' time_future: Завршава се у %{time} time_past: Завршено пре %{time} + created: Направљено + ago: пре %{time} status: Стање show: Прикажи edit: Уреди @@ -2071,6 +2279,7 @@ sr: link: Веза или HTML long_link: Веза short_link: Кратка веза + geo_uri: Geo URI embed: HTML custom_dimensions: Постави посебне димензије format: 'Формат:' @@ -2082,10 +2291,13 @@ sr: center_marker: Центрирај карту на ознаку paste_html: Налепи HTML да га уградиш у веб страницу view_larger_map: Погледај већу карту + only_standard_layer: Само стандардни лејер може да се извезе као слика + embed: + report_problem: Пријави проблем key: title: Легенда tooltip: Легенда карте - tooltip_disabled: Легенда је доступна само за стандардни слој + tooltip_disabled: Легенда није доступна само за овај лејер map: zoom: in: Увећај @@ -2102,6 +2314,7 @@ sr: header: Слојеви карте notes: Белешке на карти data: Подаци карте + gps: Јавне GPS трасе overlays: Омогући преклапање за тражење грешака на карти title: Слојеви copyright: © ОпенСтритМап сарадници @@ -2139,8 +2352,10 @@ sr: comment: Коментариши edit_help: Помери карту и увећај на место које хоћеш да уредиш, затим кликни овде. directions: + ascend: Растуће engines: graphhopper_bicycle: Бициклом (GraphHopper) + graphhopper_car: Ауто (GraphHopper) graphhopper_foot: Пешке (GraphHopper) mapquest_bicycle: Бициклом (MapQuest) mapquest_car: Аутомобилом (MapQuest) @@ -2149,6 +2364,7 @@ sr: mapzen_bicycle: Бициклом (Mapzen) mapzen_car: Аутомобилом (Mapzen) mapzen_foot: Пешке (Mapzen) + descend: Опадајуће directions: Путања distance: Удаљеност errors: @@ -2157,11 +2373,21 @@ sr: instructions: continue_without_exit: Наставите на %{name} slight_right_without_exit: Мало удесно у %{name} + offramp_right_without_exit: Идите на рампу десно, на %{name} + onramp_right_without_exit: Скрените десно на рампи, на %{name} + endofroad_right_without_exit: На крају цесте скрените десно, на %{name} + merge_right_without_exit: Укључите се десно, на %{name} + fork_right_without_exit: На рачвању скрените десно, на %{name} turn_right_without_exit: Скрените десно у %{name} sharp_right_without_exit: Нагло удесно у %{name} uturn_without_exit: Полукружно окретање дуж %{name} sharp_left_without_exit: Нагло улево у %{name} turn_left_without_exit: Скрените лево у %{name} + offramp_left_without_exit: Идите на рампу лево, на %{name} + onramp_left_without_exit: Скрените лево на рампи, на %{name} + endofroad_left_without_exit: На крају цесте скрените лево, на %{name} + merge_left_without_exit: Укључите се лево, на %{name} + fork_left_without_exit: На рачвању скрените лево, на %{name} slight_left_without_exit: Мало улево у %{name} via_point_without_exit: (преко тачке) follow_without_exit: Пратите %{name} @@ -2173,6 +2399,11 @@ sr: against_oneway_without_exit: Идите једносмерном на %{name} end_oneway_without_exit: Крај једносмерне на %{name} roundabout_with_exit: На кружном току изаберите излаз %{exit} на %{name} + turn_left_with_exit: На кружном току скрените лево у %{name} + slight_left_with_exit: На кружном току скрените благо лево у %{name} + turn_right_with_exit: На кружном току скрените десно у %{name} + slight_right_with_exit: На кружном току скрените благо десно у %{name} + continue_with_exit: На кружном току наставите право у %{name} unnamed: без имена courtesy: Путању је омогућио %{link} time: Време @@ -2183,6 +2414,13 @@ sr: nothing_found: Нема објеката у близини error: 'Грешка при повезивању са %{server}: %{error}%{error}' timeout: Истекло је време за повезивање са %{server} + context: + directions_from: Упути одавде + directions_to: Упути довде + add_note: Додај белешку овде + show_address: Прикажи адресу + query_features: Одлике упита + centre_map: Центрирај мапу овде redaction: edit: description: Опис diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 2619f3510..b5a29b489 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -6,6 +6,7 @@ # Author: Adrianod # Author: Ainali # Author: Balp +# Author: Bengtsson96 # Author: Cohan # Author: Cybjit # Author: Dan Koehl @@ -56,7 +57,7 @@ sv: language: SprÃ¥k message: Meddelande node: Nod - node_tag: Nodtagg + node_tag: Nodetikett notifier: Meddelande old_node: Gammal nod old_node_tag: Gammal nodtagg @@ -65,7 +66,7 @@ sv: old_relation_tag: Gammal relationstagg old_way: Gammal sträcka old_way_node: Gammal sträcknod - old_way_tag: Gammal sträcktagg + old_way_tag: Gammal sträcketikett relation: Relation relation_member: Relationsmedlem relation_tag: Relationstagg @@ -74,11 +75,11 @@ sv: tracepoint: SpÃ¥rpunkt tracetag: SpÃ¥retikett user: Användare - user_preference: Användarinställningar + user_preference: Användarinställning user_token: Användarnyckel way: Sträcka way_node: Sträcknod - way_tag: Vägtagg + way_tag: Sträcketikett attributes: diary_comment: body: Brödtext @@ -131,12 +132,14 @@ sv: browse: created: Skapad closed: Stängd - created_html: Skapade %{time} sedan - closed_html: Stängde för %{time} sedan - created_by_html: Skapade %{time} sedan av %{user} - deleted_by_html: Raderade %{time} sedan av %{user} - edited_by_html: Redigerade %{time} sedan av %{user} - closed_by_html: Stängde för %{time} sedan av %{user} + created_html: Skapades för %{time} sedan + closed_html: Stängdes för %{time} sedan + created_by_html: Skapades för %{time} sedan av %{user} + deleted_by_html: Raderades för %{time} sedan av + %{user} + edited_by_html: Redigerades för %{time} sedan av + %{user} + closed_by_html: Stängdes för %{time} sedan av %{user} version: Version in_changeset: Ändringsset anonymous: anonym @@ -218,9 +221,9 @@ sv: webbläsare lÃ¥ngsam eller fÃ¥ den att sluta svara. Är säker pÃ¥ att du vill visa denna data? load_data: Ladda data - loading: Läser in... + loading: Läser in … tag_details: - tags: Taggar + tags: Etiketter wiki_link: key: Wiki-beskrivningssidan för %{key}-taggen tag: Wiki-beskrivningssidan för %{key}=%{value}-taggen @@ -237,17 +240,19 @@ sv: open_by: Skapad av %{user} %{when} sedan open_by_anonymous: Skapad av anonym %{when} sedan commented_by: Kommentar frÃ¥n %{user} %{when} sedan - commented_by_anonymous: Kommentar frÃ¥n anonym %{when} - sedan - closed_by: Löst av %{user} %{when} sedan - closed_by_anonymous: Löst av anonym %{when} sedan - reopened_by: Återaktiverad av %{user} %{when} sedan - reopened_by_anonymous: Återaktiverad av anonym %{when} + commented_by_anonymous: Kommentar frÃ¥n en anonym användare för + %{when} sedan + closed_by: Löst av %{user} för %{when} sedan + closed_by_anonymous: Löst av en anonym användare för + %{when} sedan + reopened_by: Återaktiverades av %{user} för %{when} sedan - hidden_by: Gömd av %{user} %{when} sedan + reopened_by_anonymous: Återaktiverades av en anonym användare för + %{when} sedan + hidden_by: Doldes av %{user} för %{when} sedan query: title: Undersök kartobjekt - introduction: Klicka pÃ¥ kartan för att hitta närliggande funktioner. + introduction: Klicka pÃ¥ kartan för att hitta funktioner i närheten. nearby: Finns i närheten enclosing: Omgivande kartobjekt changeset: @@ -414,7 +419,6 @@ sv: search: title: latlon: Resultat frÃ¥n OpenStreetMap - us_postcode: Resultat frÃ¥n Geocoder.us uk_postcode: Resultat frÃ¥n NPEMap / Free The Postcode ca_postcode: Resultat frÃ¥n Geocoder.CA @@ -573,7 +577,7 @@ sv: bridleway: Ridstig bus_guideway: SpÃ¥rbussväg bus_stop: BusshÃ¥llplats - construction: Motorväg under konstruktion + construction: Väg under byggnad cycleway: CykelspÃ¥r elevator: Hiss emergency_access_point: Utryckningsplats @@ -1444,6 +1448,7 @@ sv: date: Datum reply_button: Svara unread_button: Markera som oläst + delete_button: Radera back: Tillbaka to: Till wrong_user: Du är inloggad som '%{user}', men meddelandet du har bett om att diff --git a/config/locales/te.yml b/config/locales/te.yml index bfad7e408..abbe0f978 100644 --- a/config/locales/te.yml +++ b/config/locales/te.yml @@ -227,7 +227,6 @@ te: search: title: latlon: అంతర్గత ఫలితాలు - us_postcode: Geocoder.us నుండి ఫలితాలు ca_postcode: Geocoder.CA నుండి ఫలితాలు geonames: GeoNames నుండి ఫలితాలు search_osm_nominatim: diff --git a/config/locales/th.yml b/config/locales/th.yml new file mode 100644 index 000000000..1a47c367e --- /dev/null +++ b/config/locales/th.yml @@ -0,0 +1,1660 @@ +# Messages for Thai (ไทย) +# Exported from translatewiki.net +# Export driver: phpyaml +# Author: Ariesanywhere +# Author: Pon44695 +# Author: Ruila +# Author: TMo3289 +--- +th: + time: + formats: + friendly: '%e %B %Y เมื่อเวลา %H:%M น.' + activerecord: + models: + acl: รายการควบคุมการเข้าถึง + changeset: ชุดการเปลี่ยนแปลง + changeset_tag: ป้ายกำกับชุดการเปลี่ยนแปลง + country: ประเทศ + diary_comment: ความคิดเห็นสำหรับบันทึก + diary_entry: รายการบันทึก + friend: เพื่อน + language: ภาษา + message: ข้อความ + node: หมุด + node_tag: ป้ายกำกับหมุด + notifier: ผู้แจ้ง + old_node: หมุดเก่า + old_node_tag: ป้ายกำกับหมุดเก่า + old_relation: ความสัมพันธ์เดิม + old_relation_member: สมาชิกของความสัมพันธ์เดิม + old_relation_tag: ป้ายกำกับของความสัมพันธ์เดิม + old_way: เส้นทางเดิม + old_way_node: จุดของเส้นทางเดิม + old_way_tag: ป้ายกำกับของเส้นทางเดิม + relation: ความสัมพันธ์ + relation_member: สมาชิกของความสัมพันธ์ + relation_tag: ป้ายกำกับของความสัมพันธ์ + session: การเข้าใช้งาน + trace: รอยทาง + tracepoint: จุดรอยทาง + tracetag: ป้ายกำกับรอยทาง + user: ผู้ใช้งาน + user_preference: การตั้งค่าผู้ใช้ + user_token: รหัสคำขอผู้ใช้ + way: เส้นทาง + way_node: หมุดเส้นทาง + way_tag: ป้ายกำกับเส้นทาง + attributes: + diary_comment: + body: เนื้อหา + diary_entry: + user: ผู้ใช้งาน + title: หัวเรื่อง + latitude: ละติจูด + longitude: ลองติจูด + language: ภาษา + friend: + user: ผู้ใช้งาน + friend: เพื่อน + trace: + user: ผู้ใช้งาน + visible: เปิดเผย + name: ชื่อ + size: ขนาด + latitude: ละติจูด + longitude: ลองติจูด + public: สาธารณะ + description: คำอธิบาย + message: + sender: ผู้ส่ง + title: หัวเรื่อง + body: เนื้อหา + recipient: ผู้รับ + user: + email: อีเมล์ + active: เปิดใช้ + display_name: ชื่อที่ใช้แสดง + description: คำอธิบาย + languages: ภาษา + pass_crypt: รหัสผ่าน + editor: + default: ค่าปกติ (ขณะนี้ %{name}) + potlatch: + name: พอตแลตช์ 1 + description: พอตแลตช์ 1 (ตัวแก้ไขในเบราว์เซอร์) + id: + name: iD + description: iD (ตัวแก้ไขในเบราว์เซอร์) + potlatch2: + name: พอตแลตช์ 2 + description: พอตแลตช์ 2 (ตัวแก้ไขในเบราว์เซอร์) + remote: + name: การควบคุมระยะไกล + description: ตัวควบคุมระยะไกล (JOSM หรือ Merkaartor) + browse: + created: สร้างเมื่อ + closed: ปิดเมื่อ + created_html: สร้างเมื่อ %{time} ก่อน + closed_html: ปิดเมื่อ %{time} ก่อน + created_by_html: สร้างเมื่อ %{time} ก่อน โดย %{user} + deleted_by_html: ลบเมื่อ %{time} ก่อน โดย %{user} + edited_by_html: แก้ไขเมื่อ %{time} ก่อน โดย %{user} + closed_by_html: ปิดเมื่อ %{time} ก่อน โดย %{user} + version: รุ่นที่ + in_changeset: ชุดการเปลี่ยนแปลง + anonymous: ไม่ระบุตัวตน + no_comment: (ไม่มีความคิดเห็น) + part_of: เป็นส่วนหนึ่งของ + download_xml: ดาวน์โหลด XML + view_history: ดูประวัติ + view_details: ดูรายละเอียด + location: 'ที่ตั้ง:' + changeset: + title: 'ชุดการเปลี่ยนแปลง: %{id}' + belongs_to: ผู้สร้างสรรค์ + node: หมุด (%{count}) + node_paginated: หมุดที่ (%{x}-%{y} จากทั้งหมด %{count}) + way: เส้นทาง (%{count}) + way_paginated: เส้นทางที่ (%{x}-%{y} จาก %{count}) + relation: ความสัมพันธ์ (%{count}) + relation_paginated: ความสัมพันธ์ (%{x}-%{y} จาก %{count}) + comment: ความคิดเห็น (%{count}) + hidden_commented_by: ความคิดเห็นซ่อนจาก %{user} เมื่อ %{when} + ก่อน + commented_by: ความคิดเห็นจาก %{user} เมื่อ %{when} + ก่อน + changesetxml: ชุดการเปลี่ยนแปลง XML + feed: + title: ชุดการเปลี่ยนแปลง %{id} + title_comment: ชุดการเปลี่ยนแปลง %{id} - %{comment} + join_discussion: เข้าสู่ระบบเพื่อเข้าร่วมการอภิปราย + discussion: การอภิปราย + node: + title: 'หมุด: %{name}' + history_title: 'ประวัติหมุด: %{name}' + way: + title: 'เส้นทาง: %{name}' + history_title: 'ประวัติเส้นทาง: %{name}' + nodes: หมุด + relation: + title: 'ความสัมพันธ์: %{name}' + history_title: 'ประวัติความสัมพันธ์: %{name}' + members: สมาชิก + relation_member: + entry_role: '%{type} %{name} ในฐานะ %{role}' + type: + node: หมุด + way: เส้นทาง + relation: ความสัมพันธ์ + containing_relation: + entry: ความสัมพันธ์ %{relation_name} + entry_role: ความสัมพันธ์ %{relation_name} (ในฐานะ %{relation_role}) + not_found: + sorry: 'ขออภัย ไม่พบ %{type} #%{id}' + type: + node: หมุด + way: เส้นทาง + relation: ความสัมพันธ์ + changeset: ชุดการเปลี่ยนแปลง + note: หมายเหตุ + timeout: + sorry: ขออภัย ข้อมูลสำหรับชนิด %{type} ที่กำกับด้วยรหัส %{id} ใช้เวลานานเกินสมควรในการเรียกดู + type: + node: หมุด + way: เส้นทาง + relation: ความสัมพันธ์ + changeset: ชุดการเปลี่ยนแปลง + note: หมายเหตุ + redacted: + redaction: การตรวจทาน %{id} + message_html: รุ่นที่ %{version} ชนิด %{type} ไม่สามารถแสดงว่าถูกตรวจทานมาแล้ว + โปรดไปที่ %{redaction_link} เพื่อดูรายละเอียด + type: + node: หมุด + way: เส้นทาง + relation: ความสัมพันธ์ + start_rjs: + feature_warning: กำลังโหลดส่วนประกอบจำนวน %{num_features} ส่วน การนี้ทำให้เบราว์เซอร์ของท่านทำงานช้าหรือไม่ตอบสนอง + ท่านแน่ใจหรือไม่ที่จะแสดงข้อมูลนี้? + load_data: กำลังโหลดข้อมูล + loading: กำลังโหลด... + tag_details: + tags: ป้ายกำกับ + wiki_link: + key: หน้าคำอธิบายวิกิาสำหรับป้ายระบุ %{key} + tag: หน้าคำอธิบายวิกิาสำหรับป้ายระบุ %{key}=%{value} + wikidata_link: รายการ %{page} ที่วิกิข้อมูล + wikipedia_link: บทความ %{page} ที่วิกิพีเดีย + telephone_link: โทรศัพท์ไปเลขหมาย %{phone_number} + note: + title: 'หมายเหตุ: %{id}' + new_note: หมายเหตุใหม่ + description: คำอธิบาย + open_title: 'บันทึกยังไม่ตอบสนอง #%{note_name}' + closed_title: บันทึกตอบสนองแล้ว %{note_name} + hidden_title: 'บันทึกที่ถูกซ่อน #%{note_name}' + open_by: จัดทำโดย %{user} เมื่อ %{when} ก่อน + open_by_anonymous: จัดทำโดยผู้ไม่ประสงค์ออกนามเมื่อ %{when} + ก่อน + commented_by: ความเห็นจาก %{user} เมื่อ %{when} + ก่อน + commented_by_anonymous: ความเห็นจากผู้ไม่ประสงค์ออกนามเมื่อ %{when} + ก่อน + closed_by: แก้ไขโดย %{user} เมื่อ %{when} ก่อน + closed_by_anonymous: แก้ไขโดยผู้ไม่ประสงค์ออกนามเมื่อ %{when} + ก่อน + reopened_by: เปิดใช้ซ้ำโดย %{user} เมื่อ %{when} + ก่อน + reopened_by_anonymous: เปิดใช้ซ้ำโดยผู้ไม่ประสงค์ออกนาม เมื่อ %{when} + ก่อน + hidden_by: ซ่อนโดย %{user} เมื่อ %{when} ก่อน + query: + title: คุณสมบัติการสอบถาม + introduction: คลิกที่แผนที่เพื่อค้นหาคุณสมบัติต่าง ๆ ที่อยู่ใกล้เคียง + nearby: คุณสมบัติที่อยู่ใกล้เคียง + enclosing: คุณสมบัติที่ปิดล้อม + changeset: + changeset_paging_nav: + showing_page: หน้า %{page} + next: ถัดไป » + previous: « ก่อนหน้า + changeset: + anonymous: ผู้ไม่ประสงค์ออกนาม + no_edits: (ไม่มีรายการแก้ไข) + view_changeset_details: ดูรายละเอียดชุดการเปลี่ยนแปลง + changesets: + id: รหัส + saved_at: บันทึกที่ + user: ผู้ใช้ + comment: ความเห็น + area: พื้นที่ + list: + title: ชุดการเปลี่ยนแปลง + title_user: ชุดการเปลี่ยนแปลงที่ทำโดย %{user} + title_friend: ชุดการเปลี่ยนแปลงที่ทำโดยเพื่อนของท่าน + title_nearby: ชุดการเปลี่ยนแปลงที่ทำโดยผู้ใช้ที่อยู่ใกล้เคียง + empty: ไม่พบชุดการเปลี่ยนแปลง + empty_area: ไม่พบชุดการเปลี่ยนแปลงในพื้นที่นี้ + empty_user: ผู้ใช้นี้ไม่มีชุดการเปลี่ยนแปลง + no_more: ไม่พบชุดการเปลี่ยนแปลงอีก + no_more_area: ไม่พบชุดการเปลี่ยนแปลงอีกในพื้นที่นี้ + no_more_user: ไม่พบชุดการเปลี่ยนแปลงอีกโดยผู้ใช้คนนี้ + load_more: แสดงเพิ่มขึ้น + timeout: + sorry: ขออภัย รายการชุดการเปลี่ยนแปลงที่ท่านร้องขอใช้เวลานานเกินสมควรในการสืบค้น + rss: + title_all: การสนทนาชุดการเปลี่ยนแปลงของ OpenStreetMap + title_particular: 'การอภิปรายชุดการเปลี่ยนแปลง OpenStreetMap #%{changeset_id}' + comment: 'ความคิดเห็นใหม่ที่มีต่อชุดการเปลี่ยนแปลง #%{changeset_id} โดย %{author}' + commented_at_html: ปรับปรุงเมื่อ %{when} ก่อน + commented_at_by_html: ปรับปรุงเมื่อ %{when} ก่อน โดย %{user} + full: การสนทนาแบบเต็ม + diary_entry: + new: + title: สร้างบันทึกใหม่ + publish_button: เผยแพร่ + list: + title: บันทึกของผู้ใช้ + title_friends: บันทึกของเพื่อน + title_nearby: บันทึกของผู้ใช้ที่อยู่ใกล้เคียง + user_title: บันทึกของ %{user} + in_language_title: รายการบันทึกทั้งหมดในภาษา %{language} + new: สร้างบันทึกใหม่ + new_title: สร้างบันทึกใหม่ในสมุดบันทึกประจำตัวของท่าน + no_entries: ไม่มีรายการบันทึก + recent_entries: รายการบันทึกล่าสุด + older_entries: รายการก่อนหน้า + newer_entries: รายการใหม่กว่า + edit: + title: แก้ไขรายการบันทึก + subject: 'เรื่อง:' + body: 'เนื้อหา:' + language: 'ภาษา:' + location: 'ที่ตั้ง:' + latitude: 'ละติจูด:' + longitude: 'ลองจิจูด:' + use_map_link: ใช้แผนที่ + save_button: บันทึก + marker_text: ที่ตั้งของรายการบันทึก + view: + title: บันทึกของ %{user} | %{title} + user_title: บันทึกของ %{user} + leave_a_comment: แสดงความคิดเห็น + login_to_leave_a_comment: '%{login_link} เพื่อแสดงความคิดเห็น' + login: ลงชื่อเข้าใช้ + save_button: บันทึก + no_such_entry: + title: ไม่มีรายการบันทึกที่ระบุ + heading: 'ไม่มีรายการรหัส: %{id}' + body: ขออภัย ไม่พบรายการบันทึกหรือข้อคิดเห็นที่กำกับด้วยรหัส %{id} โปรดตรวจการสะกดของท่าน + หรือถ้าไม่เป็นผลแสดงว่าลิงก์ที่ท่านคลิกมาผิดพลาด + diary_entry: + posted_by: ประกาศโดย %{link_user} เมื่อ %{created} ในภาษา %{language_link} + comment_link: แสดงความคิดเห็นต่อรายการนี้ + reply_link: ตอบกลับข้อความรายการนี้ + comment_count: + zero: ไม่มีข้อคิดเห็น + one: '%{count} ข้อคิดเห็น' + other: '%{count} ข้อคิดเห็น' + edit_link: แก้ไขรายการนี้ + hide_link: ซ่อนรายการนี้ + confirm: ยืนยัน + diary_comment: + comment_from: ความคิดเห็นจาก %{link_user} เมื่อ %{comment_created_at} + hide_link: ซ่อนข้อคิดเห็นนี้ + confirm: ยืนยัน + location: + location: 'ที่ตั้ง:' + view: ดู + edit: แก้ไข + feed: + user: + title: รายการบันทึก OpenStreetMap สำหรับผู้ใช้ %{user} + description: รายการบันทึกล่าสุด OpenStreetMap จากผู้ใช้ %{user} + language: + title: รายการบันทึก OpenStreetMap ในภาษา%{language_name} + description: รายการบันทึกล่าสุดจากผู้ใช้ OpenStreetMap ในภาษา%{language_name} + all: + title: รายการบันทึก OpenStreetMap + description: รายการบันทึกล่าสุดจากผู้ใช้ OpenStreetMap + comments: + has_commented_on: '%{display_name} ได้แสดงความคิดเห็นต่อรายการบันทึกต่อไปนี้' + post: เผยแพร่ + when: เมื่อ + comment: ความเห็น + ago: เมื่อ %{ago} ก่อน + newer_comments: ความคิดเห็นใหม่กว่า + older_comments: ความคิดเห็นเก่ากว่า + export: + title: ส่งออก + start: + area_to_export: พื้นที่ที่จะส่งออก + manually_select: เลือกพื้นที่อื่นด้วยตนเอง + format_to_export: รูปแบบที่จะส่งออก + osm_xml_data: ข้อมูล XML ของ OpenStreetMap + map_image: ภาพแผนที่ (แสดงชั้นภาพมาตรฐาน) + embeddable_html: HTML ฝังตัวได้ + licence: สัญญาอนุญาต + export_details: บรรดาข้อมูลที่ปรากฏในเว็บไซต์ OpenStreetMap อนุญาตให้ใช้ภายใต้สัญญาอนุญาต Open Data + Commons Open Database (ODbL). + too_large: + advice: 'ถ้าการส่งออกข้างต้นล้มเหลว โปรดพิจารณาใช้แหล่งข้อมูลตามที่ระบุด้านล่างนี้:' + body: พื้นที่ใหญ่เกินกว่าที่จะส่งออกเป็นข้อมูล XML ของ OpenStreetMap โปรดขยายเข้าหรือเลือกพื้นที่ที่เล็กลง + หรืออาจจะใช้แหล่งข้อมูลข้างล่างในการดาวน์โหลดแฟ้มข้อมูลจำนวนมาก + planet: + description: สำเนาของฐานข้อมูล OpenStreetMap ซึ่งปรับปรุงอย่างสม่ำเสมอ + geofabrik: + description: รายการทวีป ประเทศ และเมืองสำคัญซึ่งปรับปรุงอย่างสม่ำเสมอ + metro: + title: เมโทรเอกซ์แทรกซ์ + description: รายการเมืองสำคัญของโลกและพื้นที่โดยรอบ + other: + title: แหล่งข้อมูลอื่น + description: แหล่งข้อมูลอื่นตามที่ระบุไว้ใน OpenStreetMap wiki + options: ตัวเลือก + format: รูปแบบ + scale: มาตราส่วน + max: ขนาดสูงสุด + image_size: ขนาดภาพ + zoom: ย่อ-ขยาย + add_marker: เพิ่มเครื่องหมายลงในแผนที่ + latitude: 'ละติจูด:' + longitude: 'ลองจิจูด:' + output: การแสดงผล + paste_html: วาง HTML สำหรับนำไปใช้ในเว็บไซต์ + export_button: ส่งออก + geocoder: + search: + title: + latlon: ผลการค้นหาจาก เว็บไซต์นี้ + uk_postcode: ผลการค้นหาจาก NPEMap / FreeThe + Postcode + ca_postcode: ผลการค้นหาจาก Geocoder.CA + osm_nominatim: ผลการค้นหาจาก OpenStreetMap + Nominatim + geonames: ผลการค้นหาจาก GeoNames + osm_nominatim_reverse: ผลการค้นหาจาก OpenStreetMap + Nominatim + geonames_reverse: ผลการค้นหาจาก GeoNames + search_osm_nominatim: + prefix: + aerialway: + cable_car: รถกระเช้า + chair_lift: รถกระเช้าเปลือย + drag_lift: ลิฟต์ลากสกี + gondola: รถกระเช้า + station: สถานีรถกระเช้า + aeroway: + aerodrome: สนามบิน (ทุกประเภท) + apron: ลานจอดเครื่องบิน + gate: ประตูขึ้นเครื่อง + helipad: ลานจอดเฮลิคอปเตอร์ + runway: ทางวิ่งเครื่องบิน + taxiway: ทางขับเครื่องบิน + terminal: อาคารผู้โดยสาร + amenity: + animal_shelter: สถานสงเคราะห์สัตว์ + arts_centre: ศูนย์ศิลปะ + atm: บริการเงินสดด่วน + bank: ธนาคาร + bar: ร้านสุรา + bbq: ร้านอาหารย่าง + bench: ม้านั่ง + bicycle_parking: ที่จอดจักรยาน + bicycle_rental: บริการเช่าจักรยาน + biergarten: สวนเบียร์ + boat_rental: บริการเช่าเรือ + brothel: สถานบริการทางเพศ + bureau_de_change: ร้านรับแลกเงินตรา + bus_station: สถานีขนส่ง + cafe: ร้านกาแฟ + car_rental: บริการเช่ารถยนต์ + car_sharing: บริการร่วมเดินทาง + car_wash: บริการรับล้างรถ + casino: บ่อนไพ่ + charging_station: สถานีประจุไฟฟ้า + childcare: สถานรับเลี้ยงเด็ก + cinema: โรงภาพยนตร์ + clinic: คลินิก + clock: นาฬิกา + college: วิทยาลัย + community_centre: ศูนย์รวมชุมชน + courthouse: ศาล + crematorium: ฌาปนสถาน + dentist: ทันตแพทย์ + doctors: แพทย์ + dormitory: หอพักนักศึกษา + drinking_water: น้ำดื่ม + driving_school: สถานสอนขับรถ + embassy: สถานทูต + emergency_phone: โทรศัพท์ฉุกเฉิน + fast_food: อาหารจานด่วน + ferry_terminal: สถานีเรือข้ามฟาก + fire_hydrant: จุดรับน้ำดับเพลิง + fire_station: สถานดับเพลิง + food_court: ศูนย์อาหาร + fountain: น้ำพุ + fuel: สถานีบริการเชื้อเพลิง + gambling: การพนัน + grave_yard: สุสาน + gym: สถานออกกำลังกาย + health_centre: ศูนย์สุขภาพ + hospital: โรงพยาบาล + hunting_stand: บังไพรล่าสัตว์ + ice_cream: ร้านไอศกรีม + kindergarten: โรงเรียนอนุบาล + library: ห้องสมุด + market: ตลาด + marketplace: ตลาดนัด + monastery: วัดหรือโบสถ์ + motorcycle_parking: ที่จอดรถจักรยานยนต์ + nightclub: สถานบริการ + nursery: สถานรับเลี้ยงเด็ก + nursing_home: สถานสงเคราะห์หรือบ้านพักคนชรา + office: สำนักงาน + parking: ที่จอดรถ + parking_entrance: ทางเข้าที่จอดรถ + pharmacy: ร้านขายยา + place_of_worship: สถานที่ประกอบพิธีทางศาสนา + police: สถานีตำรวจ + post_box: ตู้ไปรษณีย์ + post_office: ที่ทำการไปรษณีย์ + preschool: โรงเรียนชั้นประถมวัย + prison: ทัณฑสถาน + pub: ร้านอาหาร + public_building: อาคารสาธารณะ + reception_area: พื้นที่ต้อนรับ + recycling: จุดรีไซเคิล + restaurant: ร้านอาหาร + retirement_home: บ้านพักวัยเกษียณ + sauna: สถานที่อบตัว + school: โรงเรียน + shelter: สถานที่พักพิง + shop: ร้านค้า + shower: สถานที่อาบน้ำ + social_centre: ศูนย์พบปะสมาคม + social_club: สโมสรพบปะ + social_facility: สโมสรพบปะ + studio: สถานที่บันทึกภาพและเสียง + swimming_pool: สระว่ายน้ำ + taxi: รถแท็กซี่ + telephone: โทรศัพท์สาธารณะ + theatre: โรงภาพยนตร์ + toilets: ห้องน้ำสาธารณะ + townhall: ศาลาว่าการเมือง + university: มหาวิทยาลัย + vending_machine: เครื่องขายสินค้า + veterinary: คลินิกสัตวแพทย์ + village_hall: ศาลากลางหมู่บ้าน + waste_basket: ถังขยะ + waste_disposal: ที่ทิ้งขยะ + youth_centre: ศูนย์เยาวชน + boundary: + administrative: ขอบเขตการปกครอง + census: ขอบเขตการสำรวจประชากร + national_park: อุทยานแห่งชาติ + protected_area: พื้นที่ปกป้อง + bridge: + aqueduct: สะพานส่งน้ำ + suspension: สะพานแขวน + swing: สะพานหันข้าง + viaduct: สะพานบก + "yes": สะพาน + building: + "yes": อาคาร + craft: + brewery: โรงทำสุรา + carpenter: ช่างไม้ + electrician: ช่างไฟฟ้า + gardener: คนสวน + painter: ช่างทาสี + photographer: นักถ่ายภาพ + plumber: ช่างท่อประปา + shoemaker: ช่างทำรองเท้า + tailor: ช่างตัดเสื้อผ้า + "yes": ร้านงานฝีมือ + emergency: + ambulance_station: สถานีรถพยาบาล + defibrillator: เครื่องช่วยกระตุ้นหัวใจ + landing_site: พื้นที่ลงจอดฉุกเฉิน + phone: โทรศัพท์ฉุกเฉิน + highway: + abandoned: ทางหลวงที่เลิกใช้แล้ว + bridleway: ทางเกวียน + bus_guideway: ทางรถสาธารณะชนิดบังคับล้อได้ + bus_stop: ที่หยุดรถสาธารณะ + construction: ทางหลวงกำลังสร้าง + cycleway: ทางจักรยาน + elevator: ลิฟต์ + emergency_access_point: จุดเข้าถึงฉุกเฉิน + footway: ทางเดินเท้า + ford: ถนนตัดทางน้ำ + living_street: ถนนใช้ร่วมรถและคน + milestone: หลักไมล์ + motorway: ทางหลวงพิเศษ + motorway_junction: แยกทางหลวงพิเศษ + motorway_link: ถนนทางหลวงพิเศษ + path: เส้นทาง + pedestrian: ทางคนเดิน + platform: ชานชาลา + primary: ถนนสายหลัก + primary_link: ถนนสายหลัก + proposed: ถนนที่เสนอให้สร้าง + raceway: ลานแข่งรถ + residential: ถนนในเขตที่พักอาศัย + rest_area: จุดแวะพัก + road: ถนน + secondary: ถนนสายรอง + secondary_link: ถนนสายรอง + service: ถนนสำหรับซ่อมบำรุง + services: บริการทางหลวงพิเศษ + speed_camera: กล้องจับความเร็ว + steps: ขั้น + street_lamp: ไฟส่องทาง + tertiary: ถนนสายย่อย + tertiary_link: ถนนสายย่อย + track: ราง + traffic_signals: สัญญาณจราจร + trail: ทางเดิน + trunk: ถนนสายประธาน + trunk_link: ถนนสายประธาน + unclassified: ถนนที่มิได้จำแนก + unsurfaced: ถนนที่ยังไม่ปูลาด + "yes": ถนน + historic: + archaeological_site: สถานที่ทางโบราณคดี + battlefield: สนามรบ + boundary_stone: หินแสดงขอบเขต + building: อาคารประวัติศาสตร์ + bunker: บังเกอร์ + castle: ปราสาท + church: โบสถ์ + city_gate: ประตูเมือง + citywalls: กำแพงเมือง + fort: ป้อม + heritage: สถานที่มรดก + house: บ้าน + icon: ไอคอน + manor: บ้านสวน + memorial: อนุสรณ์ + mine: เหมือง + monument: อนุสาวรีย์ + roman_road: ถนนโรมัน + ruins: ซากโบราณสถาน + stone: หลักหิน + tomb: สุสาน + tower: หอคอย + wayside_cross: กางเขนข้างทาง + wayside_shrine: ศาลเจ้าข้างทาง + wreck: ซากปรักหักพัง + junction: + "yes": ทางแยก + landuse: + allotments: ที่ดินแบ่งใช้ + basin: แอ่ง + brownfield: พื้นที่อุตสาหกรรมเดิม + cemetery: สุสาน + commercial: พื้นที่พาณิชยกรรม + conservation: การอนุรักษ์ + construction: การก่อสร้าง + farm: ไร่นา + farmland: ไร่นา + farmyard: ลานไร่นา + forest: ป่า + garages: โรงรถ + grass: หญ้า + greenfield: พื้นที่สีเขียว + industrial: พื้นที่อุตสาหกรรม + landfill: บ่อขยะ + meadow: ทุ่งหญ้า + military: เขตทหาร + mine: เหมือง + orchard: สวนผลไม้ + quarry: บ่อขุดหิน + railway: ทางรถไฟ + recreation_ground: สนามสำหรับเล่น + reservoir: อ่างเก็บน้ำ + reservoir_watershed: สันปันน้ำ + residential: เขตที่พักอาศัย + retail: ร้านค้าขายปลีก + road: พื้นที่ถนน + village_green: ลานหญ้าในเขตหมู่บ้าน + vineyard: ไร่องุ่น + "yes": การใช้ประโยชน์ที่ดิน + leisure: + beach_resort: สถานตากอากาศชายหาด + bird_hide: บังไพรดูนก + club: สโมสร + common: พื้นที่สาธารณประโยชน์ + dog_park: สวนสุนัข + fishing: พื้นที่ตกปลา + fitness_centre: ศูนย์ออกกำลังกาย + fitness_station: ศูนย์ออกกำลังกาย + garden: สวน + golf_course: สนามกอล์ฟ + horse_riding: สนามม้า + ice_rink: ลานสเก็ตน้ำแข็ง + marina: ที่จอดเรือ + miniature_golf: สนามกอล์ฟเล็ก + nature_reserve: พื้นที่สงวนธรรมชาติ + park: สวน + pitch: ลานกีฬา + playground: สนามเด็กเล่น + recreation_ground: สนามสำหรับเล่น + resort: สถานที่พักผ่อน + sauna: สถานที่อบตัว + slipway: ทางลาดสำหรับเรือ + sports_centre: ศูนย์กีฬา + stadium: สนามกีฬา + swimming_pool: สระว่ายน้ำ + track: ทางวิ่ง + water_park: สวนน้ำ + "yes": สถานที่เพื่อนันทนาการ + man_made: + lighthouse: ประภาคาร/กระโจมไฟ + pipeline: ท่อส่งน้ำมัน + tower: หอคอย + works: โรงงาน + "yes": ที่มนุษย์สร้างขึ้น + military: + airfield: สนามบินทหาร + barracks: โรงทหาร + bunker: หลุมหลบภัย + mountain_pass: + "yes": ช่องเขา + natural: + bay: อ่าว + beach: หาด + cape: ถ้ำ + cave_entrance: ทางเข้าถ้ำ + cliff: หน้าผา + crater: หลุมอุกกาบาต + dune: เนินทราย + fell: ทุ่งหญ้า + fjord: ฟยอร์ด + forest: ป่าดิบ + geyser: น้ำพุร้อน + glacier: ธารน้ำแข็ง + grassland: ทุ่งหญ้า + heath: ทุ่งไม้พุ่ม + hill: เนินเขา + island: เกาะ + land: ที่ดิน + marsh: ที่ลุ่มน้ำขัง + moor: ทุ่งหญ้าที่สูง + mud: โคลน + peak: ยอดเขา + point: จุด + reef: แนวปะการัง + ridge: สันเขา + rock: หลักหิน + saddle: หุบโค้ง + sand: ทราย + scree: ลาดหินร่วง + scrub: ป่าไม้พุ่ม + spring: น้ำพุ + stone: หลักหิน + strait: ช่องแคบ + tree: ต้นไม้ + valley: หุบผา + volcano: ภูเขาไฟ + water: น้ำ + wetland: พื้นที่ชุ่มน้ำ + wood: ไม้ + office: + accountant: นักบัญชี + administrative: การปกครอง + architect: สถาปนิก + company: บริษัท + employment_agency: บริษัทจัดหางาน + estate_agent: บริษัทอสังหาริมทรัพย์ + government: สำนักงานของรัฐบาล + insurance: สำนักงานประกันภัย + lawyer: ทนายความ + ngo: สำนักงานองค์กรเอกชน + telecommunication: ที่ทำการโทรคมนาคม + travel_agent: ตัวแทนการเดินทาง + "yes": สำนักงาน + place: + allotments: ที่ดินแบ่งใช้ + block: ช่วงตึก + airport: สนามบิน + city: เมือง + country: ประเทศ + county: จังหวัด + farm: ไร่นา + hamlet: ชุมชนขนาดเล็ก + house: บ้าน + houses: บ้าน + island: เกาะ + islet: เกาะขนาดเล็ก + isolated_dwelling: ที่อยู่อาศัยโดด + locality: ชุมชน + moor: ทุ่งหญ้าที่สูง + municipality: เทศบาล + neighbourhood: ชุมชน + postcode: รหัสไปรษณีย์ + region: ภูมิภาค + sea: ทะเล + state: รัฐ + subdivision: เขตการปกครองย่อย + suburb: ชานเมือง + town: เมือง + unincorporated_area: พื้นที่นอกเขตเทศบาล + village: หมู่บ้าน + "yes": สถานที่ + railway: + abandoned: ทางรถไฟที่เลิกใช้แล้ว + construction: ทางรถไฟกำลังสร้าง + disused: ทางรถไฟเลิกใช้แล้ว + disused_station: สถานีรถไฟยุบแล้ว + funicular: รถไฟขึ้นลงเนิน + halt: ที่หยุดรถไฟ + historic_station: สถานีรถไฟในอดีต + junction: ชุมทางรถไฟ + level_crossing: ทางผ่านเสมอระดับ + light_rail: รถไฟเบา + miniature: รถไฟเล็ก + monorail: รถราวหรือโมโนเรล + narrow_gauge: รถไฟรางแคบ + platform: ชานชาลารถไฟ + preserved: ทางรถไฟที่อนุรักษ์ไว้ + proposed: ทางรถไฟที่เสนอให้สร้าง + spur: ทางรถไฟสายย่อย + station: สถานีรถไฟ + stop: ที่หยุดรถไฟ + subway: รถไฟใต้ดิน + subway_entrance: ทางเข้ารถไฟใต้ดิน + switch: ประแจรถไฟ + tram: ทางรถราง + tram_stop: ที่หยุดรถราง + shop: + alcohol: ร้านขายสุรา + antiques: ร้านขายของเก่า + art: ร้านขายงานศิลปะ + bakery: ร้านขายขนมอบ + beauty: ร้านเสริมสวย + beverages: ร้านขายเครื่องดื่ม + bicycle: ร้านขายและเช่าจักรยาน + books: ร้านขายหนังสือ + boutique: ร้านเสริมสวย + butcher: ร้านขายเนื้อ + car: ร้านรถยนต์ + car_parts: ร้านอะไหล่รถยนต์ + car_repair: ร้านรับซ่อมรถยนต์ + carpet: ร้านขายพรม + charity: ร้านการกุศล + chemist: ร้านขายยา + clothes: ร้านขายเสื้อผ้า + computer: ร้านคอมพิวเตอร์ + confectionery: ร้านขายขนมหวาน + convenience: ร้านสะดวกซื้อ + copyshop: ร้านถ่ายเอกสาร + cosmetics: ร้านขายเครื่องสำอาง + deli: ร้านขายอาหารพิเศษ + department_store: ห้างสรรพสินค้า + discount: ร้านสินค้าลดราคา + doityourself: ทำด้วยตัวท่านเอง + dry_cleaning: บริการซักแห้ง + electronics: ร้านอิเล็กทรอนิกส์ + estate_agent: บริษัทอสังหาริมทรัพย์ + farm: ร้านในไร่นา + fashion: ร้านแฟชั่น + fish: ร้านขายปลา + florist: ร้านขายดอกไม้ + food: ร้านขายอาหาร + funeral_directors: บริการจัดการศพ + furniture: เครื่องเรือน + gallery: สถานที่แสดงงานศิลปะ + garden_centre: ศูนย์การจัดสวน + general: ร้านค้าทั่วไป + gift: ร้านของขวัญ + greengrocer: ร้านขายผักผลไม้ + grocery: ร้านชำ + hairdresser: ร้านทำผม + hardware: ร้านวัสดุก่อสร้าง + hifi: เครื่องเสียง + insurance: ประกันภัย + jewelry: ร้านเครื่องประดับ + kiosk: ร้านแผงลอย + laundry: ร้านซักรีด + mall: ห้างสรรพสินค้าขนาดใหญ่ + market: ตลาด + mobile_phone: ร้านโทรศัพท์มือถือ + motorcycle: ร้านรถจักรยานยนต์ + music: ร้านดนตรี + newsagent: ร้านขายหนังสือพิมพ์ + optician: จักษุแพทย์ + organic: ร้านขายอาหารอินทรีย์ + outdoor: ร้านขายอุปกรณ์ผจญภัย + pet: ร้านขายสัตว์เลี้ยงและอุปกรณ์ + pharmacy: ร้านขายยา + photo: ร้านถ่ายภาพ + salon: ร้านทำผมสตรี + second_hand: ร้านขายของมือสอง + shoes: ร้านขายรองเท้า + shopping_centre: ห้างสรรพสินค้า + sports: ร้านขายอุปกรณ์กีฬา + stationery: ร้านขายเครื่องเขียน + supermarket: ห้างสรรพสินค้า + tailor: ช่างตัดเสื้อผ้า + toys: ร้านขายของเล่น + travel_agency: ตัวแทนการเดินทาง + video: ร้านขายภาพยนตร์ + wine: ร้านขายสุรา + "yes": ร้านค้า + tourism: + alpine_hut: กระท่อมป่าสน + apartment: อาคารชุด + artwork: งานศิลปะ + attraction: แหล่งท่องเที่ยว + bed_and_breakfast: เรือนพักพร้อมอาหาร + cabin: กระท่อม + camp_site: ลานตั้งค่าย + caravan_site: ลานจอดรถบ้าน + chalet: กระท่อมพักผ่อน/ชาเลต์ + gallery: สถานที่แสดงงานศิลปะ + guest_house: เรือนพัก + hostel: โรงแรมนอนรวม + hotel: โรงแรม + information: ประชาสัมพันธ์ + motel: โรงแรมสำหรับผู้เดินทาง + museum: พิพิธภัณฑ์ + picnic_site: สถานที่ปิกนิก + theme_park: สวนสนุก + viewpoint: จุดชมวิว + zoo: สวนสัตว์ + tunnel: + culvert: ท่อระบายน้ำ + "yes": อุโมงค์ + waterway: + artificial: ทางน้ำที่มนุษย์สร้าง + boatyard: ที่จอดเรือ + canal: คลอง + dam: เขื่อน + derelict_canal: คลองเลิกใช้แล้ว + ditch: คู + dock: แอ่งจอดเรือ + drain: ทางระบายน้่ำ + lock: แอ่งยกเรือ + lock_gate: ประตูแอ่งยกเรือ + mooring: หลักผูกเรือ + rapids: แก่ง + river: แม่น้ำ + stream: ลำธาร + wadi: หุบวาดี + waterfall: น้ำตก + weir: ฝาย + "yes": ทางน้ำ + admin_levels: + level2: แนวเขตประเทศ + level4: แนวเขตรัฐ + level5: แนวเขตภูมิภาค + level6: แนวเขตจังหวัด + level8: แนวเขตเมือง/อำเภอ + level9: แนวเขตหมู่บ้าน + level10: แนวเขตชานเมือง + description: + title: + osm_nominatim: ตำบลที่ตั้งจาก OpenStreetMap + Nominatim + geonames: ตำบลที่ตั้งจาก GeoNames + types: + cities: เมือง + towns: เมือง + places: สถานที่ + results: + no_results: ไม่พบผลลัพธ์ + more_results: ดูผลลัพธ์เพิ่ม + layouts: + logo: + alt_text: ตราสัญลักษณ์ OpenStreetMap + home: กลับไปที่ตำแหน่งบ้าน + logout: ออกจากระบบ + log_in: ลงชื่อเข้าใช้ + log_in_tooltip: ลงชื่อเข้าใช้ด้วยบัญชีที่มีอยู่แล้ว + sign_up: สมัครบัญชี + start_mapping: เริ่มการทำแผนที่ + sign_up_tooltip: สร้างบัญชีสำหรับการแก้ไข + edit: แก้ไข + history: ประวัติ + export: ส่งออก + data: ข้อมูล + export_data: ส่งออกข้อมูล + gps_traces: รอยทาง GPS + gps_traces_tooltip: จัดการรอยทาง GPS + user_diaries: บันทึกของผู้ใช้ + user_diaries_tooltip: ดูบันทึกของผู้ใช้ + edit_with: แก้ไขด้วย %{editor} + tag_line: แผนที่โลกวิกิ ใช้งานได้ไม่เสียค่าใช้จ่าย + intro_header: ยินดีต้อนรับสู่ OpenStreetMap! + intro_text: OpenStreetMap เป็นแผนที่โลกที่สร้างโดยผู้คนเช่นท่าน และใช้งานได้ไม่เสียค่าใช้จ่ายภายใต้สัญญาอนุญาตแบบเปิด + intro_2_create_account: สร้างบัญชีผู้ใช้ใหม่ + partners_html: เซิร์ฟเวอร์สนับสนุนโดย %{ucl}, %{bytemark}, %{ic}, และ%{partners}อื่น + ๆ + partners_ucl: ยูซีแอล (วิทยาลัยอุดมศึกษาลอนดอน) + partners_ic: วิทยาลัยอิมพีเรียลลอนดอน + partners_bytemark: ไบต์มาร์กโฮสติง + partners_partners: องค์กรพันธมิตร + osm_offline: ฐานข้อมูลของ OpenStreetMap กำลังออฟไลน์เพื่อให้สามารถดำเนินการบำรุงรักษาตามปกติได้ + osm_read_only: ฐานข้อมูลของ OpenStreetMap กำลังอยู่ในโหมดอ่านอย่างเดียวเพื่อให้สามารถดำเนินการบำรุงรักษาตามปกติได้ + donate: สนับสนุน OpenStreetMap โดย %{link} สมทบทุนปรับปรุงฮาร์ดแวร์ + help: วิธีใช้ + about: เกี่ยวกับ + copyright: ลิขสิทธิ์ + community: ชุมชน + community_blogs: บทความชุมชน + community_blogs_title: บทความเพื่อชุมชนจากสมาชิก OpenStreetMap + foundation: มูลนิธิ + foundation_title: มูลนิธิ OpenStreetMap + make_a_donation: + title: สนับสนุน OpenStreetMap โดยการบริจาคเงิน + text: บริจาค + learn_more: เรียนรู้เพิ่มเติม + more: เพิ่มเติม + license_page: + foreign: + title: เกี่ยวกับการแปลนี้ + text: หากมีข้อขัดแย้งจากากรตีความหน้าที่แปลนี้กับหน้าเดิมในภาษาอังกฤษ %{english_original_link} + ให้ถือภาษาอังกฤษเป็นสำคัญถูกต้องเสมอ + english_link: หน้าเดิมในภาษาอังกฤษ + native: + title: เกี่ยวกับหน้านี้ + text: ท่านกำลังเรียกดูหน้าข้อมูลลิขสิทธิ์ในภาษาอังกฤษ และสามารถกลับไปที่หน้าภาษา + %{native_link} หรือกลับไปยังแผนที่ที่ %{mapping_link}. + native_link: รุ่นภาษาTHIS_LANGUAGE_NAME_HERE + mapping_link: เริ่มการทำแผนที่ + legal_babble: + title_html: ลิขสิทธิ์และสัญญาอนุญาต + intro_1_html: |- + OpenStreetMap® เป็นข้อมูลเปิดให้ใช้งาน และอนุญาตให้ใช้งานภายใต้สัญญาอนุญาต Open Data + Commons Open Database License (ODbL) โดยมูลนิธิ OpenStreetMap (OSMF). + intro_2_html: "ท่านสามารถทำสำเนา แจกจ่าย แพร่ภาพ และปรับใช้ข้อมูลของเรา\nตราบเท่าที่ได้ระบุชื่อ + OpenStreetMap ตลอดจนผู้ร่วมจัดทำไว้ในคำขอบคุณหรือที่มา\nถ้าท่านปรับแก้ไขหรือสร้างสรรค์งานใหม่โดยใช้ข้อมูลของเราเป็นพื้น + ท่านสามารถ\nแจกจ่ายผลลัพธ์ที่ได้ภายใต้สัญญาอนุญาตเดียวกันเท่านั้น โปรดดู ข้อกำหนดทางกฎหมาย + \nซึ่งจะอธิบายสิทธิและหน้าที่ที่ท่านพึงมี" + intro_3_html: |- + ภาพร่าง ลายเส้นแผนที่ตามที่ปรากฏ และเอกสารกำกับ อนุญาตให้ใช้งานตามสัญญาอนุญาต Creative + Commons Attribution-ShareAlike 2.0 (CC BY-SA) + credit_title_html: วิธีการแสดงที่มาหรือคำขอบคุณ OpenStreetMap + credit_1_html: |- + เราจำเป็นต้องให้ท่านแสดงที่มาหรือคำขอบคุณแก่ “© ผู้ร่วมสร้างสรรค์ OpenStreetMap + ”. + credit_2_html: |- + ท่านจะต้องระบุให้ชัดเจนเจาะจงว่าข้อมูลอนุญาตให้ใช้ตามสัญญาอนุญาต Open + Database License และถ้ามีการนำรูปแผนที่ไปใช้ รูปนั้นอนุญาตให้ใช้ตามสัญญาอนุญาต + CC BY-SA ในการนี้อาจจะลิงก์ไปยังหน้า + ข้อมูลลิขสิทธิ์ + นอกจากนี้ (จำเป็นหากท่านจ่ายแจกข้อมูล OSM) ท่านสามารถลิงก์ไปยังสัญญาอนุญาตโดยตรง + ในสื่ออย่างอื่น อาทิ สิ่งพิมพ์ ซึ่งไม่สามารถลิงก์ข้อมูลได้แนะนำให้ระบุเพียง openstreetmap.org + และ/หรือ opendatacommons.org และ/หรือ creativecommons.org + more_title_html: ค้นหาเพิ่มเติม + contributors_title_html: ผู้ร่วมสร้างสรรค์ของเรา + contributors_at_html: |- + ออสเตรีย: มีข้อมูลจาก + Stadt Wien (under + CC BY), + Land Vorarlberg และ + Land Tirol (under CC BY AT with amendments). + contributors_ca_html: |- + แคนาดา: มีข้อมูลจาก + GeoBase®, GeoGratis (© Department of Natural + Resources Canada), CanVec (© Department of Natural + Resources Canada) และ StatCan (Geography Division, + Statistics Canada) + contributors_fi_html: |- + ฟินแลนด์: มีข้อมูลจาก + ฐานข้อมูลการสำรวจภูมิศาสตร์แห่งชาติฟินแลนด์และฐานข้อมูลอื่น + อนุญาตให้ใช้ตาม + สัญญาอนุญาต NLSFI. + contributors_fr_html: |- + ฝรั่งเศส: มีข้อมูลจากอธิบดีกรมภาษี ( + Direction Générale des Impôts) + contributors_gb_html: |- + สหราชอาณาจักร: มีข้อมูลจากกองแผนที่ Ordnance + Survey data © ลิขสิทธิ์ราชการและสิทธิ์แห่งฐานข้อมูล + 2010-12 + infringement_title_html: การละเมิดลิขสิทธิ์ + welcome_page: + title: ยินดีต้อนรับ! + basic_terms: + title: เงื่อนไขพื้นฐานสำหรับการทำแผนที่ + questions: + title: มีคำถามอีกหรือไม่? + paragraph_1_html: "OpenStreetMap มีสื่อสำหรับค้นคว้า สอบถาม ตอบคำถาม \nสนทนา + ตลอดจนจัดทำวิธีการสร้างแผนที่\nขอรับความช่วยเหลือที่นี่" + start_mapping: เริ่มการทำแผนที่ + add_a_note: + title: ไม่มีเวลาแก้ไขใช่ไหม? เพิ่มบันทึกเดี๋ยวนี้! + paragraph_1_html: หากท่านต้องการแก้ไขสิ่งต่าง ๆ ไม่มากนัก และไม่มีเวลาเข้าใช้ระบบและเรียนรู้วิธีแก้ไขมากนัก + อาจจะเพิ่มบันทึกแทนได้ + paragraph_2_html: |- + แค่ไปที่แผนที่ แล้วคลิกไอคอน บันทึก: + . จากนั้นจะมีเครื่องหมายมาที่แผนที่ให้ท่านลากไปยัง + ตำแหน่งที่ต้องการ ใส่ข้อความที่ต้องการ คลิกบันทึก จากนั้นผู้ใช้ท่านอื่นจะเข้ามาตรวจสอบ + fixthemap: + title: รายงานปัญหา/แก้ไขข้อผิดพลาดในแผนที่ + how_to_help: + title: วิธีการช่วยเหลือ + join_the_community: + title: เข้าร่วมเป็นสมาชิก + explanation_html: หากท่านประสบปัญหาเกี่ยวกับข้อมูลแผนที่ของเรา หรือพบข้อผิดพลาด + เช่น ถนนหายไป หรือมีข้อผิดพลาดด้านที่อยู่ วิธีที่ดีที่สุดคือสมัครเป็นสมาชิก + OpenStreetMap เพื่อดำเนินการแก้ไขด้วยตัวท่านเอง + help_page: + beginners_guide: + url: http://wiki.openstreetmap.org/wiki/Th:Beginners%27_guide + mailing_lists: + title: รายการอีเมลรับข่าวสาร + forums: + title: กระดานสนทนา + about_page: + next: ถัดไป + open_data_title: ข้อมูลเปิดเผย + open_data_html: |- + OpenStreetMap อนุญาตให้ใช้ตามหลักเกณฑ์ข้อมูลเปิดเผย โดยจะนำไปใช้ในวัตถุประสงค์อื่นใดก็ได้ + แต่ต้องแสดงที่มาหรือให้คำขอบคุณต่อ OpenStreetMap ตลอดจนผู้ร่วมสร้างสรรค์ ถ้าท่านปรับแก้ สร้างสรรค์ + หรือกระทำการให้เกิดสิ่งอื่นใดใหม่ขึ้นต่องานที่มีนี้ ท่านสามารถแจกจ่ายได้แต่เพียงภายใต้สัญญาอนุญาตเดิม โปรดดู + หน้าลิขสิทธิ์และสัญญาอนุญาต ถ้าต้องการรายละเอียดเพิ่ม + legal_title: ข้อกำหนดทางกฎหมาย + legal_html: "เว็บไซต์และบริการที่เกี่ยวข้องนี้ดำเนินการและบำรุงรักษาอย่างเป็นทางการโดย\nมูลนิธิ OpenStreetMap (OSMF) \nในนามสมาชิกทุกคน + การใช้บริการที่ดำเนินการโดย OSMF จะต้องอยู่ใต้เงื่อนไข\nการใช้งานที่ยอมรับได้ + และนโยบายความเป็นส่วนบุคคล\n
      + \nโปรดติดต่อ OSMF \nถ้าท่านมีข้อสงสัยเกี่ยวกับสัญญาอนุญาต + ข้อมูลลิขสิทธิ์ คำถามกฎหมายและประเด็นที่เกี่ยวข้อง" + partners_title: องค์กรพันธมิตร + notifier: + diary_comment_notification: + subject: '[OpenStreetMap] ผู้ใช้ %{user} แสดงความคิดเห็นต่อรายการบันทึก' + hi: เรียนคุณ %{to_user}, + header: 'ผู้ใช้ %{from_user} ได้แสดงความคิดเห็นต่อบันทึก OpenStreetMap หัวเรื่อง + %{subject}:' + footer: ท่านสามารถอ่านความคิดเห็นได้ที่ลิงก์ %{readurl} และแสดงความคิดเห็นตอบได้ที่ + %{commenturl} หรือตอบกลับได้ที่ %{replyurl} + message_notification: + hi: เรียนคุณ %{to_user}, + header: 'ผู้ใช้ %{from_user} ส่งข้อความหาท่านผ่านทาง OpenStreetMap โดยมีหัวเรื่อง + %{subject}:' + footer_html: ท่านสามารถอ่านข้อความที่ลิงก์ %{readurl} และถ้าต้องการสามารถตอบกลับที่ลิงก์ + %{replyurl} + friend_notification: + hi: เรียนคุณ %{to_user}, + subject: '[OpenStreetMap] %{user} เพิ่มท่านในรายการเพื่อน' + had_added_you: ผู้ใช้ %{user} เพิ่มท่านในรายการเพื่อนบน OpenStreetMap + see_their_profile: ท่านสามารถดูหน้าประวัติส่วนตัวของเขาได้ที่ %{userurl}. + befriend_them: นอกจากนี้ท่านสามารถเพิ่มเขาในรายการเพื่อนได้ที่ %{befriendurl}. + gpx_notification: + greeting: สวัสดี, + your_gpx_file: ดูเหมือนว่าแฟ้มข้อมูล GPX ของท่าน + with_description: มีคำอธิบาย + and_the_tags: 'และป้ายกำกับต่อไปนี้:' + and_no_tags: และไม่มีป้ายกำกับ + failure: + subject: '[OpenStreetMap] การนำเข้า GPX ล้มเหลว' + failed_to_import: 'การนำเข้าล้มเหลว เนื่องจาก:' + more_info_1: รายละเอียดเพิ่มเติมเกี่ยวกับข้อผิดพลาดและความล้มเหลวในการนำเข้า + GPX และวิธีการหลีกเลี่ยง + more_info_2: 'ทั้งหมดสามารถพบได้ที่:' + success: + subject: '[OpenStreetMap] การนำเข้า GPX เรียบร้อย' + loaded_successfully: การนำเข้าสำเร็จ มีจำนวนจุด %{trace_points} จุด จากที่เป็นไปได้ทั้งหมด + %{possible_points} จุด + signup_confirm: + subject: '[OpenStreetMap] ยินดีต้อนรับสู่ OpenStreetMap' + greeting: เรียนท่านผู้ใช้งาน + created: มีบางคน (ซึ่งอาจเป็นท่าน) ได้สร้างบัญชีผู้ใช้ใหม่ไว้ที่ %{site_url} + confirm: 'ก่อนที่ทางเราจะดำเนินการต่อไปได้ เราขอให้ท่านยืนยันว่า ท่านได้สมัครสมาชิกจริงหรือไม่ + ถ้าจริง ขอให้ท่านคลิกลิงก์ข้างล่างเพื่อยืนยันบัญชีของท่าน:' + welcome: หลังจากที่ยืนยันบัญชีของท่านแล้ว เราจะให้รายละเอียดเพิ่มเติมเพื่อให้ท่านเริ่มใช้งานเว็บไซต์ได้ต่อไป + email_confirm: + subject: '[OpenStreetMap] ยืนยันที่อยู่อีเมลของท่าน' + email_confirm_plain: + greeting: เรียนท่านผู้ใช้งาน + hopefully_you: มีบางคน (ซึ่งอาจเป็นท่าน) ประสงค์จะเปลี่ยนที่อยู่อีเมลที่รักษาไว้ที่ + %{server_url} เป็น %{new_address} + click_the_link: ถ้าเป็นท่านจริง ขอให้คลิกลิงก์ด้านล่างเพื่อยืนยันการเปลี่ยนแปลง + email_confirm_html: + greeting: เรียนท่านผู้ใช้งาน + hopefully_you: มีบางคน (ซึ่งอาจเป็นท่าน) ประสงค์จะเปลี่ยนที่อยู่อีเมลที่รักษาไว้ที่ + %{server_url} เป็น %{new_address} + click_the_link: ถ้าเป็นท่านจริง ขอให้คลิกลิงก์ด้านล่างเพื่อยืนยันการเปลี่ยนแปลง + lost_password: + subject: '[OpenStreetMap] คำขอเปลี่ยนรหัสผ่านใหม่' + lost_password_plain: + greeting: เรียนท่านผู้ใช้งาน + hopefully_you: มีบางคน (ซึ่งอาจเป็นท่าน) ขอเปลี่ยนรหัสผ่านซึ่งกำกับบัญชีผู้ใช้ + openstreetmap.org + click_the_link: หากเป็นท่านจริง โปรดคลิกลิงก์ข้างล่าง เพื่อดำเนินการเปลี่ยนรหัสผ่านใหม่ + lost_password_html: + greeting: เรียนท่านผู้ใช้งาน + hopefully_you: มีบางคน (ซึ่งอาจเป็นท่าน) ขอเปลี่ยนรหัสผ่านซึ่งกำกับบัญชีผู้ใช้ + openstreetmap.org + click_the_link: หากเป็นท่านจริง โปรดคลิกลิงก์ข้างล่าง เพื่อดำเนินการเปลี่ยนรหัสผ่านใหม่ + note_comment_notification: + anonymous: ผู้ใช้ไม่ระบุตัวตน + greeting: เรียนท่านผู้ใช้งาน + commented: + subject_own: '[OpenStreetMap] ผู้ใช้ %{commenter} แสดงความคิดเห็นต่อบันทึกของท่าน' + subject_other: '[OpenStreetMap] ผู้ใช้ %{commenter} แสดงความคิดเห็นต่อบันทึกที่ท่านสนใจ' + your_note: ผู้ใช้ %{commenter} ได้แสดงความคิดเห็นต่อบันทึกของท่านที่อยู่ใกล้กับ + %{place} + commented_note: ผู้ใช้ %{commenter} ได้แสดงความคิดเห็นต่อบันทึกที่ท่านแสดงความเห็นก่อนหน้านี้ + บันทึกนั้นอยู่ใกล้กับ %{place} + closed: + subject_own: '[OpenStreetMap] ผู้ใช้ %{commenter} ได้แก้ไขหรือสนองตอบต่อบันทึกของท่านหนึ่งฉบับแล้ว' + subject_other: '[OpenStreetMap] ผู้ใช้ %{commenter} ได้แก้ไขหรือสนองตอบต่อบันทึกที่ท่านสนใจ' + your_note: ผู้ใช้ %{commenter} ได้แก้ไขหรือสนองตอบต่อบันทึกของท่านที่อยู่ใกล้กับ + %{place} + commented_note: ผู้ใช้ %{commenter} ได้แก้ไขหรือสนองตอบต่อบันทึกที่ท่านแสดงความเห็นก่อนหน้านี้ + บันทึกนั้นอยู่ใกล้กับ %{place} + reopened: + subject_own: '[OpenStreetMap] ผู้ใช้ %{commenter} ได้ขอรื้อฟื้นหรือเปิดใช้งานบันทึกของท่าน' + subject_other: '[OpenStreetMap] ผู้ใช้ %{commenter} ได้ขอรื้อฟื้นหรือเปิดใช้งานบันทึกที่ท่านสนใจ' + your_note: ผู้ใช้ %{commenter} ได้แก้ไขหรือสนองตอบต่อบันทึกของท่านที่อยู่ใกล้กับ + %{place} + commented_note: ผู้ใช้ %{commenter} ได้แก้ไขหรือสนองตอบต่อบันทึกที่ท่านแสดงความเห็นก่อนหน้านี้ + บันทึกนั้นอยู่ใกล้กับ %{place} + details: รายละเอียดเพิ่มเติมเกี่ยวกับบันทึกสามารถหาได้ที่ %{url} + changeset_comment_notification: + hi: เรียนคุณ %{to_user}, + greeting: เรียนท่านผู้ใช้งาน + commented: + subject_own: '[OpenStreetMap] ผู้ใช้ %{commenter} ได้แสดงความคิดเห็นต่อชุดการเปลี่ยนแปลงของท่าน' + subject_other: '[OpenStreetMap] ผู้ใช้ %{commenter} ได้แสดงความคิดเห็นต่อชุดการเปลี่ยนแปลงที่ท่านสนใจ' + your_changeset: ผู้ใช้ %{commenter} ได้แสดงความคิดเห็นต่อชุดการเปลี่ยนแปลงของท่านที่ทำไว้ + ณ เวลา %{time} + commented_changeset: ผู้ใช้ %{commenter} ได้แสดงความคิดเห็นต่อชุดการเปลี่ยนแปลงที่ท่านเฝ้าดู + ซึ่งสร้างโดยผู้ใช้ %{changeset_author} ณ เวลา %{time} + partial_changeset_with_comment: มีข้อคิดเห็น '%{changeset_comment}' + partial_changeset_without_comment: ไม่มีข้อคิดเห็น + details: รายละเอียดเพิ่มเติมเกี่ยวกับชุดการเปลี่ยนแปลงสามารถหาได้ที่ %{url} + unsubscribe: เพื่อบอกเลิกการรับข้อมูลการปรับปรุงชุดการเปลี่ยนแปลงนี้ โปรดไปนี้ + %{url} แล้วคลิก "เลิกรับข้อมูล". + message: + inbox: + title: จดหมายรับ + my_inbox: จดหมายรับส่วนตัว + outbox: จดหมายออก + messages: ท่านมี %{new_messages} และ %{old_messages} + new_messages: + one: ข้อความใหม่ %{count} ข้อความ + other: ข้อความใหม่ %{count} ข้อความ + old_messages: + one: ข้อความเก่า %{count} ข้อความ + other: ข้อความเก่า %{count} ข้อความ + from: จาก + subject: เรื่อง + date: วันที่ + no_messages_yet: ท่านยังไม่มีข้อความใด ๆ ทำไมไม่ลองติดต่อกับ%{people_mapping_nearby_link}บ้าง? + people_mapping_nearby: ผู้คนที่กำลังทำแผนที่ที่อยู่ใกล้เคียง + message_summary: + unread_button: ทำเครื่องหมายว่ายังไม่ได้อ่าน + read_button: ทำเครื่องหมายว่าอ่านแล้ว + reply_button: ตอบกลับ + delete_button: ลบ + new: + title: ส่งข้อความ + send_message_to: ส่งข้อความใหม่หาผู้ใช้ %{name} + subject: หัวเรื่อง + body: เนื้อหา + send_button: ส่ง + back_to_inbox: กลับไปที่กล่องจดหมายรับ + message_sent: ส่งข้อความแล้ว + limit_exceeded: เมื่อไม่นานมานี้ท่านส่งข้อความออกไปจำนวนมาก โปรดรอสักครู่ก่อนส่งข้อความต่อไป + no_such_message: + title: ไม่พบข้อความที่ระบุ + heading: ไม่พบข้อความที่ระบุ + body: ขออภัย ไม่พบข้อความที่กำกับด้วยรหัสดังกล่าว + outbox: + title: จดหมายออก + my_inbox: '%{inbox_link}ส่วนตัว' + inbox: จดหมายรับ + outbox: จดหมายออก + messages: + one: ท่านมีข้อความส่งแล้ว %{count} ฉบับ + other: ท่านมีข้อความส่งแล้ว %{count} ฉบับ + to: ถึง + subject: หัวเรื่อง + date: วันที่ + no_sent_messages: ท่านยังไม่มีข้อความใด ๆ ทำไมไม่ลองติดต่อกับ%{people_mapping_nearby_link}บ้าง? + people_mapping_nearby: ผู้คนที่กำลังทำแผนที่ที่อยู่ใกล้เคียง + reply: + wrong_user: ท่านเข้าระบบโดยใช้ชื่อผู้ใช้ `%{user}' แต่ข้อความที่ท่านกำลังจะตอบกลับไม่ได้ส่งถึงผู้ใช้ดังกล่าว + โปรดเข้าระบบใหม่โดยใช้ชื่อผู้ใช้นั้นเพื่อตอบกลับ + read: + title: อ่านข้อความ + from: จาก + subject: เรื่อง + date: วันที่ + reply_button: ตอบกลับ + unread_button: ทำเครื่องหมายว่ายังไม่ได้อ่าน + delete_button: ลบ + back: ย้อนกลับ + to: ถึง + wrong_user: ท่านเข้าระบบโดยใช้ชื่อผู้ใช้ `%{user}' แต่ข้อความที่ท่านกำลังจะตอบกลับไม่ได้ส่งโดยหรือส่งถึงผู้ใช้ดังกล่าว + โปรดเข้าระบบใหม่โดยใช้ชื่อผู้ใช้นั้นเพื่อตอบกลับ + sent_message_summary: + delete_button: ลบ + mark: + as_read: ข้อความถูกทำเครื่องหมายว่าอ่านแล้ว + as_unread: ข้อความถูกทำเครื่องหมายว่ายังไม่ได้อ่าน + delete: + deleted: ข้อความถูกลบแล้ว + site: + index: + js_1: ท่านกำลังใช้เบราว์เซอร์ที่ไม่รองรับจาวาสคริปต์ หรือท่านปิดใช้งานจาวาสคริปต์ + permalink: ลิงก์ถาวร + shortlink: ลิงก์ย่อ + createnote: เพิ่มบันทึก + edit: + not_public: ท่านยังไม่ได้ตั้งค่าการแก้ไขให้มองเห็นได้ทั่วไป + not_public_description: ท่านไม่สามารถแก้ไขแผนที่นี้ได้เว้นแต่จะดำเนินการสิ่งอื่นบางอย่าง + ท่านสามารถตั้งให้การแก้ไขของท่านมองเห็นได้ทั่วไปที่%{user_page} + user_page_link: หน้าผู้ใช้ + no_iframe_support: เบราว์เซอร์ของท่านไม่รองรับการใช้งานเฟรมภายในหน้า HTML จึงไม่สามารถใช้ส่วนประกอบนี้ได้ + sidebar: + search_results: ผลการค้นหา + close: ปิด + search: + search: ค้นหา + get_directions: ขอเส้นทาง + get_directions_title: ค้นหาเส้นทางระหว่างจุดสองจุด + from: จาก + to: ถึง + where_am_i: ข้าพเจ้าอยู่ที่ไหน? + where_am_i_title: อธิบายตำแหน่งปัจจุบันโดยใช้เครื่องมือค้นหา + submit_text: ไป + key: + table: + entry: + motorway: ทางหลวงพิเศษ + main_road: ถนนสายหลัก + trunk: ถนนสายประธาน + primary: ถนนสายหลัก + secondary: ถนนสายรอง + unclassified: ถนนที่มิได้จำแนก + track: รอยทาง + bridleway: ทางเกวียน + cycleway: ทางจักรยาน + cycleway_national: ทางจักรยานระดับประเทศ + cycleway_regional: ทางจักรยานระดับภูมิภาค + cycleway_local: ทางจักรยานระดับท้องถิ่น + footway: ทางเดินเท้า + rail: ทางรถไฟ + subway: รถไฟใต้ดิน + tram: + - รถไฟเบา + - รถราง + cable: + - รถกระเช้า + - รถกระเช้าเปลือย + runway: + - ทางวิ่งสนามบิน + - ทางขับเครื่องบิน + apron: + - โรงซ่อมบำรุงเครื่องบิน + - อาคารผู้โดยสาร + admin: ขอบเขตการปกครอง + forest: ป่า + wood: ไม้ + golf: สนามกอล์ฟ + park: สวน + resident: เขตที่พักอาศัย + common: + - ที่ส่วนกลาง + - ทุ่งหญ้า + retail: พื้นที่พาณิชยกรรม + industrial: พื้นที่อุตสาหกรรม + commercial: พื้นที่พาณิชยกรรม + heathland: ทุ่งไม้พุ่ม + lake: + - ทะเลสาบ + - อ่างเก็บน้ำ + farm: ไร่นา + brownfield: พื้นที่อุตสาหกรรมเดิม + cemetery: สุสาน + allotments: ที่ดินแบ่งใช้ + pitch: ลานกีฬา + centre: ศูนย์กีฬา + reserve: พื้นที่สงวนธรรมชาติ + military: เขตทหาร + school: + - โรงเรียน + - มหาวิทยาลัย + building: อาคารสำคัญ + station: สถานีรถไฟ + summit: + - ยอดเขา + - ยอดเขา + tunnel: เส้นประ = อุโมงค์ + bridge: เส้นทึบ = สะพาน + private: พื้นที่ส่วนบุคคล + destination: การเข้าถึงที่จุดปลายทาง + construction: ถนนกำลังก่อสร้าง + bicycle_shop: ร้านขายและเช่าจักรยาน + bicycle_parking: ที่จอดจักรยาน + toilets: ห้องน้ำสาธารณะ + richtext_area: + edit: แก้ไข + preview: แสดงตัวอย่าง + markdown_help: + title_html: ตัดอ่านโดย Markdown + headings: หัวเรื่องหลัก + heading: หัวเรื่องหลัก + subheading: หัวเรื่องย่อย + unordered: รายการไม่เรียงลำดับ + ordered: รายการเรียงลำดับ + first: รายการแรก + second: รายการที่สอง + link: ลิงก์ + text: ข้อความ + image: รูปภาพ + alt: ข้อความทดแทนภาพ + url: ที่อยู่ลิงก์ + trace: + visibility: + private: ส่วนตัว (เผยแพร่ในนามผู้ไม่ประสงค์ออกนาม แต่ละจุดไม่เรียงลำดับ) + public: สาธารณะ (แสดงในรายการรอยทาง และในนามผู้ไม่ประสงค์ออกนาม แต่ละจุดไม่เรียงลำดับ) + trackable: ติดตามได้ (แสดงในนามผู้ไม่ประสงค์ออกนาม แต่ละจุดมีเวลากำกับ) + identifiable: ระบุได้ (แสดงเป็นชื่อให้ติดตามได้ แต่ละจุดมีเวลากำกับ) + create: + upload_trace: อัปโหลดรอยทาง GPS + edit: + tags_help: คั่นด้วยจุลภาค + save_button: บันทึกการเปลี่ยนแปลง + visibility: 'สถานะการแสดง:' + visibility_help: นี่หมายความว่าอะไร? + trace_form: + upload_gpx: 'อัปโหลดแฟ้ม GPX:' + description: 'คำอธิบาย:' + tags: 'ป้ายกำกับ:' + tags_help: คั่นด้วยจุลภาค + visibility: 'สถานะการแสดง:' + visibility_help: นี่หมายความว่าอะไร? + upload_button: อัปโหลด + help: วิธีใช้ + trace_header: + upload_trace: อัปโหลดรอยทาง + see_all_traces: แสดงรอยทางทั้งหมด + see_your_traces: แสดงรอยทางของท่าน + list: + public_traces: รอยทาง GPS สาธารณะ + your_traces: รอยทาง GPS ของท่าน + user: + login: + openid_logo_alt: เข้าใช้งานด้วย OpenID + auth_providers: + openid: + title: เข้าใช้งานด้วย OpenID + alt: เข้าใช้งานด้วยลิงก์ OpenID + google: + title: เข้าใช้งานด้วย Google + alt: เข้าใช้งานด้วย Google OpenID + facebook: + title: เข้าใช้งานด้วย Facebook + alt: เข้าใช้งานด้วยบัญชี Facebook + windowslive: + title: เข้าใช้งานด้วย Windows Live + alt: เข้าใช้งานด้วยบัญชี Windows Live + logout: + title: ออกจากระบบ + logout_button: ออกจากระบบ + lost_password: + title: ตั้งรหัสผ่านใหม่ + heading: ลืมรหัสผ่านหรือ? + new password button: ตั้งรหัสผ่านใหม่ + new: + email address: 'ที่อยู่อีเมล:' + confirm email address: 'ยืนยันที่อยู่อีเมล:' + not displayed publicly: ที่อยู่ของท่านจะไม่แสดงให้บุคคลภายนอกเห็น โปรดดู นโบายความเป็นส่วนบุคคล ถ้าต้องการรายละเอียดเพิ่มเติม + display name: 'ชื่อที่ใช้แสดง:' + display name description: ชื่อที่แสดงต่อสาธารณะ ท่านสามารถเปลี่ยนในภายหลังได้ในหน้าการตั้งค่า + external auth: 'บัญชีผู้ใช้จากเว็บอื่น:' + password: 'รหัสผ่าน:' + confirm password: 'ยืนยันรหัสผ่าน:' + use external auth: นอกจากนี้ ท่านสามารถใช้บัญชีผู้ใช้จากเว็บอื่นในการเข้าใช้งานได้ + auth no password: ถ้ามีบัญชีผู้ใช้จากเว็บอื่น โดยปกติไม่จำเป็นต้องมีรหัสผ่าน + แต่ถ้าเข้าใช้งานเครื่องมือบางตัวหรือเซิร์ฟเวอร์ก็ยังจำเป็นต้องมีรหัสผ่านอยู่ + continue: สมัครบัญชี + terms accepted: ขอบคุณสำหรับการตอบรับเงื่อนไขผู้ร่วมสร้างสรรค์! + terms declined: ขออภัย ท่านมิได้ยอมรับเงื่อนไขผู้ร่วมสร้างสรรค์ เราจึงไม่สามารถดำเนินการต่อไปได้ + รายละเอียดเพิ่มเติมโปรดดูหน้านี้. + terms: + title: เงื่อนไขผู้ร่วมสร้างสรรค์ + heading: เงื่อนไขผู้ร่วมสร้างสรรค์ + read and accept: โปรดอ่านข้อตกลงต่อไปนี้และเลือกปุ่ม ยอมรับ เพื่อยืนยันว่าท่านยอมรับเงื่อนไขนี้ในการสร้างสรรค์ที่เคยทำมาและที่จะทำต่อไปในอนาคต + consider_pd: นอกเหนือจากข้อตกลงข้างต้น ข้าพเจ้ายินดีสละการสร้างสรรค์ของข้าพเจ้าให้เป็นงานอันไม่มีลิขสิทธิ์ + consider_pd_why: นี้คืออะไร? + agree: ยอมรับ + decline: ไม่ยอมรับ + legale_select: 'ประเทศที่พำนัก:' + legale_names: + france: ฝรั่งเศส + italy: อิตาลี + rest_of_world: พื้นที่อื่น ๆ ในโลก + no_such_user: + title: ไม่มีผู้ใช้ที่ระบุ + heading: ไม่พบผู้ใช้ชื่อ %{user} + view: + create_block: กีดกันผู้ใช้นี้ + activate_user: เปิดใช้งานผู้ใช้นี้ + deactivate_user: ปิดใช้งานผู้ใช้นี้ + account: + title: แก้ไขบัญชี + contributor terms: + link text: นี้คืออะไร? + profile description: 'คำอธิบายหน้าประวัติส่วนตัว:' + preferred languages: 'ภาษาที่ต้องการ:' + preferred editor: 'ตัวแก้ไขที่ต้องการใช้:' + image: 'รูปภาพ:' + gravatar: + gravatar: ใช้ Gravatar + link text: นี้คืออะไร? + disabled: Gravatar ถูกปิดใช้ + enabled: การแสดง Gravatar ของท่านถูกเปิดใช้ + new image: เพิ่มรูปภาพ + keep image: ใช้รูปภาพปัจจุบัน + delete image: ลบรูปภาพปัจจุบัน + replace image: เปลี่ยนรูปภาพปัจจุบัน + image size hint: (ภาพขนาดสี่เหลี่ยม 100x100 จะดีที่สุด) + home location: 'ที่อยู่บ้าน:' + no home location: ท่านยังไม่ได้ระบุที่อยู่บ้าน + latitude: 'ละติจูด:' + longitude: 'ลองจิจูด:' + update home location on click: แก้ไขที่อยู่บ้านถ้าคลิกแผนที่หรือไม่? + save changes button: บันทึกการเปลี่ยนแปลง + make edits public button: ทำให้การแก้ไขของข้าพเจ้าเป็นสาธารณะเห็นได้ทั่วไป + return to profile: กลับไปหน้าประวัติผู้ใช้ + flash update success confirm needed: การปรับปรุงข้อมูลผู้ใช้งานสำเร็จเรียบร้อย + โปรดตรวจสอบอีเมลของท่านเพื่อยืนยันที่อยู่อีเมลใหม่ + flash update success: การปรับปรุงข้อมูลผู้ใช้งานสำเร็จเรียบร้อย + confirm: + heading: โปรดตรวจสอบอีเมลของท่าน! + introduction_1: เราได้ส่งอีเมลยืนยันให้ท่านแล้ว + introduction_2: โปรดยืนยันบัญชีของท่านโดยคลิกลิงก์ในอีเมล หลังจากนั้นท่านสามารถเริ่มใช้งานแผนที่ได้ + press confirm button: คลิกปุ่ม ยืนยัน ข้างล่างเพื่อเปิดใช้บัญชีของท่าน + button: ยืนยัน + success: บัญชีของท่านยืนยันเสร็จแล้ว ขอบคุณสำหรับการสมัครใช้งาน! + already active: บัญชีนี้ได้ถูกยืนยันมาก่อนแล้ว + unknown token: รหัสยืนยันหมดอายุหรือผิดพลาด + reconfirm_html: ถ้าท่านต้องการให้เราส่งอีเมลยืนยันซ้ำ โปรดคลิกที่นี่. + confirm_resend: + success: เราได้ส่งบันทึกยืนยันใหม่ไปยังอีเมล %{email} เมื่อท่านยืนยันแล้ว จะสามารถเริ่มทำแผนที่ได้ทันที

      ถ้าท่านมีระบบป้องกันสแปม โปรดให้ %{sender} อยู่ในรายการปลอดภัย (whitelist) + เพราะเราไม่สามารถตอบอีเมลยืนยันใด ๆ ได้ + failure: ไม่พบผู้ใช้ %{name} + confirm_email: + heading: ยืนยันการเปลี่ยนแปลงที่อยู่อีเมล + press confirm button: คลิกปุ่ม ยืนยัน ข้างล่างเพื่อยืนยันที่อยู่อีเมลใหม่ + button: ยืนยัน + success: ยืนยันการเปลี่ยนแปลงที่อยู่อีเมลเรียบร้อย! + failure: อีเมลนี้ถูกยืนยันกับคำขอนี้เรียบร้อย + unknown_token: รหัสยืนยันหมดอายุหรือผิดพลาด + set_home: + flash success: ตำแหน่งที่อยู่บ้านบันทึกเรียบร้อย + go_public: + flash success: การแก้ไขของท่านเป็นสาธารณะ ท่านสามารถแก้ไขได้ + make_friend: + heading: เพิ่มผู้ใช้ %{user} ในรายการเพื่อนหรือไม่? + button: เพิ่มในรายการเพื่อน + success: ผู้ใช้ %{name} อยู่ในรายการเพื่อนของท่านเรียบร้อย! + failed: ขออภัย ไม่สามารถเพิ่มผู้ใช้ %{name} ในรายการเพื่อน + already_a_friend: ท่านมีผู้ใช้ %{name}ในรายการเพื่อนอยู่แล้ว + remove_friend: + heading: ต้องการลบผู้ใช้ %{user} ออกจากรายการเพื่อนหรือไม่? + button: ลบจากรายการเพื่อน + success: ท่านได้ลบผู้ใช้ %{name} ออกจากรายการเพื่อน + not_a_friend: ผู้ใช้ %{name} ไม่ได้อยู่ในรายการเพื่อนของท่าน + filter: + not_an_administrator: ท่านต้องเป็นผู้ดูแลระบบจึงจะสามารกระทำสิ่งนี้ได้ + list: + title: ผู้ใช้ + heading: ผู้ใช้ + showing: + one: หน้าที่ %{page} (%{first_item} จาก %{items}) + other: หน้าที่ %{page} (%{first_item}-%{last_item} จาก %{items}) + summary: '%{name} สร้างจากไอพี %{ip_address} เมื่อ %{date}' + suspended: + title: บัญชีถูกระงับ + heading: บัญชีถูกระงับ + webmaster: ผู้ดูแลเว็บ + body: |2- + +

      + ขออภัยอย่างสูง เนื่องจากมีการกระทำต้องสงสัย บัญชีของท่านถูกระงับโดยอัตโนมัติ +

      +

      + การดำเนินการอื่นใดจะถูกกลั่นกรองโดยผู้ดูแลเว็บในเวลาไม่นานจากนี้ หรืออาจจะชี้แจงต่อ%{webmaster}หากต้องการเหตุผล +

      + auth_failure: + connection_failed: การเชื่อมต่อกับผู้ให้บริการบัญชีภายนอกล้มเหลว + invalid_credentials: ชื่อผู้ใช้และ/หรือรหัสผ่านไม่ถูกต้อง + no_authorization_code: ไม่มีรหัสยืนยัน + unknown_signature_algorithm: ขั้นตอนวิธีลายมือชื่อไม่ทราบ + invalid_scope: ขอบข่ายผิดพลาด + auth_association: + heading: บัญชีภายนอกของท่านยังมิได้ต่อเชื่อมกับบัญชี OpenStreetMap + option_1: ถ้าท่านเป็นผู้ใช้ OpenStreetMap ใหม่ โปรดใช้แบบฟอร์มข้างล่างสร้างบัญชีผู้ใช้ + option_2: "ถ้าท่านมีบัญชีผู้ใช้แล้ว สามารถเข้าสู่ระบบโดยใช้ชื่อผู้ใช้ รหัสผ่าน + \nแล้วผูกโยงบัญชีกับบัญชีภายนอกในหน้าการตั้งค่าา" + user_role: + filter: + not_an_administrator: ท่านไม่ได้เป็นผู้ดูแลระบบ จึงไม่สามารถจัดการเรื่องแต่งตั้งถอดถอนสถานะของผู้ใช้งานได้ + not_a_role: ข้อความ `%{role}' ไม่ใช่สถานะผู้ใช้งานที่ถูกต้อง + already_has_role: ผู้ใช้มีสถานะเป็น %{role} อยู่แล้ว + doesnt_have_role: ผู้ใช้ไม่ได้มีสถานะ %{role} + grant: + title: ยืนยันการแต่งตั้งสถานะ + heading: ยืนยันการแต่งตั้งสถานะ + are_you_sure: ท่านแน่ใจว่าต้องการแต่งตั้งสถานะ `%{role}' แก่ผู้ใช้ `%{name}' + หรือไม่? + confirm: ยืนยัน + fail: ไม่สามารถแต่งตั้งสถานะ `%{role}' แก่ผู้ใช้ `%{name}' โปรดตรวจสอบว่าทั้งผู้ใช้และสถานะเป็นที่ถูกต้องดีแล้ว + revoke: + title: ยืนยันการถอดถอนสถานะ + heading: ยืนยันการถอดถอนสถานะ + are_you_sure: ท่านแน่ใจว่าต้องการถอดถอนสถานะ `%{role}' จากผู้ใช้ `%{name}' หรือไม่? + confirm: ยืนยัน + fail: ไม่สามารถถอดถอนสถานะ `%{role}' แก่ผู้ใช้ `%{name}' โปรดตรวจสอบว่าทั้งผู้ใช้และสถานะเป็นที่ถูกต้องดีแล้ว + javascripts: + share: + format: 'รูปแบบ:' + scale: 'ขนาด:' + map: + base: + cycle_map: แผนที่จักรยาน + transport_map: แผนที่การขนส่ง + hot: เพื่อมนุษยธรรม + layers: + header: ชั้นแผนที่ + notes: หมายเหตุแผนที่ + data: ข้อมูลแผนที่ + donate_link_text: + site: + edit_tooltip: แก้ไขแผนที่ + edit_disabled_tooltip: ขยายเพื่อแก้ไขแผนที่ + createnote_tooltip: เพิ่มบันทึกลงในแผนที่ + changesets: + show: + subscribe: บอกรับข้อมูล + unsubscribe: เลิกรับข้อมูล + directions: + instructions: + continue_without_exit: เคลื่อนต่อไปทางถนน %{name} + offramp_right_without_exit: ใช้ทางลาดด้านขวาไปที่ถนน %{name} + onramp_right_without_exit: เลี่ยวขวาที่ทางลาดไปที่ถนน %{name} + endofroad_right_without_exit: เมื่อถึงสุดถนนเลี้ยวขวาไปที่ถนน %{name} + merge_right_without_exit: เลี้ยวขวาเข้าสู่ถนน %{name} ซึ่งเป็นทางเอก + fork_right_without_exit: ที่ทางแยกเลี้ยวขวาไปที่ถนน %{name} + uturn_without_exit: วกกลับไปตามถนน %{name} + sharp_left_without_exit: เลี้ยวซ้ายหักไปที่ %{name} + turn_left_without_exit: เลี้ยวซ้ายไปที่ %{name} + offramp_left_without_exit: ใช้ทางลาดด้านซ้ายไปที่ %{name} + onramp_left_without_exit: เลี้ยวซ้ายบนทางลาดไปที่ถนน %{name} + endofroad_left_without_exit: เมื่อถึงสุดถนนเลี้ยวซ้ายไปที่ถนน %{name} + merge_left_without_exit: เลี้ยวซ้ายเข้าสู่ถนน %{name} ซึ่งเป็นทางเอก + fork_left_without_exit: ที่ทางแยกเลี้ยวซ้ายไปที่ถนน %{name} + slight_left_without_exit: ขยับซ้ายเล็กน้อยไปที่ %{name} + roundabout_with_exit: ณ วงเวียน ใช้ทางออก %{exit} ไปที่ถนน %{name} + turn_left_with_exit: ณ วงเวียน เลี้ยวซ้ายไปที่ถนน %{name} + slight_left_with_exit: ณ วงเวียน ขยับซ้ายไปที่ถนน %{name} + turn_right_with_exit: ณ วงเวียน เลี้ยวขวาไปที่ถนน %{name} + slight_right_with_exit: ณ วงเวียน ขยับขวาไปที่ถนน %{name} + continue_with_exit: ณ วงเวียน ตรงไปที่ถนน %{name} + unnamed: ถนนไม่มีชื่อ + courtesy: เอื้อเฟื้อเส้นทางโดย %{link} + time: เวลา + query: + node: หมุด + way: เส้นทาง + relation: ความสัมพันธ์ + nothing_found: ไม่พบส่วนประกอบ + error: 'มีความผิดพลาดขณะติดต่อ %{server}: %{error}' + timeout: หมดเวลาขณะพยายามติดต่อ %{server} + context: + directions_from: เส้นทางจากที่นี่ + directions_to: เส้นทางมาที่นี่ + add_note: เพิ่มบันทึกที่นี่ + show_address: แสดงที่อยู่ + query_features: สอบถามส่วนประกอบ + centre_map: วางแผนที่ตรงกลางที่นี่ + redaction: + edit: + description: คำอธิบาย + heading: แก้ไขการตรวจทาน + submit: บันทึกการตรวจทาน + title: แก้ไขการตรวจทาน + index: + empty: ไม่มีการตรวจทานให้แสดง + heading: รายการการตรวจทาน + title: รายการการตรวจทาน + new: + description: คำอธิบาย + heading: กรอกรายละเอียดการตรวจทานใหม่ + submit: สร้างการตรวจทาน + title: สร้างการตรวจทานใหม่ + show: + description: 'คำอธิบาย:' + heading: แสดงการตรวจทาน "%{title}" + title: แสดงการตรวจทาน + user: 'ผู้สร้าง:' + edit: แก้ไขการตรวจทานนี้ + destroy: ลบการตรวจทานนี้ + confirm: ท่านแน่ใจหรือไม่? + create: + flash: การตรวจทานสร้างเรียบร้อย + update: + flash: การเปลี่ยนแปลงบันทึกเรียบร้อย + destroy: + not_empty: การตรวจทานยังไม่ว่าง โปรดถอดการตรวจทานรุ่นเก่า ๆ ที่เกี่ยวเนื่องกับการตรวจทานนี้ก่อนลบทิ้ง + flash: การตรวจทานถูกลบแล้ว + error: มีความผิดพลาดขณะลบการตรวจทานนี้ +... diff --git a/config/locales/tl.yml b/config/locales/tl.yml index a7cf3f1c3..008482441 100644 --- a/config/locales/tl.yml +++ b/config/locales/tl.yml @@ -91,18 +91,31 @@ tl: editor: default: Likas na pagtatakda (kasalukuyang %{name}) potlatch: - name: Pagbibigay-daan 1 - description: Pagbibigay-daan 1 (patnugot na nasa loob ng pantingin-tingin) + name: Potlatch 1 + description: Potlatch 1 (patnugot na nasa loob ng pantingin-tingin) + id: + name: iD + description: iD (patnugot na nasa loob ng pantingin-tingin) potlatch2: - name: Pagbibigay-daan 2 - description: Pagbibigay-daan 2 (patnugot na nasa loob ng pantingin-tingin) + name: Potlatch 2 + description: Potlatch 2 (patnugot na nasa loob ng pantingin-tingin) remote: name: Pangmalayong Pantaban description: Pangmalayong Pantaban (JOSM o Merkaartor) browse: created: Nilikha closed: Isinara + created_html: Nilikha %{time} ang nakaraan + closed_html: Isinara %{time} ang nakaraan + created_by_html: Nilikha %{time} ang nakaraan ni + %{user} + deleted_by_html: Binura %{time} ang nakaraan ni + %{user} + edited_by_html: Binago %{time} ang nakaraan ni %{user} + closed_by_html: Isinara %{time} ang nakaraan ni + %{user} version: Bersyon + in_changeset: Pangkat ng pagbabago anonymous: Hindi nagpapakilala (anonimo) no_comment: (walang mga puna) part_of: Bahagi ng @@ -118,6 +131,7 @@ tl: feed: title: '%{id} ng pangkat ng pagbabago' title_comment: '%{id} ng angkat ng pagbabago - %{comment}' + join_discussion: Lumagda para sumali sa talakayan relation: members: Mga kasapi relation_member: @@ -131,7 +145,7 @@ tl: entry: Kaugnayan %{relation_name} entry_role: Kaugnayan %{relation_name} (bilang %{relation_role}) not_found: - sorry: Paumanhin, ang %{type} na may ID na %{id}, ay hindi matagpuan. + sorry: 'Paumanhin, %{type} #%{id} ay hindi matagpuan.' type: node: buko way: daan @@ -186,6 +200,8 @@ tl: title_friend: Mga pangkat ng pagbabago ng mga kaibigan mo title_nearby: Mga pangkat ng pagbabago ng kalapit na mga tagagamit empty: Walang natagpuang mga aparato/gadyet. + empty_user: Walang pangkat ng pagbabago mula sa tagagamit na ito. + no_more_area: Walang pangkat ng pagbabago sa lugar na ito. load_more: Magkarga pa timeout: sorry: Paumanhin, ang talaan ng mga pangkat ng pagbabagong hiniling mo ay naging @@ -235,7 +251,8 @@ tl: comment_link: Punahin ang pagpapasok na ito reply_link: Tumugon sa pagpapasok na ito comment_count: - one: 1 puna + zero: Wala pang mga puna + one: '%{count} puna' other: '%{count} mga puna' edit_link: Baguhin ang ipinasok na ito hide_link: Itago ang ipinasok na ito @@ -284,6 +301,8 @@ tl: too_large: body: Masyadong malaki ang lugar na ito upang mailuwas bilang Dato ng XML ng OpenStreetMap. Mangyaring lumapit o pumili ng isang mas maliit na pook. + overpass: + title: Overpass API other: title: Iba pang mga Pinagmulan options: Mga mapagpipilian @@ -302,7 +321,6 @@ tl: search: title: latlon: Mga kinalabasan mula sa Panloob - us_postcode: Mga kinalabasan mula sa Geocoder.us uk_postcode: Mga kinalabasan mula sa NPEMap / FreeThe Postcode ca_postcode: Mga kinalabasan mula sa Geocoder.CA @@ -324,6 +342,7 @@ tl: taxiway: Daanan ng Taksi terminal: Terminal amenity: + animal_shelter: Kanlungan ng hayop arts_centre: Lunduyan ng Sining atm: ATM bank: Bangko @@ -333,6 +352,7 @@ tl: bicycle_parking: Paradahan ng Bisikleta bicycle_rental: Arkilahan ng Bisikleta biergarten: Inuman ng Serbesa + boat_rental: Arkilahan ng Bangka brothel: Bahay-aliwan bureau_de_change: Tanggapang Palitan ng Pera bus_station: Himpilan ng Bus @@ -374,11 +394,14 @@ tl: library: Aklatan market: Pamilihan marketplace: Palengke + monastery: Monasteryo + motorcycle_parking: Paradahan ng Motorsiklo nightclub: Alibangbang nursery: Alagaan ng mga Bata nursing_home: Alagaan ng mga Matatanda office: Tanggapan parking: Paradahan + parking_entrance: Pasukan ng Paradahan pharmacy: Botika place_of_worship: Sambahan police: Pulis @@ -428,8 +451,11 @@ tl: craft: carpenter: Anluwage gardener: Hardinero + painter: Pintor photographer: Litratista + tailor: Mananahi emergency: + ambulance_station: Istasyon ng Ambulansya phone: Teleponong Pangsakuna highway: abandoned: Pinabayaang daang-bayan @@ -465,6 +491,7 @@ tl: tertiary: Pampangatlong Kalsada tertiary_link: Pampangatlong Kalsada track: Pinak + traffic_signals: Mga Senyas sa Trapiko trail: Bulaos trunk: Pangunahing Ruta trunk_link: Pangunahing Ruta @@ -549,6 +576,7 @@ tl: water_park: Liwasang Tubigan "yes": Pampalipas oras man_made: + pipeline: Linya ng tubo tower: Tore works: Pabrika "yes": Gawa ng tao @@ -723,6 +751,7 @@ tl: sports: Tindahang Pampalakasan stationery: Tindahan ng Papel supermarket: Malaking Pamilihan + tailor: Mananahi toys: Tindahan ng Laruan travel_agency: Ahensiya ng Paglalakbay video: Tindahan ng Bidyo @@ -767,6 +796,8 @@ tl: wadi: Tuyot na Ilog waterfall: Talon weir: Pilapil + admin_levels: + level8: Hangganan ng Lungsod description: title: osm_nominatim: Kinalalagyan mula sa Nominatim @@ -795,6 +826,7 @@ tl: edit: Baguhin history: Kasaysayan export: Iluwas + export_data: Iluwas ang Data gps_traces: Mga Bakas ng GPS gps_traces_tooltip: Pamahalaan ang mga Bakas ng GPS user_diaries: Mga Talaarawan ng mga Tagagamit @@ -805,7 +837,7 @@ tl: intro_2_create_account: Lumikha ng isang akawnt ng tagagamit partners_html: Ang pagpapasinaya ay sinusuportahan ng %{ucl}, %{ic} at %{bytemark}, at iba pang %{partners}. - partners_ucl: Ang Sentro ng UCL VR + partners_ucl: UCL partners_ic: Dalubhasaang Pang-imperyo Londres partners_bytemark: Pagpapasinaya ng Bytemark partners_partners: mga kawaksi @@ -818,7 +850,7 @@ tl: ng Uri ng Hardwer. help: Tulong about: Patungkol - copyright: Karapatang-ari at Lisensiya + copyright: Karapatang-ari community: Pamayanan community_blogs: Mga Blog ng Pamayanan community_blogs_title: Mga blog mula sa mga kasapi ng pamayanan ng OpenStreetMap @@ -924,6 +956,7 @@ tl: ay hindi nagpapahiwatig na ang orihinal \nna tagapagbigay ng dato ay tumatangkilik sa OpenStreetMap, nagbibigay ng anumang garantiya, o \ntumatanggap ng anumang pananagutan." + trademarks_title_html: Mga Trademark welcome_page: title: Maligayang pagdating! whats_on_the_map: @@ -954,6 +987,7 @@ tl: header: 'Nagpadala sa iyo si %{from_user} ng isang mensahe sa pamamagitan ng OpenStreetMap na may paksang %{subject}:' friend_notification: + hi: Kumusta %{to_user}, subject: Idinagdag ka ni %{user} ng [OpenStreetMap] bilang isang kaibigan had_added_you: Idinagdag ka ni %{user} bilang isang kaibigan doon sa OpenStreetMap. see_their_profile: Maaari mong makita ang kanilang balangkas sa %{userurl}. @@ -1004,6 +1038,9 @@ tl: click_the_link: Kung ikaw ito, mangyaring pindutin ang kawing na nasa ibaba upang itakdang muli ang hudyat mo. note_comment_notification: + anonymous: Isang di-nagpakilalang tagagamit + greeting: Kumusta, + changeset_comment_notification: greeting: Kumusta, message: inbox: @@ -1067,6 +1104,7 @@ tl: date: Petsa reply_button: Tumugon unread_button: Tatakan bilang hindi pa nababasa + delete_button: Burahin back: Bumalik to: Para kay wrong_user: Lumagda ka bilang si `%{user}' ngunit ang mensaheng hiniling mong @@ -1185,6 +1223,7 @@ tl: private: Pribadong pagpunta destination: Pagpapapunta sa patutunguhan construction: Mga kalsadang ginagawa + bicycle_parking: Paradahan ng bisikleta toilets: Mga banyo richtext_area: edit: Baguhin @@ -1313,7 +1352,7 @@ tl: message: Pangkasalukuyang hindi makukuha ang sistema ng pagkakarga ng talaksang GPX offline: - heading: Hindi nakaugnay sa Internet na Imbakan ng GPX + heading: Hindi nakaugnay sa Internet ang imbakan ng GPX message: Pangkasalukuyang hindi makukuha ang sistema ng pagkakarga at pag-iimbak ng talaksang GPX. application: @@ -1566,14 +1605,12 @@ tl: deactivate_user: Tanggalin ang prebelehiyo ng 'User' confirm_user: Tiyakin ang tagagamit na ito hide_user: itago ang tagagamit na ito - unhide_user: huwag itago ang tagagamit na ito - delete_user: burahin ang tagagamit na ito + unhide_user: Huwag itago ang Tagagamit na ito + delete_user: Burahin ang Tagagamit na ito confirm: Tiyakin - friends_changesets: Tumingin-tingin sa lahat ng pagtatakda ng mga pagbabago - ng mga kaibigan - friends_diaries: Tumingin-tingin sa lahat ng mga lahok ng mga kaibigan - nearby_changesets: Tumingin-tingin sa lahat ng mga pagtatakda ng pagbabago ng - kanugnog na mga tagagamit + friends_changesets: mga pagbabago ng mga kaibigan + friends_diaries: mga lahok ng mga kaibigan + nearby_changesets: mga pagtatakda ng pagbabago mula sa kalapit na mga tagagamit nearby_diaries: Tumingin-tingin sa lahat ng mga inilahok sa talaarawan ng kanugnog na mga tagagamit popup: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 60be65ec1..81b9cdca0 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -403,7 +403,6 @@ tr: search: title: latlon: OSM'in sonuçları - us_postcode: Geocoder.us'ın sonuçları uk_postcode: FreeThe Postcode sonuçları (İngiltere) ca_postcode: Geocoder.CA'dan sonuçları @@ -1098,6 +1097,7 @@ tr: header: 'OpenStreetMap kullanıcı %{from_user} sana %{subject} konulu bir mesaj gönderdi:' friend_notification: + hi: Merhaba %{to_user}, subject: '[OpenStreetMap] kullanıcı %{user} seni arkadaş olarak ekledi' had_added_you: Kullanıcı %{user} seni arkadaş olarak OpenStreetMap'te ekledi. see_their_profile: '%{userurl} üzerinden profillerini görebilirsiniz.' @@ -1193,6 +1193,7 @@ tr: date: Tarih reply_button: Yanıtla unread_button: Okunmadı olarak işaretle + delete_button: Sil back: Geri to: Alıcı sent_message_summary: @@ -1204,15 +1205,21 @@ tr: deleted: Mesaj silindi site: index: + js_1: JavaScript desteklemeyen bir tarayıcı kullanıyorsunuz ya da JavaScript + devre dışı bırakılmış. js_2: OpenStreetMap harita gösterim için JavaScript kullanıyor. permalink: Kalıcı Bağlantı shortlink: Kısa Bağlantı createnote: Bir not ekle license: copyright: Telif Hakkı OpenStreetMap ve katılımcılar, açık lisans altında + remote_failed: Düzenleme başarısız - JOSM veya Merkaartor'un yüklendiğinden + ve uzaktan kontrol seçeneğinin etkinleştirildiğinden emin olun. edit: user_page_link: kullanıcı sayfası anon_edits: (%{link}) + potlatch2_unsaved_changes: Kaydedilmemiş değişiklikleriniz var. (Potlatch 2'de + kaydetmek için kaydet'e tıklamalısınız.) id_not_configured: iD yapılandırılmamış no_iframe_support: Bu özelliği görüntülemek için gerekli olan HTML iframe tarayıcınız desteklemiyor. @@ -1288,6 +1295,8 @@ tr: private: Özel giriş destination: Hedef noktası construction: yapım aşamasında yolu + bicycle_shop: Bisikletçi + bicycle_parking: Bisiklet parkı toilets: Tuvaletler richtext_area: edit: Düzenle @@ -1401,6 +1410,9 @@ tr: heading: GPX Yükleme Servisi Çevrimdışı georss: title: OpenStreetMap GPS İzleri + application: + require_moderator: + not_a_moderator: Bu eylemi gerçekleştirebilmek için moderatör olmalısınız. oauth: oauthorize_success: verification: Doğrulama kodu %{code}. diff --git a/config/locales/uk.yml b/config/locales/uk.yml index d29b62c08..d7b8dd4cb 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -412,7 +412,6 @@ uk: search: title: latlon: Результати від OpenStreetMap - us_postcode: Результати від Geocoder.us uk_postcode: Результати від NPEMap / FreeThe Postcode ca_postcode: Результати від Geocoder.CA @@ -1420,6 +1419,7 @@ uk: date: Дата reply_button: Відповісти unread_button: Позначити як непрочитане + delete_button: Видалити back: Назад to: 'Кому:' wrong_user: Ви увійшли як „%{user}“, але повідомлення, яке ви хочете прочитати, @@ -2392,6 +2392,7 @@ uk: ascend: Вгору engines: graphhopper_bicycle: Велосипед (GraphHopper) + graphhopper_car: Автівкою (GraphHopper) graphhopper_foot: Пішки (GraphHopper) mapquest_bicycle: Велосипед (MapQuest) mapquest_car: Машина (MapQuest) diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 71d197d67..252fbfc36 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -258,7 +258,7 @@ vi: diary_entry: new: title: Mục Nhật ký Mới - publish_button: Xuất bản + publish_button: Đăng list: title: Các Nhật ký Cá nhân title_friends: Các nhật ký của bạn bè @@ -381,7 +381,6 @@ vi: search: title: latlon: Kết quả nội bộ - us_postcode: Kết quả Geocoder.us uk_postcode: Kết quả NPEMap / FreeThe Postcode ca_postcode: Kết quả Geocoder.CA @@ -948,7 +947,7 @@ vi: intro_2_create_account: Mở tài khoản mới partners_html: Dịch vụ nhờ sự hỗ trợ hosting của %{ucl}, %{ic}, và %{bytemark}, cũng như %{partners} khác. - partners_ucl: Trung tâm VR tại UCL + partners_ucl: UCL partners_ic: Đại học Hoàng gia Luân Đôn partners_bytemark: Bytemark Hosting partners_partners: các công ty bảo trợ @@ -1222,6 +1221,7 @@ vi: footer_html: Bạn cũng có thể đọc tin nhắn này tại %{readurl} và có thể trả lời tại %{replyurl} friend_notification: + hi: Chào %{to_user}, subject: '[OpenStreetMap] %{user} đã kết bạn với bạn' had_added_you: '%{user} đã thêm bạn vào danh sách bạn tại OpenStreetMap.' see_their_profile: Có thể xem trang cá nhân của họ tại %{userurl}. @@ -1378,6 +1378,7 @@ vi: date: Ngày reply_button: Trả lời unread_button: Đánh dấu là chưa đọc + delete_button: Xóa back: Quay lại to: Tới wrong_user: Bạn đã đăng nhập dùng tài khoản “%{user}” nhưng vừa yêu cầu đọc @@ -1675,6 +1676,8 @@ vi: invalid: Dấu hiệu cho phép không hợp lệ. revoke: flash: Bạn đã thu hồi dấu của %{application} + permissions: + missing: Bạn chưa cấp phép cho ứng dụng sử dụng chức năng này oauth_clients: new: title: Đăng ký chương trình mới @@ -1960,7 +1963,8 @@ vi: enabled: Kích hoạt. Không vô danh và có thể sửa đổi dữ liệu. enabled link: http://wiki.openstreetmap.org/wiki/Anonymous_edits?uselang=vi enabled link text: đây là gì? - disabled: Vô hiệu. Không thể sửa đổi dữ liệu. all previous edits are anonymous. + disabled: Vô hiệu. Không thể sửa đổi dữ liệu. Tất cả các sửa đổi truớc là + vô danh. disabled link text: tại sao không thể sửa đổi? public editing note: heading: Sửa đổi công khai @@ -2326,8 +2330,10 @@ vi: edit_help: Di chuyển bản đồ và phóng to một vị trí mà bạn muốn sửa đổi, rồi nhấn chuột vào đây. directions: + ascend: Lên engines: graphhopper_bicycle: Xe đạp (GraphHopper) + graphhopper_car: Xe hơi (GraphHopper) graphhopper_foot: Đi bộ (GraphHopper) mapquest_bicycle: Xe đạp (MapQuest) mapquest_car: Xe hơi (MapQuest) @@ -2336,6 +2342,7 @@ vi: mapzen_bicycle: Xe đạp (Mapzen) mapzen_car: Xe hơi (Mapzen) mapzen_foot: Đi bộ (Mapzen) + descend: Xuống directions: Chỉ đường distance: Tầm xa errors: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 42e893804..c2e80800c 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -11,6 +11,7 @@ # Author: Impersonator 1 # Author: Jienus # Author: Jiwei +# Author: Koalberry # Author: Liangent # Author: Liuxinyu970226 # Author: Mmyangfl @@ -393,7 +394,6 @@ zh-CN: search: title: latlon: 来自内部的结果 - us_postcode: 来自 Geocoder.us 的结果 uk_postcode: 来自 NPEMap / FreeThe Postcode 的结果 ca_postcode: 来自 Geocoder.CA 的结果 @@ -1290,6 +1290,7 @@ zh-CN: date: 日期 reply_button: 回复 unread_button: 标记为未读 + delete_button: 删除 back: 返回 to: 收件人 wrong_user: 您已经以 '%{user}' 的身份登录,但是您想要阅读的消息并非寄给这个用户。请以正确的用户身份登录以阅读这个消息。 @@ -1445,7 +1446,7 @@ zh-CN: start_coord: 起始坐标: map: 地图 edit: 编辑 - owner: 所有人: + owner: 所有者: description: 说明: tags: 标签: tags_help: 用逗号分隔 @@ -1482,7 +1483,7 @@ zh-CN: start_coordinates: 起始坐标: map: 地图 edit: 编辑 - owner: 所有人: + owner: 所有者: description: 说明: tags: 标签: none: 无 @@ -2125,7 +2126,7 @@ zh-CN: header: 地图图层 notes: 地图笔记 data: 地图数据 - gps: 公开 GPS 痕迹 + gps: 公开 GPS 轨迹 overlays: 启用解决地图问题的覆盖层 title: 图层 copyright: © OpenStreetMap 贡献者 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index a4b2c59a5..70fbd5a57 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -1,6 +1,7 @@ # Messages for Traditional Chinese (中文(繁體)‎) # Exported from translatewiki.net # Export driver: phpyaml +# Author: A2093064 # Author: Anakmalaysia # Author: Cwlin0416 # Author: EagerLin @@ -391,7 +392,6 @@ zh-TW: search: title: latlon: 來自內部的結果 - us_postcode: 來自Geocoder.us的結果 uk_postcode: 來自NPEMap / FreeThe Postcode的結果 ca_postcode: 來自Geocoder.CA的結果 osm_nominatim: 來自OpenStreetMap @@ -1314,6 +1314,7 @@ zh-TW: date: 日期 reply_button: 回覆 unread_button: 標記為未讀 + delete_button: 刪除 back: 返回 to: 收件者 wrong_user: 您已經以 "%{user}" 的身份登入,但是您想要閱讀的訊息並非寄給那個使用者。請以正確的使用者身份登入以閱讀它。 @@ -1620,7 +1621,7 @@ zh-TW: my_tokens: 我授權的應用程式 list_tokens: 下列密鑰已核發給您名下的應用程式: application: 應用程式名稱 - issued_at: 簽發於 + issued_at: 已發於 revoke: 撤銷! my_apps: 我的用戶端應用程式 no_apps: 您是否有想要註冊以使用於 %{oauth} 標準的應用程式?您必須先註冊您的網頁應用程式,才能對這個服務進行 OAuth 要求。 @@ -1837,7 +1838,7 @@ zh-TW: current email address: 目前的電子郵件地址: new email address: 新的電子郵件地址: email never displayed publicly: (永遠不公開顯示) - external auth: 外部認証: + external auth: 外部認證: openid: link: HTTP://wiki.openstreetmap.org/wiki/OpenID link text: 這是什麼? @@ -1941,8 +1942,8 @@ zh-TW: body: "

      \n對不起,您的帳號已因可疑\n活動被自動暫停。 \n

      \n

      \n這項決定將在短期內由行政員審核,或是如果你想討論這一點\n,可以聯絡 %{webmaster}。 \n

      " auth_failure: - connection_failed: 連線至認証供應者失敗 - invalid_credentials: 無效的認証憑証 + connection_failed: 連線至認證供應者失敗 + invalid_credentials: 無效的認證憑證 no_authorization_code: 無授權碼 unknown_signature_algorithm: 不明的簽章演算法 invalid_scope: 無效範圍 diff --git a/config/routes.rb b/config/routes.rb index 47bedac08..98bb332f2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -246,7 +246,6 @@ OpenStreetMap::Application.routes.draw do # geocoder match "/search" => "geocoder#search", :via => :get, :as => :search match "/geocoder/search_latlon" => "geocoder#search_latlon", :via => :get - match "/geocoder/search_us_postcode" => "geocoder#search_us_postcode", :via => :get match "/geocoder/search_uk_postcode" => "geocoder#search_uk_postcode", :via => :get match "/geocoder/search_ca_postcode" => "geocoder#search_ca_postcode", :via => :get match "/geocoder/search_osm_nominatim" => "geocoder#search_osm_nominatim", :via => :get diff --git a/db/migrate/006_tile_nodes.rb b/db/migrate/006_tile_nodes.rb index 29200d06a..1f27ec79e 100644 --- a/db/migrate/006_tile_nodes.rb +++ b/db/migrate/006_tile_nodes.rb @@ -3,33 +3,33 @@ require "migrate" class TileNodes < ActiveRecord::Migration def self.upgrade_table(from_table, to_table, model) if ENV["USE_DB_FUNCTIONS"] - execute <<-END_SQL + execute <<-SQL INSERT INTO #{to_table} (id, latitude, longitude, user_id, visible, tags, timestamp, tile) SELECT id, ROUND(latitude * 10000000), ROUND(longitude * 10000000), user_id, visible, tags, timestamp, tile_for_point(CAST(ROUND(latitude * 10000000) AS INTEGER), CAST(ROUND(longitude * 10000000) AS INTEGER)) FROM #{from_table} - END_SQL + SQL else - execute <<-END_SQL + execute <<-SQL INSERT INTO #{to_table} (id, latitude, longitude, user_id, visible, tags, timestamp, tile) SELECT id, ROUND(latitude * 10000000), ROUND(longitude * 10000000), user_id, visible, tags, timestamp, 0 FROM #{from_table} - END_SQL + SQL model.all.each(&:save!) end end def self.downgrade_table(from_table, to_table) - execute <<-END_SQL + execute <<-SQL INSERT INTO #{to_table} (id, latitude, longitude, user_id, visible, tags, timestamp) SELECT id, latitude / 10000000, longitude / 10000000, user_id, visible, tags, timestamp FROM #{from_table} - END_SQL + SQL end def self.up diff --git a/db/migrate/008_remove_segments.rb b/db/migrate/008_remove_segments.rb index 62f618abf..fe3716152 100644 --- a/db/migrate/008_remove_segments.rb +++ b/db/migrate/008_remove_segments.rb @@ -10,7 +10,7 @@ class RemoveSegments < ActiveRecord::Migration cmd = "db/migrate/008_remove_segments_helper" src = "#{cmd}.cc" if !File.exist?(cmd) || File.mtime(cmd) < File.mtime(src) - system("c++ -O3 -Wall `mysql_config --cflags --libs` " + + system("c++ -O3 -Wall `mysql_config --cflags --libs` " \ "#{src} -o #{cmd}") || raise end diff --git a/db/migrate/020_populate_node_tags_and_remove.rb b/db/migrate/020_populate_node_tags_and_remove.rb index 0fd1dc564..e2d253d17 100644 --- a/db/migrate/020_populate_node_tags_and_remove.rb +++ b/db/migrate/020_populate_node_tags_and_remove.rb @@ -10,7 +10,7 @@ class PopulateNodeTagsAndRemove < ActiveRecord::Migration cmd = "db/migrate/020_populate_node_tags_and_remove_helper" src = "#{cmd}.c" if !File.exist?(cmd) || File.mtime(cmd) < File.mtime(src) - system("cc -O3 -Wall `mysql_config --cflags --libs` " + + system("cc -O3 -Wall `mysql_config --cflags --libs` " \ "#{src} -o #{cmd}") || raise end diff --git a/db/migrate/023_add_changesets.rb b/db/migrate/023_add_changesets.rb index 933a62cd5..8265353a7 100644 --- a/db/migrate/023_add_changesets.rb +++ b/db/migrate/023_add_changesets.rb @@ -28,7 +28,7 @@ class AddChangesets < ActiveRecord::Migration # all edits up to the API change, # all the changesets will have the id of the user that made them. # We need to generate a changeset for each user in the database - execute "INSERT INTO changesets (id, user_id, created_at, open)" + + execute "INSERT INTO changesets (id, user_id, created_at, open)" \ "SELECT id, id, creation_time, false from users;" @conv_user_tables.each do |tbl| diff --git a/lib/bounding_box.rb b/lib/bounding_box.rb index 51972efbc..f12683d3c 100644 --- a/lib/bounding_box.rb +++ b/lib/bounding_box.rb @@ -66,18 +66,14 @@ class BoundingBox def check_boundaries # check the bbox is sane if min_lon > max_lon - raise OSM::APIBadBoundingBox.new( - "The minimum longitude must be less than the maximum longitude, but it wasn't" - ) + raise OSM::APIBadBoundingBox, "The minimum longitude must be less than the maximum longitude, but it wasn't" end if min_lat > max_lat - raise OSM::APIBadBoundingBox.new( - "The minimum latitude must be less than the maximum latitude, but it wasn't" - ) + raise OSM::APIBadBoundingBox, "The minimum latitude must be less than the maximum latitude, but it wasn't" end if min_lon < -LON_LIMIT || min_lat < -LAT_LIMIT || max_lon > +LON_LIMIT || max_lat > +LAT_LIMIT - raise OSM::APIBadBoundingBox.new("The latitudes must be between #{-LAT_LIMIT} and #{LAT_LIMIT}," + - " and longitudes between #{-LON_LIMIT} and #{LON_LIMIT}") + raise OSM::APIBadBoundingBox, "The latitudes must be between #{-LAT_LIMIT} and #{LAT_LIMIT}," \ + " and longitudes between #{-LON_LIMIT} and #{LON_LIMIT}" end self end @@ -85,8 +81,8 @@ class BoundingBox def check_size(max_area = MAX_REQUEST_AREA) # check the bbox isn't too large 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") + raise OSM::APIBadBoundingBox, "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 end @@ -171,9 +167,7 @@ class BoundingBox def from_bbox_array(bbox_array) unless bbox_array - raise OSM::APIBadUserInput.new( - "The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat" - ) + raise OSM::APIBadUserInput, "The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat" end # Take an array of length 4, create a bounding box with min_lon, min_lat, max_lon and # max_lat within their respective boundaries. diff --git a/lib/consistency_validations.rb b/lib/consistency_validations.rb index 0d17d2830..7e9b33586 100644 --- a/lib/consistency_validations.rb +++ b/lib/consistency_validations.rb @@ -7,26 +7,26 @@ module ConsistencyValidations # This will throw an exception if there is an inconsistency def check_consistency(old, new, user) if new.id != old.id || new.id.nil? || old.id.nil? - raise OSM::APIPreconditionFailedError.new("New and old IDs don't match on #{new.class}. #{new.id} != #{old.id}.") + raise OSM::APIPreconditionFailedError, "New and old IDs don't match on #{new.class}. #{new.id} != #{old.id}." elsif new.version != old.version raise OSM::APIVersionMismatchError.new(new.id, new.class.to_s, new.version, old.version) elsif new.changeset.nil? - raise OSM::APIChangesetMissingError.new + raise OSM::APIChangesetMissingError elsif new.changeset.user_id != user.id - raise OSM::APIUserChangesetMismatchError.new + raise OSM::APIUserChangesetMismatchError elsif !new.changeset.is_open? - raise OSM::APIChangesetAlreadyClosedError.new(new.changeset) + raise OSM::APIChangesetAlreadyClosedError, new.changeset end end # This is similar to above, just some validations don't apply def check_create_consistency(new, user) if new.changeset.nil? - raise OSM::APIChangesetMissingError.new + raise OSM::APIChangesetMissingError elsif new.changeset.user_id != user.id - raise OSM::APIUserChangesetMismatchError.new + raise OSM::APIUserChangesetMismatchError elsif !new.changeset.is_open? - raise OSM::APIChangesetAlreadyClosedError.new(new.changeset) + raise OSM::APIChangesetAlreadyClosedError, new.changeset end end @@ -37,11 +37,11 @@ module ConsistencyValidations # check user credentials - only the user who opened a changeset # may alter it. if changeset.nil? - raise OSM::APIChangesetMissingError.new + raise OSM::APIChangesetMissingError elsif user.id != changeset.user_id - raise OSM::APIUserChangesetMismatchError.new + raise OSM::APIUserChangesetMismatchError elsif !changeset.is_open? - raise OSM::APIChangesetAlreadyClosedError.new(changeset) + raise OSM::APIChangesetAlreadyClosedError, changeset end end end diff --git a/lib/daemons/gpx_import_ctl b/lib/daemons/gpx_import_ctl index 00b3a00b3..495ce1fb1 100755 --- a/lib/daemons/gpx_import_ctl +++ b/lib/daemons/gpx_import_ctl @@ -6,7 +6,7 @@ require "erb" class Hash def with_symbols! - keys.each { |key| self[key.to_s.to_sym] = self[key] } + each_key { |key| self[key.to_s.to_sym] = self[key] } self end end diff --git a/lib/diff_reader.rb b/lib/diff_reader.rb index c2e7f1839..94c41a6d5 100644 --- a/lib/diff_reader.rb +++ b/lib/diff_reader.rb @@ -86,8 +86,8 @@ class DiffReader with_element do |model_name, _model_attributes| model = MODELS[model_name] if model.nil? - raise OSM::APIBadUserInput.new("Unexpected element type #{model_name}, " + - "expected node, way or relation.") + raise OSM::APIBadUserInput, "Unexpected element type #{model_name}, " \ + "expected node, way or relation." end # new in libxml-ruby >= 2, expand returns an element not associated # with a document. this means that there's no encoding parameter, @@ -130,7 +130,7 @@ class DiffReader # take the first element and check that it is an osmChange element @reader.read - raise OSM::APIBadUserInput.new("Document element should be 'osmChange'.") if @reader.name != "osmChange" + raise OSM::APIBadUserInput, "Document element should be 'osmChange'." if @reader.name != "osmChange" result = OSM::API.new.get_xml_doc result.root.name = "diffResult" @@ -152,7 +152,7 @@ class DiffReader # check if the placeholder ID has been given before and throw # an exception if it has - we can't create the same element twice. model_sym = model.to_s.downcase.to_sym - raise OSM::APIBadUserInput.new("Placeholder IDs must be unique for created elements.") if ids[model_sym].include? placeholder_id + raise OSM::APIBadUserInput, "Placeholder IDs must be unique for created elements." if ids[model_sym].include? placeholder_id # some elements may have placeholders for other elements in the # diff, so we must fix these before saving the element. @@ -252,7 +252,7 @@ class DiffReader else # no other actions to choose from, so it must be the users fault! - raise OSM::APIChangesetActionInvalid.new(action_name) + raise OSM::APIChangesetActionInvalid, action_name end end diff --git a/lib/not_redactable.rb b/lib/not_redactable.rb index 7fe119fea..6a5773296 100644 --- a/lib/not_redactable.rb +++ b/lib/not_redactable.rb @@ -6,6 +6,6 @@ module NotRedactable end def redact!(_r) - raise OSM::APICannotRedactError.new + raise OSM::APICannotRedactError end end diff --git a/lib/osm.rb b/lib/osm.rb index 80b68c2a9..e4835a76b 100644 --- a/lib/osm.rb +++ b/lib/osm.rb @@ -532,7 +532,7 @@ module OSM # Parse a float, raising a specified exception on failure def self.parse_float(str, klass, *args) Float(str) - rescue + rescue StandardError raise klass.new(*args) end @@ -553,7 +553,7 @@ module OSM tilesql = QuadTile.sql_for_area(bbox, prefix) bbox = bbox.to_scaled - "#{tilesql} AND #{prefix}latitude BETWEEN #{bbox.min_lat} AND #{bbox.max_lat} " + + "#{tilesql} AND #{prefix}latitude BETWEEN #{bbox.min_lat} AND #{bbox.max_lat} " \ "AND #{prefix}longitude BETWEEN #{bbox.min_lon} AND #{bbox.max_lon}" end diff --git a/lib/redactable.rb b/lib/redactable.rb index 6adfec72a..d827cfd74 100644 --- a/lib/redactable.rb +++ b/lib/redactable.rb @@ -13,7 +13,7 @@ module Redactable def redact!(redaction) # check that this version isn't the current version - raise OSM::APICannotRedactError.new if is_latest_version? + raise OSM::APICannotRedactError if is_latest_version? # make the change self.redaction = redaction diff --git a/lib/session_persistence.rb b/lib/session_persistence.rb index 7d42b71e7..ac0e690c2 100644 --- a/lib/session_persistence.rb +++ b/lib/session_persistence.rb @@ -55,7 +55,7 @@ module SessionPersistence if session[session_persistence_key] request.session_options[:expire_after] = session[session_persistence_key] end - rescue + rescue StandardError reset_session end end diff --git a/test/controllers/api_controller_test.rb b/test/controllers/api_controller_test.rb index 9cdbd718c..11d850ac3 100644 --- a/test/controllers/api_controller_test.rb +++ b/test/controllers/api_controller_test.rb @@ -406,7 +406,7 @@ class ApiControllerTest < ActionController::TestCase end def test_permissions_basic_auth - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" get :permissions assert_response :success assert_select "osm > permissions", :count => 1 do diff --git a/test/controllers/changeset_controller_test.rb b/test/controllers/changeset_controller_test.rb index 654682ac0..b1aa79810 100644 --- a/test/controllers/changeset_controller_test.rb +++ b/test/controllers/changeset_controller_test.rb @@ -98,16 +98,16 @@ class ChangesetControllerTest < ActionController::TestCase def test_create basic_authorization create(:user, :data_public => false).email, "test" # Create the first user's changeset - content "" + - "" + + content "" \ + "" \ "" put :create assert_require_public_data basic_authorization create(:user).email, "test" # Create the first user's changeset - content "" + - "" + + content "" \ + "" \ "" put :create @@ -327,7 +327,7 @@ class ChangesetControllerTest < ActionController::TestCase # simple diff to change a node, way and relation by removing # their tags - diff = < @@ -343,7 +343,7 @@ class ChangesetControllerTest < ActionController::TestCase -EOF +CHANGESET # upload it content diff @@ -357,7 +357,7 @@ EOF # simple diff to change a node, way and relation by removing # their tags - diff = < @@ -373,7 +373,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -387,7 +387,7 @@ EOF # simple diff to change a node, way and relation by removing # their tags - diff = < @@ -403,7 +403,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -429,7 +429,7 @@ EOF basic_authorization user.email, "test" # simple diff to create a node way and relation using placeholders - diff = < @@ -448,7 +448,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -561,8 +561,8 @@ EOF basic_authorization create(:user).email, "test" # create a temporary changeset - content "" + - "" + + content "" \ + "" \ "" assert_difference "Changeset.count", 1 do put :create @@ -582,7 +582,7 @@ EOF # upload some widely-spaced nodes, spiralling positive and negative to cause # largest bbox over-expansion possible. - diff = < @@ -605,7 +605,7 @@ EOF -EOF +CHANGESET # upload it, which used to cause an error like "PGError: ERROR: # integer out of range" (bug #2152). but shouldn't any more. @@ -739,7 +739,7 @@ EOF basic_authorization changeset.user.email, "test" # simple diff to create a node way and relation using placeholders - diff = < @@ -747,7 +747,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -770,7 +770,7 @@ EOF basic_authorization changeset.user.email, "test" # simple diff to create a node way and relation using placeholders - diff = < @@ -790,7 +790,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -832,7 +832,7 @@ EOF basic_authorization changeset.user.email, "test" # simple diff to create a node way and relation using placeholders - diff = < @@ -854,7 +854,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -878,7 +878,7 @@ EOF # change the location of a node multiple times, each time referencing # the last version. doesn't this depend on version numbers being # sequential? - diff = < @@ -891,7 +891,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -914,14 +914,14 @@ EOF basic_authorization changeset.user.email, "test" - diff = < -EOF +CHANGESET # upload it content diff @@ -937,13 +937,13 @@ EOF basic_authorization changeset.user.email, "test" - diff = < -EOF +CHANGESET # upload it content diff @@ -959,13 +959,13 @@ EOF basic_authorization changeset.user.email, "test" - diff = < -EOF +CHANGESET content diff post :upload, :params => { :id => changeset.id } assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping" @@ -985,7 +985,7 @@ EOF basic_authorization changeset.user.email, "test" - diff = < @@ -997,7 +997,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1021,7 +1021,7 @@ EOF basic_authorization changeset.user.email, "test" - diff = < @@ -1035,7 +1035,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1056,7 +1056,7 @@ EOF basic_authorization changeset.user.email, "test" - diff = < @@ -1064,7 +1064,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1082,7 +1082,7 @@ EOF basic_authorization changeset.user.email, "test" - diff = < @@ -1096,7 +1096,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1106,7 +1106,7 @@ EOF assert_equal "Placeholder node not found for reference -4 in way -1", @response.body # the same again, but this time use an existing way - diff = < @@ -1120,7 +1120,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1139,7 +1139,7 @@ EOF basic_authorization changeset.user.email, "test" - diff = < @@ -1153,7 +1153,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1163,7 +1163,7 @@ EOF assert_equal "Placeholder Node not found for reference -4 in relation -1.", @response.body # the same again, but this time use an existing relation - diff = < @@ -1177,7 +1177,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1193,8 +1193,8 @@ EOF def test_upload_node_move basic_authorization create(:user).email, "test" - content "" + - "" + + content "" \ + "" \ "" put :create assert_response :success @@ -1231,8 +1231,8 @@ EOF def test_upload_way_extend basic_authorization create(:user).email, "test" - content "" + - "" + + content "" \ + "" \ "" put :create assert_response :success @@ -1280,7 +1280,7 @@ EOF # upload it content diff post :upload, :params => { :id => changeset.id } - assert_response(:success, "should be able to upload " + + assert_response(:success, "should be able to upload " \ "empty changeset: " + diff) end end @@ -1321,28 +1321,28 @@ EOF node = create(:node) ## First try with a non-public user, which should get a forbidden - basic_authorization(create(:user, :data_public => false).email, "test") + basic_authorization create(:user, :data_public => false).email, "test" # create a temporary changeset - content "" + - "" + + content "" \ + "" \ "" put :create assert_response :forbidden ## Now try with a normal user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # create a temporary changeset - content "" + - "" + + content "" \ + "" \ "" put :create assert_response :success changeset_id = @response.body.to_i # add a diff to it - diff = < @@ -1355,7 +1355,7 @@ EOF -EOF +CHANGESET # upload it content diff @@ -1377,11 +1377,11 @@ EOF # # NOTE: the error turned out to be something else completely! def test_josm_upload - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # create a temporary changeset - content "" + - "" + + content "" \ + "" \ "" put :create assert_response :success @@ -1439,18 +1439,18 @@ OSMFILE node = create(:node) node2 = create(:node) way = create(:way) - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # create a temporary changeset - content "" + - "" + + content "" \ + "" \ "" put :create assert_response :success changeset_id = @response.body.to_i # add a diff to it - diff = < @@ -1470,7 +1470,7 @@ OSMFILE -EOF +CHANGESET # upload it content diff @@ -1880,7 +1880,7 @@ EOF # check that the changeset is now closed as well assert(!changeset.is_open?, - "changeset should have been auto-closed by exceeding " + + "changeset should have been auto-closed by exceeding " \ "element limit.") end @@ -2147,7 +2147,7 @@ EOF deleted_user = create(:user, :deleted) private_user_closed_changeset = create(:changeset, :closed, :user => private_user) - basic_authorization(user.email, "test") + basic_authorization user.email, "test" assert_difference "ChangesetComment.count", 1 do assert_no_difference "ActionMailer::Base.deliveries.size" do @@ -2176,7 +2176,7 @@ EOF ActionMailer::Base.deliveries.clear - basic_authorization(user2.email, "test") + basic_authorization user2.email, "test" assert_difference "ChangesetComment.count", 1 do assert_difference "ActionMailer::Base.deliveries.size", 2 do @@ -2205,7 +2205,7 @@ EOF post :comment, :params => { :id => create(:changeset, :closed).id, :text => "This is a comment" } assert_response :unauthorized - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # bad changeset id assert_no_difference "ChangesetComment.count" do @@ -2235,7 +2235,7 @@ EOF ## # test subscribe success def test_subscribe_success - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" changeset = create(:changeset, :closed) assert_difference "changeset.subscribers.count", 1 do @@ -2256,7 +2256,7 @@ EOF end assert_response :unauthorized - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # bad changeset id assert_no_difference "changeset.subscribers.count" do @@ -2284,7 +2284,7 @@ EOF # test unsubscribe success def test_unsubscribe_success user = create(:user) - basic_authorization(user.email, "test") + basic_authorization user.email, "test" changeset = create(:changeset, :closed) changeset.subscribers.push(user) @@ -2304,7 +2304,7 @@ EOF end assert_response :unauthorized - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # bad changeset id assert_no_difference "changeset.subscribers.count" do @@ -2338,14 +2338,14 @@ EOF assert_response :unauthorized assert_equal true, comment.reload.visible - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # not a moderator post :hide_comment, :params => { :id => comment.id } assert_response :forbidden assert_equal true, comment.reload.visible - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" # bad comment id post :hide_comment, :params => { :id => 999111 } @@ -2359,7 +2359,7 @@ EOF comment = create(:changeset_comment) assert_equal true, comment.visible - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" post :hide_comment, :params => { :id => comment.id } assert_response :success @@ -2377,14 +2377,14 @@ EOF assert_response :unauthorized assert_equal false, comment.reload.visible - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # not a moderator post :unhide_comment, :params => { :id => comment.id } assert_response :forbidden assert_equal false, comment.reload.visible - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" # bad comment id post :unhide_comment, :params => { :id => 999111 } @@ -2398,7 +2398,7 @@ EOF comment = create(:changeset_comment, :visible => false) assert_equal false, comment.visible - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" post :unhide_comment, :params => { :id => comment.id } assert_response :success diff --git a/test/controllers/diary_entry_controller_test.rb b/test/controllers/diary_entry_controller_test.rb index fcd93eb2a..f95c57d7c 100644 --- a/test/controllers/diary_entry_controller_test.rb +++ b/test/controllers/diary_entry_controller_test.rb @@ -254,7 +254,7 @@ class DiaryEntryControllerTest < ActionController::TestCase get :edit, :params => { :display_name => entry.user.display_name, :id => entry.id } assert_response :redirect - assert_redirected_to :controller => :user, :action => :login, :referer => "/user/#{URI.encode(entry.user.display_name)}/diary/#{entry.id}/edit" + assert_redirected_to :controller => :user, :action => :login, :referer => "/user/#{ERB::Util.u(entry.user.display_name)}/diary/#{entry.id}/edit" # Verify that you get a not found error, when you pass a bogus id get :edit, @@ -284,7 +284,7 @@ class DiaryEntryControllerTest < ActionController::TestCase assert_select "h1", :text => /Edit diary entry/, :count => 1 end assert_select "div#content", :count => 1 do - assert_select "form[action='/user/#{URI.encode(entry.user.display_name)}/diary/#{entry.id}/edit'][method=post]", :count => 1 do + assert_select "form[action='/user/#{ERB::Util.u(entry.user.display_name)}/diary/#{entry.id}/edit'][method=post]", :count => 1 do assert_select "input#diary_entry_title[name='diary_entry[title]'][value='#{entry.title}']", :count => 1 assert_select "textarea#diary_entry_body[name='diary_entry[body]']", :text => entry.body, :count => 1 assert_select "select#diary_entry_language_code", :count => 1 @@ -329,7 +329,7 @@ class DiaryEntryControllerTest < ActionController::TestCase assert_select "abbr[class='geo'][title='#{number_with_precision(new_latitude, :precision => 4)}; #{number_with_precision(new_longitude, :precision => 4)}']", :count => 1 # As we're not logged in, check that you cannot edit # print @response.body - assert_select "a[href='/user/#{URI.encode(entry.user.display_name)}/diary/#{entry.id}/edit']", :text => "Edit this entry", :count => 1 + assert_select "a[href='/user/#{ERB::Util.u(entry.user.display_name)}/diary/#{entry.id}/edit']", :text => "Edit this entry", :count => 1 end # and when not logged in as the user who wrote the entry @@ -350,7 +350,7 @@ class DiaryEntryControllerTest < ActionController::TestCase assert_select "abbr[class=geo][title='#{number_with_precision(new_latitude, :precision => 4)}; #{number_with_precision(new_longitude, :precision => 4)}']", :count => 1 # As we're not logged in, check that you cannot edit assert_select "li[class='hidden show_if_user_#{entry.user.id}']", :count => 1 do - assert_select "a[href='/user/#{URI.encode(entry.user.display_name)}/diary/#{entry.id}/edit']", :text => "Edit this entry", :count => 1 + assert_select "a[href='/user/#{ERB::Util.u(entry.user.display_name)}/diary/#{entry.id}/edit']", :text => "Edit this entry", :count => 1 end end end @@ -430,7 +430,7 @@ class DiaryEntryControllerTest < ActionController::TestCase assert_response :success assert_select ".diary-comment", :count => 1 do assert_select "#comment#{comment.id}", :count => 1 do - assert_select "a[href='/user/#{URI.encode(other_user.display_name)}']", :text => other_user.display_name, :count => 1 + assert_select "a[href='/user/#{ERB::Util.u(other_user.display_name)}']", :text => other_user.display_name, :count => 1 end assert_select ".richtext", :text => /New comment/, :count => 1 end @@ -890,7 +890,7 @@ class DiaryEntryControllerTest < ActionController::TestCase assert_select "div.diary_post", entries.count entries.each do |entry| - assert_select "a[href=?]", "/user/#{URI.encode(entry.user.display_name)}/diary/#{entry.id}" + assert_select "a[href=?]", "/user/#{ERB::Util.u(entry.user.display_name)}/diary/#{entry.id}" end end end diff --git a/test/controllers/geocoder_controller_test.rb b/test/controllers/geocoder_controller_test.rb index ecddf96aa..ee8991d48 100644 --- a/test/controllers/geocoder_controller_test.rb +++ b/test/controllers/geocoder_controller_test.rb @@ -1,4 +1,3 @@ -# coding: utf-8 require "test_helper" require "geocoder_controller" @@ -15,10 +14,6 @@ class GeocoderControllerTest < ActionController::TestCase { :path => "/geocoder/search_latlon", :method => :get }, { :controller => "geocoder", :action => "search_latlon" } ) - assert_routing( - { :path => "/geocoder/search_us_postcode", :method => :get }, - { :controller => "geocoder", :action => "search_us_postcode" } - ) assert_routing( { :path => "/geocoder/search_uk_postcode", :method => :get }, { :controller => "geocoder", :action => "search_uk_postcode" } @@ -253,7 +248,7 @@ class GeocoderControllerTest < ActionController::TestCase ].each do |code| post :search, :params => { :query => code } assert_response :success - assert_equal %w[us_postcode osm_nominatim], assigns(:sources) + assert_equal %w[osm_nominatim], assigns(:sources) end end @@ -304,25 +299,6 @@ class GeocoderControllerTest < ActionController::TestCase results_check_error "Longitude 180.23 out of range" end - ## - # Test the US postcode search - def test_search_us_postcode - with_http_stubs "geocoder_us" do - get :search_us_postcode, :xhr => true, - :params => { :query => "90210", :zoom => 10, - :minlon => -0.559, :minlat => 51.217, - :maxlon => 0.836, :maxlat => 51.766 } - results_check :prefix => "Beverly Hills, CA,", :name => "90210", - :lat => 34.088808, :lon => -118.40612 - - get :search_us_postcode, :xhr => true, - :params => { :query => "00000", :zoom => 10, - :minlon => -0.559, :minlat => 51.217, - :maxlon => 0.836, :maxlat => 51.766 } - results_check - end - end - ## # Test the UK postcode search def test_search_uk_postcode diff --git a/test/controllers/node_controller_test.rb b/test/controllers/node_controller_test.rb index 7aeb5066b..1fdb3f907 100644 --- a/test/controllers/node_controller_test.rb +++ b/test/controllers/node_controller_test.rb @@ -46,7 +46,7 @@ class NodeControllerTest < ActionController::TestCase assert_response :unauthorized, "node upload did not return unauthorized status" ## Now try with the user which doesn't have their data public - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # create a minimal xml file content("") @@ -57,7 +57,7 @@ class NodeControllerTest < ActionController::TestCase assert_require_public_data "node create did not return forbidden status" ## Now try with the user that has the public data - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # create a minimal xml file content("") @@ -83,7 +83,7 @@ class NodeControllerTest < ActionController::TestCase user = create(:user) changeset = create(:changeset, :user => user) - basic_authorization(user.email, "test") + basic_authorization user.email, "test" lat = 3.434 lon = 3.23 @@ -160,7 +160,7 @@ class NodeControllerTest < ActionController::TestCase assert_response :unauthorized ## now set auth for the non-data public user - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # try to delete with an invalid (closed) changeset content update_changeset(private_node.to_xml, private_user_closed_changeset.id) @@ -208,7 +208,7 @@ class NodeControllerTest < ActionController::TestCase changeset = create(:changeset, :user => user) closed_changeset = create(:changeset, :closed, :user => user) node = create(:node, :changeset => changeset) - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # try to delete with an invalid (closed) changeset content update_changeset(node.to_xml, closed_changeset.id) @@ -295,7 +295,7 @@ class NodeControllerTest < ActionController::TestCase ## Second test with the private user # setup auth - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" ## trying to break changesets @@ -347,7 +347,7 @@ class NodeControllerTest < ActionController::TestCase assert_response :forbidden # setup auth - basic_authorization(user.email, "test") + basic_authorization user.email, "test" ## trying to break changesets @@ -465,7 +465,7 @@ class NodeControllerTest < ActionController::TestCase existing_tag = create(:node_tag) assert_equal true, existing_tag.node.changeset.user.data_public # setup auth - basic_authorization(existing_tag.node.changeset.user.email, "test") + basic_authorization existing_tag.node.changeset.user.email, "test" # add an identical tag to the node tag_xml = XML::Node.new("tag") @@ -492,23 +492,23 @@ class NodeControllerTest < ActionController::TestCase changeset = create(:changeset, :user => user) ## First try with the non-data public user - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # try and put something into a string that the API might # use unquoted and therefore allow code injection... - content "" + - '' + + content "" \ + '' \ "" put :create assert_require_public_data "Shouldn't be able to create with non-public user" ## Then try with the public data user - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # try and put something into a string that the API might # use unquoted and therefore allow code injection... - content "" + - '' + + content "" \ + '' \ "" put :create assert_response :success diff --git a/test/controllers/notes_controller_test.rb b/test/controllers/notes_controller_test.rb index e19810851..200f284d8 100644 --- a/test/controllers/notes_controller_test.rb +++ b/test/controllers/notes_controller_test.rb @@ -303,7 +303,7 @@ class NotesControllerTest < ActionController::TestCase ActionMailer::Base.deliveries.clear - basic_authorization(third_user.email, "test") + basic_authorization third_user.email, "test" assert_difference "NoteComment.count", 1 do assert_difference "ActionMailer::Base.deliveries.size", 2 do @@ -397,7 +397,7 @@ class NotesControllerTest < ActionController::TestCase post :close, :params => { :id => open_note_with_comment.id, :text => "This is a close comment", :format => "json" } assert_response :unauthorized - basic_authorization(user.email, "test") + basic_authorization user.email, "test" post :close, :params => { :id => open_note_with_comment.id, :text => "This is a close comment", :format => "json" } assert_response :success @@ -428,7 +428,7 @@ class NotesControllerTest < ActionController::TestCase post :close assert_response :unauthorized - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" post :close assert_response :bad_request @@ -454,7 +454,7 @@ class NotesControllerTest < ActionController::TestCase post :reopen, :params => { :id => closed_note_with_comment.id, :text => "This is a reopen comment", :format => "json" } assert_response :unauthorized - basic_authorization(user.email, "test") + basic_authorization user.email, "test" post :reopen, :params => { :id => closed_note_with_comment.id, :text => "This is a reopen comment", :format => "json" } assert_response :success @@ -487,7 +487,7 @@ class NotesControllerTest < ActionController::TestCase post :reopen, :params => { :id => hidden_note_with_comment.id } assert_response :unauthorized - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" post :reopen, :params => { :id => 12345 } assert_response :not_found @@ -606,12 +606,12 @@ class NotesControllerTest < ActionController::TestCase delete :destroy, :params => { :id => open_note_with_comment.id, :text => "This is a hide comment", :format => "json" } assert_response :unauthorized - basic_authorization(user.email, "test") + basic_authorization user.email, "test" delete :destroy, :params => { :id => open_note_with_comment.id, :text => "This is a hide comment", :format => "json" } assert_response :forbidden - basic_authorization(moderator_user.email, "test") + basic_authorization moderator_user.email, "test" delete :destroy, :params => { :id => open_note_with_comment.id, :text => "This is a hide comment", :format => "json" } assert_response :success @@ -636,12 +636,12 @@ class NotesControllerTest < ActionController::TestCase delete :destroy, :params => { :id => 12345, :format => "json" } assert_response :unauthorized - basic_authorization(user.email, "test") + basic_authorization user.email, "test" delete :destroy, :params => { :id => 12345, :format => "json" } assert_response :forbidden - basic_authorization(moderator_user.email, "test") + basic_authorization moderator_user.email, "test" delete :destroy, :params => { :id => 12345, :format => "json" } assert_response :not_found diff --git a/test/controllers/old_node_controller_test.rb b/test/controllers/old_node_controller_test.rb index be4254279..e08fbb65e 100644 --- a/test/controllers/old_node_controller_test.rb +++ b/test/controllers/old_node_controller_test.rb @@ -40,7 +40,7 @@ class OldNodeControllerTest < ActionController::TestCase propagate_tags(node, node.old_nodes.last) ## First try this with a non-public user - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # setup a simple XML node xml_doc = private_node.to_xml @@ -89,7 +89,7 @@ class OldNodeControllerTest < ActionController::TestCase # probably should check that they didn't get written to the database ## Now do it with the public user - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # setup a simple XML node @@ -137,7 +137,7 @@ class OldNodeControllerTest < ActionController::TestCase end # check all the versions - versions.keys.each do |key| + versions.each_key do |key| get :version, :params => { :id => nodeid, :version => key.to_i } assert_response :success, @@ -206,7 +206,7 @@ class OldNodeControllerTest < ActionController::TestCase # test the redaction of an old version of a node, while being # authorised as a normal user. def test_redact_node_normal_user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" node = create(:node, :with_history, :version => 4) node_v3 = node.old_nodes.find_by(:version => 3) @@ -220,7 +220,7 @@ class OldNodeControllerTest < ActionController::TestCase # test that, even as moderator, the current version of a node # can't be redacted. def test_redact_node_current_version - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" node = create(:node, :with_history, :version => 4) node_v4 = node.old_nodes.find_by(:version => 4) @@ -242,7 +242,7 @@ class OldNodeControllerTest < ActionController::TestCase assert_response :forbidden, "Redacted node shouldn't be visible via the version API." # not even to a logged-in user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" get :version, :params => { :id => node_v1.node_id, :version => node_v1.version } assert_response :forbidden, "Redacted node shouldn't be visible via the version API, even when logged in." end @@ -259,7 +259,7 @@ class OldNodeControllerTest < ActionController::TestCase assert_select "osm node[id='#{node_v1.node_id}'][version='#{node_v1.version}']", 0, "redacted node #{node_v1.node_id} version #{node_v1.version} shouldn't be present in the history." # not even to a logged-in user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" get :history, :params => { :id => node_v1.node_id } assert_response :success, "Redaction shouldn't have stopped history working." assert_select "osm node[id='#{node_v1.node_id}'][version='#{node_v1.version}']", 0, "redacted node #{node_v1.node_id} version #{node_v1.version} shouldn't be present in the history, even when logged in." @@ -271,7 +271,7 @@ class OldNodeControllerTest < ActionController::TestCase def test_redact_node_moderator node = create(:node, :with_history, :version => 4) node_v3 = node.old_nodes.find_by(:version => 3) - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" do_redact_node(node_v3, create(:redaction)) assert_response :success, "should be OK to redact old version as moderator." @@ -297,13 +297,13 @@ class OldNodeControllerTest < ActionController::TestCase def test_redact_node_is_redacted node = create(:node, :with_history, :version => 4) node_v3 = node.old_nodes.find_by(:version => 3) - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" do_redact_node(node_v3, create(:redaction)) assert_response :success, "should be OK to redact old version as moderator." # re-auth as non-moderator - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # check can't see the redacted data get :version, :params => { :id => node_v3.node_id, :version => node_v3.version } @@ -336,7 +336,7 @@ class OldNodeControllerTest < ActionController::TestCase node_v1 = node.old_nodes.find_by(:version => 1) node_v1.redact!(create(:redaction)) - basic_authorization(user.email, "test") + basic_authorization user.email, "test" post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version } assert_response :forbidden, "should need to be moderator to unredact." @@ -351,7 +351,7 @@ class OldNodeControllerTest < ActionController::TestCase node_v1 = node.old_nodes.find_by(:version => 1) node_v1.redact!(create(:redaction)) - basic_authorization(moderator_user.email, "test") + basic_authorization moderator_user.email, "test" post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version } assert_response :success, "should be OK to unredact old version as moderator." @@ -366,7 +366,7 @@ class OldNodeControllerTest < ActionController::TestCase assert_response :success, "Unredaction shouldn't have stopped history working." assert_select "osm node[id='#{node_v1.node_id}'][version='#{node_v1.version}']", 1, "node #{node_v1.node_id} version #{node_v1.version} should now be present in the history for moderators without passing flag." - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # check normal user can now see the redacted data get :version, :params => { :id => node_v1.node_id, :version => node_v1.version } diff --git a/test/controllers/old_relation_controller_test.rb b/test/controllers/old_relation_controller_test.rb index 28fd78f3b..be91962f8 100644 --- a/test/controllers/old_relation_controller_test.rb +++ b/test/controllers/old_relation_controller_test.rb @@ -50,7 +50,7 @@ class OldRelationControllerTest < ActionController::TestCase relation = create(:relation, :with_history, :version => 4) relation_v3 = relation.old_relations.find_by(:version => 3) - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" do_redact_relation(relation_v3, create(:redaction)) assert_response :forbidden, "should need to be moderator to redact." @@ -63,7 +63,7 @@ class OldRelationControllerTest < ActionController::TestCase relation = create(:relation, :with_history, :version => 4) relation_latest = relation.old_relations.last - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" do_redact_relation(relation_latest, create(:redaction)) assert_response :bad_request, "shouldn't be OK to redact current version as moderator." @@ -81,7 +81,7 @@ class OldRelationControllerTest < ActionController::TestCase assert_response :forbidden, "Redacted relation shouldn't be visible via the version API." # not even to a logged-in user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" get :version, :params => { :id => relation_v1.relation_id, :version => relation_v1.version } assert_response :forbidden, "Redacted relation shouldn't be visible via the version API, even when logged in." end @@ -98,7 +98,7 @@ class OldRelationControllerTest < ActionController::TestCase assert_select "osm relation[id='#{relation_v1.relation_id}'][version='#{relation_v1.version}']", 0, "redacted relation #{relation_v1.relation_id} version #{relation_v1.version} shouldn't be present in the history." # not even to a logged-in user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" get :version, :params => { :id => relation_v1.relation_id, :version => relation_v1.version } get :history, :params => { :id => relation_v1.relation_id } assert_response :success, "Redaction shouldn't have stopped history working." @@ -112,7 +112,7 @@ class OldRelationControllerTest < ActionController::TestCase relation = create(:relation, :with_history, :version => 4) relation_v3 = relation.old_relations.find_by(:version => 3) - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" do_redact_relation(relation_v3, create(:redaction)) assert_response :success, "should be OK to redact old version as moderator." @@ -139,13 +139,13 @@ class OldRelationControllerTest < ActionController::TestCase relation = create(:relation, :with_history, :version => 4) relation_v3 = relation.old_relations.find_by(:version => 3) - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" do_redact_relation(relation_v3, create(:redaction)) assert_response :success, "should be OK to redact old version as moderator." # re-auth as non-moderator - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # check can't see the redacted data get :version, :params => { :id => relation_v3.relation_id, :version => relation_v3.version } @@ -177,7 +177,7 @@ class OldRelationControllerTest < ActionController::TestCase relation_v1 = relation.old_relations.find_by(:version => 1) relation_v1.redact!(create(:redaction)) - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" post :redact, :params => { :id => relation_v1.relation_id, :version => relation_v1.version } assert_response :forbidden, "should need to be moderator to unredact." @@ -191,7 +191,7 @@ class OldRelationControllerTest < ActionController::TestCase relation_v1 = relation.old_relations.find_by(:version => 1) relation_v1.redact!(create(:redaction)) - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" post :redact, :params => { :id => relation_v1.relation_id, :version => relation_v1.version } assert_response :success, "should be OK to unredact old version as moderator." @@ -206,7 +206,7 @@ class OldRelationControllerTest < ActionController::TestCase assert_response :success, "Redaction shouldn't have stopped history working." assert_select "osm relation[id='#{relation_v1.relation_id}'][version='#{relation_v1.version}']", 1, "relation #{relation_v1.relation_id} version #{relation_v1.version} should still be present in the history for moderators." - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # check normal user can now see the redacted data get :version, :params => { :id => relation_v1.relation_id, :version => relation_v1.version } diff --git a/test/controllers/old_way_controller_test.rb b/test/controllers/old_way_controller_test.rb index 176f7384d..1fff79187 100644 --- a/test/controllers/old_way_controller_test.rb +++ b/test/controllers/old_way_controller_test.rb @@ -90,7 +90,7 @@ class OldWayControllerTest < ActionController::TestCase # test the redaction of an old version of a way, while being # authorised as a normal user. def test_redact_way_normal_user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" way = create(:way, :with_history, :version => 4) way_v3 = way.old_ways.find_by(:version => 3) @@ -102,7 +102,7 @@ class OldWayControllerTest < ActionController::TestCase # test that, even as moderator, the current version of a way # can't be redacted. def test_redact_way_current_version - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" way = create(:way, :with_history, :version => 4) way_latest = way.old_ways.last @@ -122,7 +122,7 @@ class OldWayControllerTest < ActionController::TestCase assert_response :forbidden, "Redacted way shouldn't be visible via the version API." # not even to a logged-in user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" get :version, :params => { :id => way_v1.way_id, :version => way_v1.version } assert_response :forbidden, "Redacted way shouldn't be visible via the version API, even when logged in." end @@ -139,7 +139,7 @@ class OldWayControllerTest < ActionController::TestCase assert_select "osm way[id='#{way_v1.way_id}'][version='#{way_v1.version}']", 0, "redacted way #{way_v1.way_id} version #{way_v1.version} shouldn't be present in the history." # not even to a logged-in user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" get :version, :params => { :id => way_v1.way_id, :version => way_v1.version } get :history, :params => { :id => way_v1.way_id } assert_response :success, "Redaction shouldn't have stopped history working." @@ -152,7 +152,7 @@ class OldWayControllerTest < ActionController::TestCase def test_redact_way_moderator way = create(:way, :with_history, :version => 4) way_v3 = way.old_ways.find_by(:version => 3) - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" do_redact_way(way_v3, create(:redaction)) assert_response :success, "should be OK to redact old version as moderator." @@ -178,13 +178,13 @@ class OldWayControllerTest < ActionController::TestCase def test_redact_way_is_redacted way = create(:way, :with_history, :version => 4) way_v3 = way.old_ways.find_by(:version => 3) - basic_authorization(create(:moderator_user).email, "test") + basic_authorization create(:moderator_user).email, "test" do_redact_way(way_v3, create(:redaction)) assert_response :success, "should be OK to redact old version as moderator." # re-auth as non-moderator - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # check can't see the redacted data get :version, :params => { :id => way_v3.way_id, :version => way_v3.version } @@ -216,7 +216,7 @@ class OldWayControllerTest < ActionController::TestCase way_v1 = way.old_ways.find_by(:version => 1) way_v1.redact!(create(:redaction)) - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" post :redact, :params => { :id => way_v1.way_id, :version => way_v1.version } assert_response :forbidden, "should need to be moderator to unredact." @@ -231,7 +231,7 @@ class OldWayControllerTest < ActionController::TestCase way_v1 = way.old_ways.find_by(:version => 1) way_v1.redact!(create(:redaction)) - basic_authorization(moderator_user.email, "test") + basic_authorization moderator_user.email, "test" post :redact, :params => { :id => way_v1.way_id, :version => way_v1.version } assert_response :success, "should be OK to unredact old version as moderator." @@ -246,7 +246,7 @@ class OldWayControllerTest < ActionController::TestCase assert_response :success, "Unredaction shouldn't have stopped history working." assert_select "osm way[id='#{way_v1.way_id}'][version='#{way_v1.version}']", 1, "way #{way_v1.way_id} version #{way_v1.version} should still be present in the history for moderators." - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # check normal user can now see the unredacted data get :version, :params => { :id => way_v1.way_id, :version => way_v1.version } diff --git a/test/controllers/relation_controller_test.rb b/test/controllers/relation_controller_test.rb index 487d99b80..f90b6b58e 100644 --- a/test/controllers/relation_controller_test.rb +++ b/test/controllers/relation_controller_test.rb @@ -216,8 +216,8 @@ class RelationControllerTest < ActionController::TestCase ### # create an relation with a node as member # This time try with a role attribute in the relation - content "" + - "" + + content "" \ + "" \ "" put :create # hope for forbidden due to user @@ -227,7 +227,7 @@ class RelationControllerTest < ActionController::TestCase ### # create an relation with a node as member, this time test that we don't # need a role attribute to be included - content "" + + content "" \ "" + "" put :create # hope for forbidden due to user @@ -236,9 +236,9 @@ class RelationControllerTest < ActionController::TestCase ### # create an relation with a way and a node as members - content "" + - "" + - "" + + content "" \ + "" \ + "" \ "" put :create # hope for forbidden, due to user @@ -277,8 +277,8 @@ class RelationControllerTest < ActionController::TestCase ### # create an relation with a node as member # This time try with a role attribute in the relation - content "" + - "" + + content "" \ + "" \ "" put :create # hope for success @@ -308,7 +308,7 @@ class RelationControllerTest < ActionController::TestCase ### # create an relation with a node as member, this time test that we don't # need a role attribute to be included - content "" + + content "" \ "" + "" put :create # hope for success @@ -337,9 +337,9 @@ class RelationControllerTest < ActionController::TestCase ### # create an relation with a way and a node as members - content "" + - "" + - "" + + content "" \ + "" \ + "" \ "" put :create # hope for success @@ -461,8 +461,8 @@ class RelationControllerTest < ActionController::TestCase basic_authorization user.email, "test" # create a relation with non-existing node as member - content "" + - "" + + content "" \ + "" \ "" put :create # expect failure @@ -482,8 +482,8 @@ class RelationControllerTest < ActionController::TestCase basic_authorization user.email, "test" # create some xml that should return an error - content "" + - "" + + content "" \ + "" \ "" put :create # expect failure @@ -514,7 +514,7 @@ class RelationControllerTest < ActionController::TestCase assert_response :unauthorized ## Then try with the private user, to make sure that you get a forbidden - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # this shouldn't work, as we should need the payload... delete :delete, :params => { :id => relation.id } @@ -556,7 +556,7 @@ class RelationControllerTest < ActionController::TestCase assert_response :forbidden ## now set auth for the public user - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # this shouldn't work, as we should need the payload... delete :delete, :params => { :id => relation.id } @@ -739,7 +739,7 @@ class RelationControllerTest < ActionController::TestCase way1 = create(:way_with_nodes, :nodes_count => 2) way2 = create(:way_with_nodes, :nodes_count => 2) - basic_authorization(user.email, "test") + basic_authorization user.email, "test" doc_str = < @@ -814,14 +814,14 @@ OSM doc = XML::Parser.string(doc_str).parse ## First try with the private user - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" content doc put :create assert_response :forbidden ## Now try with the public user - basic_authorization(user.email, "test") + basic_authorization user.email, "test" content doc put :create @@ -855,7 +855,7 @@ OSM OSM doc = XML::Parser.string(doc_str).parse - basic_authorization(user.email, "test") + basic_authorization user.email, "test" content doc put :create @@ -936,7 +936,7 @@ OSM # that the changeset bounding box is +bbox+. def check_changeset_modify(bbox) ## First test with the private user to check that you get a forbidden - basic_authorization(create(:user, :data_public => false).email, "test") + basic_authorization create(:user, :data_public => false).email, "test" # create a new changeset for this operation, so we are assured # that the bounding box will be newly-generated. @@ -947,7 +947,7 @@ OSM end ## Now do the whole thing with the public user - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # create a new changeset for this operation, so we are assured # that the bounding box will be newly-generated. @@ -1063,7 +1063,7 @@ OSM assert_equal a_tags.keys, b_tags.keys, "Tag keys should be identical." a_tags.each do |k, v| assert_equal v, b_tags[k], - "Tags which were not altered should be the same. " + + "Tags which were not altered should be the same. " \ "#{a_tags.inspect} != #{b_tags.inspect}" end end diff --git a/test/controllers/trace_controller_test.rb b/test/controllers/trace_controller_test.rb index e53809840..182fe8c02 100644 --- a/test/controllers/trace_controller_test.rb +++ b/test/controllers/trace_controller_test.rb @@ -1,4 +1,5 @@ require "test_helper" +require "digest" require "minitest/mock" class TraceControllerTest < ActionController::TestCase @@ -355,15 +356,15 @@ class TraceControllerTest < ActionController::TestCase # First with no auth, which should work since the trace is public get :data, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id } - check_trace_data public_trace_file + check_trace_data public_trace_file, "848caa72f2f456d1bd6a0fdf228aa1b9" # Now with some other user, which should work since the trace is public get :data, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) } - check_trace_data public_trace_file + check_trace_data public_trace_file, "848caa72f2f456d1bd6a0fdf228aa1b9" # And finally we should be able to do it with the owner of the trace get :data, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user } - check_trace_data public_trace_file + check_trace_data public_trace_file, "848caa72f2f456d1bd6a0fdf228aa1b9" end # Test downloading a compressed trace @@ -372,15 +373,15 @@ class TraceControllerTest < ActionController::TestCase # First get the data as is get :data, :params => { :display_name => identifiable_trace_file.user.display_name, :id => identifiable_trace_file.id } - check_trace_data identifiable_trace_file, "application/x-gzip", "gpx.gz" + check_trace_data identifiable_trace_file, "c6422a3d8750faae49ed70e7e8a51b93", "application/x-gzip", "gpx.gz" # Now ask explicitly for XML format get :data, :params => { :display_name => identifiable_trace_file.user.display_name, :id => identifiable_trace_file.id, :format => "xml" } - check_trace_data identifiable_trace_file, "application/xml", "xml" + check_trace_data identifiable_trace_file, "abd6675fdf3024a84fc0a1deac147c0d", "application/xml", "xml" # Now ask explicitly for GPX format get :data, :params => { :display_name => identifiable_trace_file.user.display_name, :id => identifiable_trace_file.id, :format => "gpx" } - check_trace_data identifiable_trace_file + check_trace_data identifiable_trace_file, "abd6675fdf3024a84fc0a1deac147c0d" end # Check an anonymous trace can't be downloaded by another user @@ -397,7 +398,7 @@ class TraceControllerTest < ActionController::TestCase # And finally we should be able to do it with the owner of the trace get :data, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => anon_trace_file.user } - check_trace_data anon_trace_file + check_trace_data anon_trace_file, "66179ca44f1e93d8df62e2b88cbea732" end # Test downloading a trace that doesn't exist @@ -692,12 +693,12 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Now with some other user, which should work since the trace is public - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" get :api_read, :params => { :id => public_trace_file.id } assert_response :success # And finally we should be able to do it with the owner of the trace - basic_authorization(public_trace_file.user.display_name, "test") + basic_authorization public_trace_file.user.display_name, "test" get :api_read, :params => { :id => public_trace_file.id } assert_response :success end @@ -711,12 +712,12 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Now try with another user, which shouldn't work since the trace is anon - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" get :api_read, :params => { :id => anon_trace_file.id } assert_response :forbidden # And finally we should be able to get the trace details with the trace owner - basic_authorization(anon_trace_file.user.display_name, "test") + basic_authorization anon_trace_file.user.display_name, "test" get :api_read, :params => { :id => anon_trace_file.id } assert_response :success end @@ -730,12 +731,12 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Login, and try again - basic_authorization(deleted_trace_file.user.display_name, "test") + basic_authorization deleted_trace_file.user.display_name, "test" get :api_read, :params => { :id => 0 } assert_response :not_found # Now try a trace which did exist but has been deleted - basic_authorization(deleted_trace_file.user.display_name, "test") + basic_authorization deleted_trace_file.user.display_name, "test" get :api_read, :params => { :id => deleted_trace_file.id } assert_response :not_found end @@ -749,14 +750,14 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Now with some other user, which should work since the trace is public - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" get :api_data, :params => { :id => public_trace_file.id } - check_trace_data public_trace_file + check_trace_data public_trace_file, "848caa72f2f456d1bd6a0fdf228aa1b9" # And finally we should be able to do it with the owner of the trace - basic_authorization(public_trace_file.user.display_name, "test") + basic_authorization public_trace_file.user.display_name, "test" get :api_data, :params => { :id => public_trace_file.id } - check_trace_data public_trace_file + check_trace_data public_trace_file, "848caa72f2f456d1bd6a0fdf228aa1b9" end # Test downloading a compressed trace through the api @@ -764,19 +765,19 @@ class TraceControllerTest < ActionController::TestCase identifiable_trace_file = create(:trace, :visibility => "identifiable", :fixture => "d") # Authenticate as the owner of the trace we will be using - basic_authorization(identifiable_trace_file.user.display_name, "test") + basic_authorization identifiable_trace_file.user.display_name, "test" # First get the data as is get :api_data, :params => { :id => identifiable_trace_file.id } - check_trace_data identifiable_trace_file, "application/x-gzip", "gpx.gz" + check_trace_data identifiable_trace_file, "c6422a3d8750faae49ed70e7e8a51b93", "application/x-gzip", "gpx.gz" # Now ask explicitly for XML format get :api_data, :params => { :id => identifiable_trace_file.id, :format => "xml" } - check_trace_data identifiable_trace_file, "application/xml", "xml" + check_trace_data identifiable_trace_file, "abd6675fdf3024a84fc0a1deac147c0d", "application/xml", "xml" # Now ask explicitly for GPX format get :api_data, :params => { :id => identifiable_trace_file.id, :format => "gpx" } - check_trace_data identifiable_trace_file + check_trace_data identifiable_trace_file, "abd6675fdf3024a84fc0a1deac147c0d" end # Check an anonymous trace can't be downloaded by another user through the api @@ -788,14 +789,14 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Now with some other user, which shouldn't work since the trace is anon - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" get :api_data, :params => { :id => anon_trace_file.id } assert_response :forbidden # And finally we should be able to do it with the owner of the trace - basic_authorization(anon_trace_file.user.display_name, "test") + basic_authorization anon_trace_file.user.display_name, "test" get :api_data, :params => { :id => anon_trace_file.id } - check_trace_data anon_trace_file + check_trace_data anon_trace_file, "66179ca44f1e93d8df62e2b88cbea732" end # Test downloading a trace that doesn't exist through the api @@ -807,12 +808,12 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Login, and try again - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" get :api_data, :params => { :id => 0 } assert_response :not_found # Now try a trace which did exist but has been deleted - basic_authorization(deleted_trace_file.user.display_name, "test") + basic_authorization deleted_trace_file.user.display_name, "test" get :api_data, :params => { :id => deleted_trace_file.id } assert_response :not_found end @@ -831,7 +832,7 @@ class TraceControllerTest < ActionController::TestCase # Now authenticated create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable") assert_not_equal "trackable", user.preferences.where(:k => "gps.trace.visibility").first.v - basic_authorization(user.display_name, "test") + basic_authorization user.display_name, "test" post :api_create, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :visibility => "trackable" } assert_response :success trace = Trace.find(response.body.to_i) @@ -849,7 +850,7 @@ class TraceControllerTest < ActionController::TestCase # Now authenticated, with the legacy public flag assert_not_equal "public", user.preferences.where(:k => "gps.trace.visibility").first.v - basic_authorization(user.display_name, "test") + basic_authorization user.display_name, "test" post :api_create, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :public => 1 } assert_response :success trace = Trace.find(response.body.to_i) @@ -868,7 +869,7 @@ class TraceControllerTest < ActionController::TestCase # Now authenticated, with the legacy private flag second_user = create(:user) assert_nil second_user.preferences.where(:k => "gps.trace.visibility").first - basic_authorization(second_user.display_name, "test") + basic_authorization second_user.display_name, "test" post :api_create, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :public => 0 } assert_response :success trace = Trace.find(response.body.to_i) @@ -894,32 +895,32 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Now with some other user, which should fail - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" content public_trace_file.to_xml put :api_update, :params => { :id => public_trace_file.id } assert_response :forbidden # Now with a trace which doesn't exist - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" content public_trace_file.to_xml put :api_update, :params => { :id => 0 } assert_response :not_found # Now with a trace which did exist but has been deleted - basic_authorization(deleted_trace_file.user.display_name, "test") + basic_authorization deleted_trace_file.user.display_name, "test" content deleted_trace_file.to_xml put :api_update, :params => { :id => deleted_trace_file.id } assert_response :not_found # Now try an update with the wrong ID - basic_authorization(public_trace_file.user.display_name, "test") + basic_authorization public_trace_file.user.display_name, "test" content anon_trace_file.to_xml put :api_update, :params => { :id => public_trace_file.id } assert_response :bad_request, "should not be able to update a trace with a different ID from the XML" # And finally try an update that should work - basic_authorization(public_trace_file.user.display_name, "test") + basic_authorization public_trace_file.user.display_name, "test" t = public_trace_file t.description = "Changed description" t.visibility = "private" @@ -931,6 +932,23 @@ class TraceControllerTest < ActionController::TestCase assert_equal nt.visibility, t.visibility end + # Test that updating a trace doesn't duplicate the tags + def test_api_update_tags + tracetag = create(:tracetag) + trace = tracetag.trace + basic_authorization trace.user.display_name, "test" + + content trace.to_xml + put :api_update, :params => { :id => trace.id } + assert_response :success + + updated = Trace.find(trace.id) + # Ensure there's only one tag in the database after updating + assert_equal Tracetag.count, 1 + # The new tag object might have a different id, so check the string representation + assert_equal trace.tagstring, updated.tagstring + end + # Check deleting a trace through the api def test_api_delete public_trace_file = create(:trace, :visibility => "public") @@ -940,22 +958,22 @@ class TraceControllerTest < ActionController::TestCase assert_response :unauthorized # Now with some other user, which should fail - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" delete :api_delete, :params => { :id => public_trace_file.id } assert_response :forbidden # Now with a trace which doesn't exist - basic_authorization(create(:user).display_name, "test") + basic_authorization create(:user).display_name, "test" delete :api_delete, :params => { :id => 0 } assert_response :not_found # And finally we should be able to do it with the owner of the trace - basic_authorization(public_trace_file.user.display_name, "test") + basic_authorization public_trace_file.user.display_name, "test" delete :api_delete, :params => { :id => public_trace_file.id } assert_response :success # Try it a second time, which should fail - basic_authorization(public_trace_file.user.display_name, "test") + basic_authorization public_trace_file.user.display_name, "test" delete :api_delete, :params => { :id => public_trace_file.id } assert_response :not_found end @@ -1017,8 +1035,9 @@ class TraceControllerTest < ActionController::TestCase end end - def check_trace_data(trace, content_type = "application/gpx+xml", extension = "gpx") + def check_trace_data(trace, digest, content_type = "application/gpx+xml", extension = "gpx") assert_response :success + assert_equal digest, Digest::MD5.hexdigest(response.body) assert_equal content_type, response.content_type assert_equal "attachment; filename=\"#{trace.id}.#{extension}\"", @response.header["Content-Disposition"] end diff --git a/test/controllers/user_controller_test.rb b/test/controllers/user_controller_test.rb index df5ba7fe7..e149b83c7 100644 --- a/test/controllers/user_controller_test.rb +++ b/test/controllers/user_controller_test.rb @@ -749,6 +749,12 @@ class UserControllerTest < ActionController::TestCase assert_response :success assert_template :reset_password + # Test that errors are reported for erroneous submissions + post :reset_password, :params => { :token => token.token, :user => { :pass_crypt => "new_password", :pass_crypt_confirmation => "different_password" } } + assert_response :success + assert_template :reset_password + assert_select "div#errorExplanation" + # Test setting a new password post :reset_password, :params => { :token => token.token, :user => { :pass_crypt => "new_password", :pass_crypt_confirmation => "new_password" } } assert_response :redirect @@ -772,7 +778,7 @@ class UserControllerTest < ActionController::TestCase # you are not logged in get :account, :params => { :display_name => user.display_name } assert_response :redirect - assert_redirected_to :controller => :user, :action => "login", :referer => "/user/#{URI.encode(user.display_name)}/account" + assert_redirected_to :controller => :user, :action => "login", :referer => "/user/#{ERB::Util.u(user.display_name)}/account" # Make sure that you are blocked when not logged in as the right user get :account, :params => { :display_name => user.display_name }, :session => { :user => create(:user) } @@ -782,6 +788,11 @@ class UserControllerTest < ActionController::TestCase get :account, :params => { :display_name => user.display_name }, :session => { :user => user } assert_response :success assert_template :account + assert_select "form#accountForm" do |form| + assert_equal "post", form.attr("method").to_s + assert_select "input[name='_method']", false + assert_equal "/user/#{ERB::Util.u(user.display_name)}/account", form.attr("action").to_s + end # Updating the description should work user.description = "new description" @@ -848,7 +859,7 @@ class UserControllerTest < ActionController::TestCase # Adding external authentication should redirect to the auth provider post :account, :params => { :display_name => user.display_name, :user => user.attributes.merge(:auth_provider => "openid", :auth_uid => "gmail.com") }, :session => { :user => user } assert_response :redirect - assert_redirected_to auth_path(:provider => "openid", :openid_url => "https://www.google.com/accounts/o8/id", :origin => "/user/#{URI.encode(user.display_name)}/account") + assert_redirected_to auth_path(:provider => "openid", :openid_url => "https://www.google.com/accounts/o8/id", :origin => "/user/#{ERB::Util.u(user.display_name)}/account") # Changing name to one that exists should fail new_attributes = user.attributes.dup.merge(:display_name => create(:user).display_name) @@ -930,14 +941,14 @@ class UserControllerTest < ActionController::TestCase get :view, :params => { :display_name => user.display_name } assert_response :success assert_select "div#userinformation" do - assert_select "a[href^='/user/#{URI.encode(user.display_name)}/history']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/traces']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/diary']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/diary/comments']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/account']", 0 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/blocks']", 0 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/blocks_by']", 0 - assert_select "a[href='/blocks/new/#{URI.encode(user.display_name)}']", 0 + assert_select "a[href^='/user/#{ERB::Util.u(user.display_name)}/history']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/traces']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/diary']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/diary/comments']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/account']", 0 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/blocks']", 0 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/blocks_by']", 0 + assert_select "a[href='/blocks/new/#{ERB::Util.u(user.display_name)}']", 0 end # Test a user who has been blocked @@ -946,14 +957,14 @@ class UserControllerTest < ActionController::TestCase get :view, :params => { :display_name => blocked_user.display_name } assert_response :success assert_select "div#userinformation" do - assert_select "a[href^='/user/#{URI.encode(blocked_user.display_name)}/history']", 1 - assert_select "a[href='/user/#{URI.encode(blocked_user.display_name)}/traces']", 1 - assert_select "a[href='/user/#{URI.encode(blocked_user.display_name)}/diary']", 1 - assert_select "a[href='/user/#{URI.encode(blocked_user.display_name)}/diary/comments']", 1 - assert_select "a[href='/user/#{URI.encode(blocked_user.display_name)}/account']", 0 - assert_select "a[href='/user/#{URI.encode(blocked_user.display_name)}/blocks']", 1 - assert_select "a[href='/user/#{URI.encode(blocked_user.display_name)}/blocks_by']", 0 - assert_select "a[href='/blocks/new/#{URI.encode(blocked_user.display_name)}']", 0 + assert_select "a[href^='/user/#{ERB::Util.u(blocked_user.display_name)}/history']", 1 + assert_select "a[href='/user/#{ERB::Util.u(blocked_user.display_name)}/traces']", 1 + assert_select "a[href='/user/#{ERB::Util.u(blocked_user.display_name)}/diary']", 1 + assert_select "a[href='/user/#{ERB::Util.u(blocked_user.display_name)}/diary/comments']", 1 + assert_select "a[href='/user/#{ERB::Util.u(blocked_user.display_name)}/account']", 0 + assert_select "a[href='/user/#{ERB::Util.u(blocked_user.display_name)}/blocks']", 1 + assert_select "a[href='/user/#{ERB::Util.u(blocked_user.display_name)}/blocks_by']", 0 + assert_select "a[href='/blocks/new/#{ERB::Util.u(blocked_user.display_name)}']", 0 end # Test a moderator who has applied blocks @@ -962,14 +973,14 @@ class UserControllerTest < ActionController::TestCase get :view, :params => { :display_name => moderator_user.display_name } assert_response :success assert_select "div#userinformation" do - assert_select "a[href^='/user/#{URI.encode(moderator_user.display_name)}/history']", 1 - assert_select "a[href='/user/#{URI.encode(moderator_user.display_name)}/traces']", 1 - assert_select "a[href='/user/#{URI.encode(moderator_user.display_name)}/diary']", 1 - assert_select "a[href='/user/#{URI.encode(moderator_user.display_name)}/diary/comments']", 1 - assert_select "a[href='/user/#{URI.encode(moderator_user.display_name)}/account']", 0 - assert_select "a[href='/user/#{URI.encode(moderator_user.display_name)}/blocks']", 0 - assert_select "a[href='/user/#{URI.encode(moderator_user.display_name)}/blocks_by']", 1 - assert_select "a[href='/blocks/new/#{URI.encode(moderator_user.display_name)}']", 0 + assert_select "a[href^='/user/#{ERB::Util.u(moderator_user.display_name)}/history']", 1 + assert_select "a[href='/user/#{ERB::Util.u(moderator_user.display_name)}/traces']", 1 + assert_select "a[href='/user/#{ERB::Util.u(moderator_user.display_name)}/diary']", 1 + assert_select "a[href='/user/#{ERB::Util.u(moderator_user.display_name)}/diary/comments']", 1 + assert_select "a[href='/user/#{ERB::Util.u(moderator_user.display_name)}/account']", 0 + assert_select "a[href='/user/#{ERB::Util.u(moderator_user.display_name)}/blocks']", 0 + assert_select "a[href='/user/#{ERB::Util.u(moderator_user.display_name)}/blocks_by']", 1 + assert_select "a[href='/blocks/new/#{ERB::Util.u(moderator_user.display_name)}']", 0 end # Login as a normal user @@ -979,14 +990,14 @@ class UserControllerTest < ActionController::TestCase get :view, :params => { :display_name => user.display_name } assert_response :success assert_select "div#userinformation" do - assert_select "a[href^='/user/#{URI.encode(user.display_name)}/history']", 1 + assert_select "a[href^='/user/#{ERB::Util.u(user.display_name)}/history']", 1 assert_select "a[href='/traces/mine']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/diary']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/diary/comments']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/account']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/blocks']", 0 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/blocks_by']", 0 - assert_select "a[href='/blocks/new/#{URI.encode(user.display_name)}']", 0 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/diary']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/diary/comments']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/account']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/blocks']", 0 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/blocks_by']", 0 + assert_select "a[href='/blocks/new/#{ERB::Util.u(user.display_name)}']", 0 end # Login as a moderator @@ -996,14 +1007,14 @@ class UserControllerTest < ActionController::TestCase get :view, :params => { :display_name => user.display_name } assert_response :success assert_select "div#userinformation" do - assert_select "a[href^='/user/#{URI.encode(user.display_name)}/history']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/traces']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/diary']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/diary/comments']", 1 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/account']", 0 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/blocks']", 0 - assert_select "a[href='/user/#{URI.encode(user.display_name)}/blocks_by']", 0 - assert_select "a[href='/blocks/new/#{URI.encode(user.display_name)}']", 1 + assert_select "a[href^='/user/#{ERB::Util.u(user.display_name)}/history']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/traces']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/diary']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/diary/comments']", 1 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/account']", 0 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/blocks']", 0 + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/blocks_by']", 0 + assert_select "a[href='/blocks/new/#{ERB::Util.u(user.display_name)}']", 1 end end @@ -1093,7 +1104,7 @@ class UserControllerTest < ActionController::TestCase assert_response :unauthorized # check that we get a response when logged in - basic_authorization(user.email, "test") + basic_authorization user.email, "test" get :api_details assert_response :success assert_equal "text/xml", response.content_type @@ -1148,7 +1159,7 @@ class UserControllerTest < ActionController::TestCase assert_response :unauthorized # check that we get a response when logged in - basic_authorization(user.email, "test") + basic_authorization user.email, "test" get :api_gpx_files assert_response :success assert_equal "application/xml", response.content_type diff --git a/test/controllers/user_preference_controller_test.rb b/test/controllers/user_preference_controller_test.rb index 2287993e8..7f614587d 100644 --- a/test/controllers/user_preference_controller_test.rb +++ b/test/controllers/user_preference_controller_test.rb @@ -34,7 +34,7 @@ class UserPreferenceControllerTest < ActionController::TestCase assert_response :unauthorized, "should be authenticated" # authenticate as a user with no preferences - basic_authorization(create(:user).email, "test") + basic_authorization create(:user).email, "test" # try the read again get :read @@ -48,7 +48,7 @@ class UserPreferenceControllerTest < ActionController::TestCase user = create(:user) user_preference = create(:user_preference, :user => user) user_preference2 = create(:user_preference, :user => user) - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # try the read again get :read @@ -74,7 +74,7 @@ class UserPreferenceControllerTest < ActionController::TestCase assert_response :unauthorized, "should be authenticated" # authenticate as a user with preferences - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # try the read again get :read_one, :params => { :preference_key => "key" } @@ -107,7 +107,7 @@ class UserPreferenceControllerTest < ActionController::TestCase end # authenticate as a user with preferences - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # try the put again assert_no_difference "UserPreference.count" do @@ -158,7 +158,7 @@ class UserPreferenceControllerTest < ActionController::TestCase end # authenticate as a user with preferences - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # try adding a new preference assert_difference "UserPreference.count", 1 do @@ -195,7 +195,7 @@ class UserPreferenceControllerTest < ActionController::TestCase assert_equal "value", UserPreference.find([user.id, "key"]).v # authenticate as a user with preferences - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # try the delete again assert_difference "UserPreference.count", -1 do diff --git a/test/controllers/way_controller_test.rb b/test/controllers/way_controller_test.rb index b93a13759..285efe269 100644 --- a/test/controllers/way_controller_test.rb +++ b/test/controllers/way_controller_test.rb @@ -128,8 +128,8 @@ class WayControllerTest < ActionController::TestCase changeset_id = private_changeset.id # create a way with pre-existing nodes - content "" + - "" + + content "" \ + "" \ "" put :create # hope for failure @@ -143,8 +143,8 @@ class WayControllerTest < ActionController::TestCase changeset_id = changeset.id # create a way with pre-existing nodes - content "" + - "" + + content "" \ + "" \ "" put :create # hope for success @@ -188,7 +188,7 @@ class WayControllerTest < ActionController::TestCase # use the first user's open changeset # create a way with non-existing node - content "" + + content "" \ "" put :create # expect failure @@ -196,7 +196,7 @@ class WayControllerTest < ActionController::TestCase "way upload with invalid node using a private user did not return 'forbidden'" # create a way with no nodes - content "" + + content "" \ "" put :create # expect failure @@ -204,7 +204,7 @@ class WayControllerTest < ActionController::TestCase "way upload with no node using a private userdid not return 'forbidden'" # create a way inside a closed changeset - content "" + + content "" \ "" put :create # expect failure @@ -216,7 +216,7 @@ class WayControllerTest < ActionController::TestCase # use the first user's open changeset # create a way with non-existing node - content "" + + content "" \ "" put :create # expect failure @@ -225,7 +225,7 @@ class WayControllerTest < ActionController::TestCase assert_equal "Precondition failed: Way requires the nodes with id in (0), which either do not exist, or are not visible.", @response.body # create a way with no nodes - content "" + + content "" \ "" put :create # expect failure @@ -234,7 +234,7 @@ class WayControllerTest < ActionController::TestCase assert_equal "Precondition failed: Cannot create way: data is invalid.", @response.body # create a way inside a closed changeset - content "" + + content "" \ "" put :create # expect failure @@ -242,9 +242,9 @@ class WayControllerTest < ActionController::TestCase "way upload to closed changeset did not return 'conflict'" # create a way with a tag which is too long - content "" + - "" + - "" + + content "" \ + "" \ + "" \ "" put :create # expect failure @@ -278,7 +278,7 @@ class WayControllerTest < ActionController::TestCase assert_response :unauthorized # now set auth using the private user - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # this shouldn't work as with the 0.6 api we need pay load to delete delete :delete, :params => { :id => private_way.id } @@ -327,7 +327,7 @@ class WayControllerTest < ActionController::TestCase ### Now check with a public user # now set auth - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # this shouldn't work as with the 0.6 api we need pay load to delete delete :delete, :params => { :id => way.id } @@ -397,7 +397,7 @@ class WayControllerTest < ActionController::TestCase ## Second test with the private user # setup auth - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" ## trying to break changesets @@ -435,7 +435,7 @@ class WayControllerTest < ActionController::TestCase ## Finally test with the public user # setup auth - basic_authorization(user.email, "test") + basic_authorization user.email, "test" ## trying to break changesets @@ -519,7 +519,7 @@ class WayControllerTest < ActionController::TestCase ## Try with the non-public user # setup auth - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # add an identical tag to the way tag_xml = XML::Node.new("tag") @@ -538,7 +538,7 @@ class WayControllerTest < ActionController::TestCase ## Now try with the public user # setup auth - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # add an identical tag to the way tag_xml = XML::Node.new("tag") @@ -569,7 +569,7 @@ class WayControllerTest < ActionController::TestCase ## Try with the non-public user # setup auth - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # add an identical tag to the way tag_xml = XML::Node.new("tag") @@ -588,7 +588,7 @@ class WayControllerTest < ActionController::TestCase ## Now try with the public user # setup auth - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # add an identical tag to the way tag_xml = XML::Node.new("tag") @@ -617,7 +617,7 @@ class WayControllerTest < ActionController::TestCase ## First test with the non-public user so should be rejected # setup auth - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # create duplicate tag tag_xml = XML::Node.new("tag") @@ -638,7 +638,7 @@ class WayControllerTest < ActionController::TestCase ## Now test with the public user # setup auth - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # create duplicate tag tag_xml = XML::Node.new("tag") @@ -671,7 +671,7 @@ class WayControllerTest < ActionController::TestCase ## First make sure that you can't with a non-public user # setup auth - basic_authorization(private_user.email, "test") + basic_authorization private_user.email, "test" # add the tag into the existing xml way_str = "" @@ -687,7 +687,7 @@ class WayControllerTest < ActionController::TestCase ## Now do it with a public user # setup auth - basic_authorization(user.email, "test") + basic_authorization user.email, "test" # add the tag into the existing xml way_str = "" diff --git a/test/helpers/application_helper_test.rb b/test/helpers/application_helper_test.rb index 720113e65..d1c41d62c 100644 --- a/test/helpers/application_helper_test.rb +++ b/test/helpers/application_helper_test.rb @@ -1,6 +1,8 @@ require "test_helper" class ApplicationHelperTest < ActionView::TestCase + attr_accessor :current_user + def setup I18n.locale = "en" end @@ -46,7 +48,7 @@ class ApplicationHelperTest < ActionView::TestCase end def test_style_rules - @user = nil + self.current_user = nil css = style_rules assert_match /\.hidden /, css @@ -57,36 +59,36 @@ class ApplicationHelperTest < ActionView::TestCase assert_match /\.hide_unless_administrator /, css assert_match /\.hide_unless_moderator /, css - @user = create(:user) + self.current_user = create(:user) css = style_rules assert_match /\.hidden /, css assert_no_match /\.hide_unless_logged_in /, css assert_match /\.hide_if_logged_in /, css - assert_match /\.hide_if_user_#{@user.id} /, css - assert_match /\.show_if_user_#{@user.id} /, css + assert_match /\.hide_if_user_#{current_user.id} /, css + assert_match /\.show_if_user_#{current_user.id} /, css assert_match /\.hide_unless_administrator /, css assert_match /\.hide_unless_moderator /, css - @user = create(:moderator_user) + self.current_user = create(:moderator_user) css = style_rules assert_match /\.hidden /, css assert_no_match /\.hide_unless_logged_in /, css assert_match /\.hide_if_logged_in /, css - assert_match /\.hide_if_user_#{@user.id} /, css - assert_match /\.show_if_user_#{@user.id} /, css + assert_match /\.hide_if_user_#{current_user.id} /, css + assert_match /\.show_if_user_#{current_user.id} /, css assert_match /\.hide_unless_administrator /, css assert_no_match /\.hide_unless_moderator /, css - @user = create(:administrator_user) + self.current_user = create(:administrator_user) css = style_rules assert_match /\.hidden /, css assert_no_match /\.hide_unless_logged_in /, css assert_match /\.hide_if_logged_in /, css - assert_match /\.hide_if_user_#{@user.id} /, css - assert_match /\.show_if_user_#{@user.id} /, css + assert_match /\.hide_if_user_#{current_user.id} /, css + assert_match /\.show_if_user_#{current_user.id} /, css assert_no_match /\.hide_unless_administrator /, css assert_match /\.hide_unless_moderator /, css end diff --git a/test/helpers/changeset_helper_test.rb b/test/helpers/changeset_helper_test.rb index 9c45b62dc..d932138f8 100644 --- a/test/helpers/changeset_helper_test.rb +++ b/test/helpers/changeset_helper_test.rb @@ -3,7 +3,7 @@ require "test_helper" class ChangesetHelperTest < ActionView::TestCase def test_changeset_user_link changeset = create(:changeset) - assert_equal %(
      #{changeset.user.display_name}), changeset_user_link(changeset) + assert_equal %(#{changeset.user.display_name}), changeset_user_link(changeset) changeset = create(:changeset, :user => create(:user, :data_public => false)) assert_equal "anonymous", changeset_user_link(changeset) @@ -20,7 +20,7 @@ class ChangesetHelperTest < ActionView::TestCase assert_match %r{^Created .* by anonymous$}, changeset_details(changeset) changeset = create(:changeset, :created_at => Time.utc(2007, 1, 1, 0, 0, 0), :closed_at => Time.utc(2007, 1, 2, 0, 0, 0)) - user_link = %(#{changeset.user.display_name}) + user_link = %(#{changeset.user.display_name}) assert_match %r{^Closed .* by #{user_link}$}, changeset_details(changeset) end diff --git a/test/helpers/note_helper_test.rb b/test/helpers/note_helper_test.rb index 5857af6bc..408236879 100644 --- a/test/helpers/note_helper_test.rb +++ b/test/helpers/note_helper_test.rb @@ -9,7 +9,7 @@ class NoteHelperTest < ActionView::TestCase user = create(:user) assert_match %r{^Created by anonymous .* ago$}, note_event("open", date, nil) - assert_match %r{^Resolved by #{user.display_name} .* ago$}, note_event("closed", date, user) + assert_match %r{^Resolved by #{user.display_name} .* ago$}, note_event("closed", date, user) end def test_note_author @@ -18,7 +18,7 @@ class NoteHelperTest < ActionView::TestCase assert_equal "", note_author(nil) assert_equal "deleted", note_author(deleted_user) - assert_equal "#{user.display_name}", note_author(user) - assert_equal "#{user.display_name}", note_author(user, :only_path => false) + assert_equal "#{user.display_name}", note_author(user) + assert_equal "#{user.display_name}", note_author(user, :only_path => false) end end diff --git a/test/helpers/title_helper_test.rb b/test/helpers/title_helper_test.rb index 7d8355430..25486f799 100644 --- a/test/helpers/title_helper_test.rb +++ b/test/helpers/title_helper_test.rb @@ -1,4 +1,3 @@ -# coding: utf-8 require "test_helper" @@ -17,11 +16,11 @@ class TitleHelperTest < ActionView::TestCase assert_equal "Test Title", @title set_title("Test & Title") - assert_equal "OpenStreetMap%20%7C%20Test%20&%20Title", response.header["X-Page-Title"] + assert_equal "OpenStreetMap%20%7C%20Test%20%26%20Title", response.header["X-Page-Title"] assert_equal "Test & Title", @title set_title("Tést & Tïtlè") - assert_equal "OpenStreetMap%20%7C%20T%C3%A9st%20&%20T%C3%AFtl%C3%A8", response.header["X-Page-Title"] + assert_equal "OpenStreetMap%20%7C%20T%C3%A9st%20%26%20T%C3%AFtl%C3%A8", response.header["X-Page-Title"] assert_equal "Tést & Tïtlè", @title end end diff --git a/test/helpers/user_helper_test.rb b/test/helpers/user_helper_test.rb index ea3464052..eedc8775c 100644 --- a/test/helpers/user_helper_test.rb +++ b/test/helpers/user_helper_test.rb @@ -55,11 +55,11 @@ class UserHelperTest < ActionView::TestCase end def test_user_image_url - user = create(:user) + user = create(:user, :image_file_name => "test.jpg", :image_fingerprint => "d41d8cd98f00b204e9800998ecf8427e") gravatar_user = create(:user, :image_use_gravatar => true) url = user_image_url(user) - assert_match %r{^/users/images/original.png$}, url + assert_match %r{^/attachments/users/images/\d{3}/\d{3}/\d{3}/original/d41d8cd98f00b204e9800998ecf8427e.jpg$}, url url = user_image_url(gravatar_user) assert_match %r{^http://www.gravatar.com/avatar/}, url diff --git a/test/helpers/user_roles_helper_test.rb b/test/helpers/user_roles_helper_test.rb index 880c16e59..058d6abd4 100644 --- a/test/helpers/user_roles_helper_test.rb +++ b/test/helpers/user_roles_helper_test.rb @@ -1,11 +1,12 @@ require "test_helper" class UserRolesHelperTest < ActionView::TestCase + attr_accessor :current_user + def test_role_icon_normal - user = create(:user) - @user = user + self.current_user = create(:user) - icon = role_icon(user, "moderator") + icon = role_icon(current_user, "moderator") assert_dom_equal "", icon icon = role_icon(create(:moderator_user), "moderator") @@ -13,22 +14,21 @@ class UserRolesHelperTest < ActionView::TestCase end def test_role_icon_administrator - @user = create(:administrator_user) + self.current_user = create(:administrator_user) user = create(:user) icon = role_icon(user, "moderator") - assert_dom_equal %(Grant moderator access), icon + assert_dom_equal %(Grant moderator access), icon moderator_user = create(:moderator_user) icon = role_icon(moderator_user, "moderator") - assert_dom_equal %(Revoke moderator access), icon + assert_dom_equal %(Revoke moderator access), icon end def test_role_icons_normal - user = create(:user) - @user = user + self.current_user = create(:user) - icons = role_icons(user) + icons = role_icons(current_user) assert_dom_equal " ", icons icons = role_icons(create(:moderator_user)) @@ -39,18 +39,18 @@ class UserRolesHelperTest < ActionView::TestCase end def test_role_icons_administrator - @user = create(:administrator_user) + self.current_user = create(:administrator_user) user = create(:user) icons = role_icons(user) - assert_dom_equal %( Grant administrator access Grant moderator access), icons + assert_dom_equal %( Grant administrator access Grant moderator access), icons moderator_user = create(:moderator_user) icons = role_icons(moderator_user) - assert_dom_equal %( Grant administrator access Revoke moderator access), icons + assert_dom_equal %( Grant administrator access Revoke moderator access), icons super_user = create(:super_user) icons = role_icons(super_user) - assert_dom_equal %( Revoke administrator access Revoke moderator access), icons + assert_dom_equal %( Revoke administrator access Revoke moderator access), icons end end diff --git a/test/http/geocoder_us.yml b/test/http/geocoder_us.yml deleted file mode 100644 index de54aa306..000000000 --- a/test/http/geocoder_us.yml +++ /dev/null @@ -1,6 +0,0 @@ -/service/csv?zip=90210: - code: 200 - body: "34.088808, -118.40612, Beverly Hills, CA, 90210" -/service/csv?zip=00000: - code: 200 - body: "1: couldn't find this zip code: 00000! sorry" diff --git a/test/integration/client_applications_test.rb b/test/integration/client_applications_test.rb index 8c5e70784..59f234c41 100644 --- a/test/integration/client_applications_test.rb +++ b/test/integration/client_applications_test.rb @@ -12,35 +12,35 @@ class ClientApplicationsTest < ActionDispatch::IntegrationTest assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true" follow_redirect! assert_response :success - post "/login", :params => { "username" => user.email, "password" => "test", :referer => "/user/#{URI.encode(user.display_name)}" } + post "/login", :params => { "username" => user.email, "password" => "test", :referer => "/user/#{ERB::Util.u(user.display_name)}" } assert_response :redirect follow_redirect! assert_response :success assert_template "user/view" - get "/user/#{URI.encode(user.display_name)}/account" + get "/user/#{ERB::Util.u(user.display_name)}/account" assert_response :success assert_template "user/account" # check that the form to allow new client application creations exists assert_in_heading do - assert_select "ul.secondary-actions li a[href='/user/#{URI.encode(user.display_name)}/oauth_clients']" + assert_select "ul.secondary-actions li a[href='/user/#{ERB::Util.u(user.display_name)}/oauth_clients']" end # now we follow the link to the oauth client list - get "/user/#{URI.encode(user.display_name)}/oauth_clients" + get "/user/#{ERB::Util.u(user.display_name)}/oauth_clients" assert_response :success assert_in_body do - assert_select "a[href='/user/#{URI.encode(user.display_name)}/oauth_clients/new']" + assert_select "a[href='/user/#{ERB::Util.u(user.display_name)}/oauth_clients/new']" end # now we follow the link to the new oauth client page - get "/user/#{URI.encode(user.display_name)}/oauth_clients/new" + get "/user/#{ERB::Util.u(user.display_name)}/oauth_clients/new" assert_response :success assert_in_heading do assert_select "h1", "Register a new application" end assert_in_body do - assert_select "form[action='/user/#{URI.encode(user.display_name)}/oauth_clients']" do + assert_select "form[action='/user/#{ERB::Util.u(user.display_name)}/oauth_clients']" do [:name, :url, :callback_url, :support_url].each do |inp| assert_select "input[name=?]", "client_application[#{inp}]" end @@ -50,7 +50,7 @@ class ClientApplicationsTest < ActionDispatch::IntegrationTest end end - post "/user/#{URI.encode(user.display_name)}/oauth_clients", + post "/user/#{ERB::Util.u(user.display_name)}/oauth_clients", :params => { "client_application[name]" => "My New App", "client_application[url]" => "http://my.new.app.org/", "client_application[callback_url]" => "http://my.new.app.org/callback", @@ -62,7 +62,7 @@ class ClientApplicationsTest < ActionDispatch::IntegrationTest assert_equal "Registered the information successfully", flash[:notice] # now go back to the account page and check its listed under this user - get "/user/#{URI.encode(user.display_name)}/oauth_clients" + get "/user/#{ERB::Util.u(user.display_name)}/oauth_clients" assert_response :success assert_template "oauth_clients/index" assert_in_body { assert_select "div>a", "My New App" } diff --git a/test/integration/cors_test.rb b/test/integration/cors_test.rb index 05754da71..9ff7e360e 100644 --- a/test/integration/cors_test.rb +++ b/test/integration/cors_test.rb @@ -8,15 +8,20 @@ class CORSTest < ActionDispatch::IntegrationTest } assert_response :success - assert_equal "http://www.example.com", response.headers["Access-Control-Allow-Origin"] + assert_equal "*", response.headers["Access-Control-Allow-Origin"] + assert_equal "text/plain", response.content_type + assert_equal "", response.body end def test_non_api_routes_dont_allow_cross_origin_requests - assert_raises ActionController::RoutingError do - process :options, "/", :headers => { - "HTTP_ORIGIN" => "http://www.example.com", - "HTTP_ACCESS_CONTROL_REQUEST_METHOD" => "GET" - } - end + process :options, "/", :headers => { + "HTTP_ORIGIN" => "http://www.example.com", + "HTTP_ACCESS_CONTROL_REQUEST_METHOD" => "GET" + } + + assert_response :success + assert_nil response.headers["Access-Control-Allow-Origin"] + assert_nil response.content_type + assert_equal "", response.body end end diff --git a/test/integration/user_login_test.rb b/test/integration/user_login_test.rb index 538c03999..2c3e61be6 100644 --- a/test/integration/user_login_test.rb +++ b/test/integration/user_login_test.rb @@ -113,7 +113,9 @@ class UserLoginTest < ActionDispatch::IntegrationTest assert_template "login" assert_select "span.username", false - assert_select "div.flash.error", /your account has been suspended/ + assert_select "div.flash.error", /your account has been suspended/ do + assert_select "a[href='mailto:openstreetmap@example.com']", "webmaster" + end end def test_login_email_password_suspended_upcase @@ -123,7 +125,9 @@ class UserLoginTest < ActionDispatch::IntegrationTest assert_template "login" assert_select "span.username", false - assert_select "div.flash.error", /your account has been suspended/ + assert_select "div.flash.error", /your account has been suspended/ do + assert_select "a[href='mailto:openstreetmap@example.com']", "webmaster" + end end def test_login_email_password_suspended_titlecase @@ -133,7 +137,9 @@ class UserLoginTest < ActionDispatch::IntegrationTest assert_template "login" assert_select "span.username", false - assert_select "div.flash.error", /your account has been suspended/ + assert_select "div.flash.error", /your account has been suspended/ do + assert_select "a[href='mailto:openstreetmap@example.com']", "webmaster" + end end def test_login_email_password_blocked @@ -264,7 +270,9 @@ class UserLoginTest < ActionDispatch::IntegrationTest assert_template "login" assert_select "span.username", false - assert_select "div.flash.error", /your account has been suspended/ + assert_select "div.flash.error", /your account has been suspended/ do + assert_select "a[href='mailto:openstreetmap@example.com']", "webmaster" + end end def test_login_username_password_suspended_upcase @@ -274,7 +282,9 @@ class UserLoginTest < ActionDispatch::IntegrationTest assert_template "login" assert_select "span.username", false - assert_select "div.flash.error", /your account has been suspended/ + assert_select "div.flash.error", /your account has been suspended/ do + assert_select "a[href='mailto:openstreetmap@example.com']", "webmaster" + end end def test_login_username_password_suspended_downcase @@ -284,7 +294,9 @@ class UserLoginTest < ActionDispatch::IntegrationTest assert_template "login" assert_select "span.username", false - assert_select "div.flash.error", /your account has been suspended/ + assert_select "div.flash.error", /your account has been suspended/ do + assert_select "a[href='mailto:openstreetmap@example.com']", "webmaster" + end end def test_login_username_password_blocked diff --git a/test/integration/user_roles_test.rb b/test/integration/user_roles_test.rb index 3f6c24248..000ea0316 100644 --- a/test/integration/user_roles_test.rb +++ b/test/integration/user_roles_test.rb @@ -32,7 +32,7 @@ class UserRolesTest < ActionDispatch::IntegrationTest assert_response :success target_user = create(:user) - post "/user/#{URI.encode(target_user.display_name)}/role/#{role}/#{action}" + post "/user/#{ERB::Util.u(target_user.display_name)}/role/#{role}/#{action}" assert_redirected_to :controller => "user", :action => "view", :display_name => target_user.display_name reset! @@ -50,7 +50,7 @@ class UserRolesTest < ActionDispatch::IntegrationTest assert_response :success target_user = create(:user) - post "/user/#{URI.encode(target_user.display_name)}/role/#{role}/#{action}" + post "/user/#{ERB::Util.u(target_user.display_name)}/role/#{role}/#{action}" assert_redirected_to :controller => "user", :action => "view", :display_name => target_user.display_name reset! diff --git a/test/lib/bounding_box_test.rb b/test/lib/bounding_box_test.rb index 53095307d..3e0c5490b 100644 --- a/test/lib/bounding_box_test.rb +++ b/test/lib/bounding_box_test.rb @@ -306,7 +306,7 @@ class BoundingBoxTest < ActiveSupport::TestCase def check_expand(bbox, array_string, margin = 0, result = nil) array = array_string.split(",").collect(&:to_f) - result = array unless result + result ||= array bbox.expand!(BoundingBox.new(array[0], array[1], array[2], array[3]), margin) check_bbox(bbox, result) end diff --git a/test/lib/i18n_test.rb b/test/lib/i18n_test.rb index 3ead036eb..689f65097 100644 --- a/test/lib/i18n_test.rb +++ b/test/lib/i18n_test.rb @@ -13,7 +13,7 @@ class I18nTest < ActiveSupport::TestCase if default_value.is_a?(Hash) variables.push("count") - default_value.each do |_subkey, subvalue| + default_value.each_value do |subvalue| subvalue.scan(/%\{(\w+)\}/) do variables.push(Regexp.last_match(1)) end diff --git a/test/models/language_test.rb b/test/models/language_test.rb index f6a6e3234..5ba558907 100644 --- a/test/models/language_test.rb +++ b/test/models/language_test.rb @@ -1,5 +1,3 @@ -# coding: utf-8 - require "test_helper" class LanguageTest < ActiveSupport::TestCase diff --git a/vendor/assets/iD/iD.css.erb b/vendor/assets/iD/iD.css.erb index c7e02c29b..fbc19869e 100644 --- a/vendor/assets/iD/iD.css.erb +++ b/vendor/assets/iD/iD.css.erb @@ -434,8 +434,9 @@ text.gpx { fill: #FF26D4; } +/* Default - light gray */ path.area.stroke { - stroke: #fff; + stroke: #ddd; stroke-width: 1; } path.area.fill { @@ -455,33 +456,16 @@ path.stroke.old-multipolygon { stroke-linecap: butt; } -path.stroke.tag-natural { - stroke: rgb(182, 225, 153); -} -path.fill.tag-natural { - stroke: rgba(182, 225, 153, 0.3); - fill: rgba(182, 225, 153, 0.3); -} -.preset-icon-fill-area.tag-natural { - border-color: rgb(182, 225, 153); - background-color: rgba(182, 225, 153, 0.3); -} - +/* Green things */ path.stroke.tag-landuse, -path.stroke.tag-natural-wood, -path.stroke.tag-natural-tree, -path.stroke.tag-natural-grassland, -path.stroke.tag-natural-grass, +path.stroke.tag-natural, path.stroke.tag-leisure-nature_reserve, path.stroke.tag-leisure-pitch, path.stroke.tag-leisure-park { stroke: rgb(140, 208, 95); } path.fill.tag-landuse, -path.fill.tag-natural-wood, -path.fill.tag-natural-tree, -path.fill.tag-natural-grassland, -path.fill.tag-natural-grass, +path.fill.tag-natural, path.fill.tag-leisure-nature_reserve, path.fill.tag-leisure-pitch, path.fill.tag-leisure-park { @@ -489,10 +473,7 @@ path.fill.tag-leisure-park { fill: rgba(140, 208, 95, 0.3); } .preset-icon-fill-area.tag-landuse, -.preset-icon-fill-area.tag-natural-wood, -.preset-icon-fill-area.tag-natural-tree, -.preset-icon-fill-area.tag-natural-grassland, -.preset-icon-fill-area.tag-natural-grass, +.preset-icon-fill-area.tag-natural, .preset-icon-fill-area.tag-leisure-nature_reserve, .preset-icon-fill-area.tag-leisure-pitch, .preset-icon-fill-area.tag-leisure-park { @@ -500,6 +481,7 @@ path.fill.tag-leisure-park { background-color: rgba(140, 208, 95, 0.3); } +/* Blue things */ path.stroke.tag-amenity-swimming_pool, path.stroke.tag-leisure-swimming_pool, path.stroke.tag-natural-water, @@ -530,13 +512,27 @@ path.fill.tag-natural-water { background-color: rgba(119, 211, 222, 0.3); } +/* Yellow things */ +.pattern-color-beach, +.pattern-color-sand, +.pattern-color-scrub { + fill: rgba(255, 255, 148, 0.2); +} +path.stroke.tag-leisure-pitch.tag-sport-beachvolleyball, +path.stroke.tag-natural-beach, +path.stroke.tag-natural-sand, +path.stroke.tag-natural-scrub, path.stroke.tag-amenity-childcare, path.stroke.tag-amenity-kindergarten, path.stroke.tag-amenity-school, path.stroke.tag-amenity-college, path.stroke.tag-amenity-university { - stroke: rgb(255, 255, 148); + stroke: rgba(255, 255, 148, 0.75); } +path.fill.tag-leisure-pitch.tag-sport-beachvolleyball, +path.fill.tag-natural-beach, +path.fill.tag-natural-sand, +path.fill.tag-natural-scrub, path.fill.tag-amenity-childcare, path.fill.tag-amenity-kindergarten, path.fill.tag-amenity-school, @@ -545,6 +541,10 @@ path.fill.tag-amenity-university { stroke: rgba(255, 255, 148, 0.15); fill: rgba(255, 255, 148, 0.15); } +.preset-icon-fill-area.tag-leisure-pitch.tag-sport-beachvolleyball, +.preset-icon-fill-area.tag-natural-beach, +.preset-icon-fill-area.tag-natural-sand, +.preset-icon-fill-area.tag-natural-scrub, .preset-icon-fill-area.tag-amenity-childcare, .preset-icon-fill-area.tag-amenity-kindergarten, .preset-icon-fill-area.tag-amenity-school, @@ -554,33 +554,52 @@ path.fill.tag-amenity-university { background-color: rgba(255, 255, 148, 0.15); } -path.stroke.tag-landuse-residential { +/* Gold things */ +.pattern-color-construction { + fill: rgba(196, 189, 25, 0.3); +} +path.stroke.tag-landuse-residential, +path.stroke.tag-landuse.tag-status, +path.stroke.tag-landuse-construction { stroke: rgb(196, 189, 25); } path.fill.tag-landuse-residential { stroke: rgba(196, 189, 25, 0.3); fill: rgba(196, 189, 25, 0.3); } -.preset-icon-fill-area.tag-landuse-residential { +.preset-icon-fill-area.tag-landuse-residential, +.preset-icon-fill-area.tag-landuse.tag-status, +.preset-icon-fill-area.tag-landuse-construction { border-color: rgb(196, 189, 25); background: rgba(196, 189, 25, 0.3); } +/* Orange things */ path.stroke.tag-landuse-retail, -path.stroke.tag-landuse-commercial { +path.stroke.tag-landuse-commercial, +path.stroke.tag-landuse-landfill, +path.stroke.tag-military, +path.stroke.tag-landuse-military { stroke: rgb(214, 136, 26); } path.fill.tag-landuse-retail, -path.fill.tag-landuse-commercial { +path.fill.tag-landuse-commercial, +path.fill.tag-landuse-landfill, +path.fill.tag-military, +path.fill.tag-landuse-military { stroke: rgba(214, 136, 26, 0.3); fill: rgba(214, 136, 26, 0.3); } .preset-icon-fill-area.tag-landuse-retail, -.preset-icon-fill-area.tag-landuse-commercial { +.preset-icon-fill-area.tag-landuse-commercial, +.preset-icon-fill-area.tag-landuse-landfill, +.preset-icon-fill-area.tag-military, +.preset-icon-fill-area.tag-landuse-military { border-color: rgb(214, 136, 26); background-color: rgba(214, 136, 26, 0.3); } +/* Pink things */ path.stroke.tag-landuse-industrial, path.stroke.tag-power-plant { stroke: rgb(228, 164, 245); @@ -596,127 +615,42 @@ path.fill.tag-power-plant { background-color: rgba(228, 164, 245, 0.3); } -path.stroke.tag-natural-bare_rock, -path.stroke.tag-natural-scree, -path.stroke.tag-landuse-railway, -path.stroke.tag-landuse-quarry { - stroke: rgb(166, 149, 123); -} -path.fill.tag-natural-bare_rock, -path.fill.tag-natural-scree, -path.fill.tag-landuse-railway, -path.fill.tag-landuse-quarry { - stroke: rgba(166, 149, 123, 0.2); - fill: rgba(166, 149, 123, 0.2); -} -.preset-icon-fill-area.tag-natural-bare_rock, -.preset-icon-fill-area.tag-natural-scree, -.preset-icon-fill-area.tag-landuse-railway, -.preset-icon-fill-area.tag-landuse-quarry { - border-color: rgb(166, 149, 123); - background-color: rgba(166, 149, 123, 0.2); -} - -path.stroke.tag-landuse-landfill { - stroke: rgb(255, 153, 51); -} -path.fill.tag-landuse-landfill { - stroke: rgba(255, 153, 51, 0.2); - fill: rgba(255, 153, 51, 0.2); -} -.preset-icon-fill-area.tag-landuse-landfill { - border-color: rgb(255, 153, 51); - background-color: rgba(255, 153, 51, 0.2); -} - -.pattern-color-construction { - fill: rgba(196, 189, 25, 0.2); -} -path.stroke.tag-landuse.tag-status, -path.stroke.tag-landuse-construction { - stroke: rgb(196, 189, 25); -} -.preset-icon-fill-area.tag-landuse.tag-status, -.preset-icon-fill-area.tag-landuse-construction { - border-color: rgb(196, 189, 25); - background-color: rgba(196, 189, 25, 0.2); -} - -path.stroke.tag-military, -path.stroke.tag-landuse-military { - stroke: rgb(214, 136, 26); -} -path.fill.tag-military, -path.fill.tag-landuse-military { - stroke: rgba(214, 136, 26, 0.2); - fill: rgba(214, 136, 26, 0.2); -} -.preset-icon-fill-area.tag-military, -.preset-icon-fill-area.tag-landuse-military { - border-color: rgb(214, 136, 26); - background-color: rgba(214, 136, 26, 0.2); -} - +/* Teal things */ .pattern-color-wetland { - fill: rgba(182, 225, 153, 0.2); + fill: rgba(153, 225, 170, 0.3); } path.stroke.tag-natural-wetland { - stroke: rgb(182, 225, 153); + stroke: rgb(153, 225, 170); } .preset-icon-fill-area.tag-natural-wetland { - border-color: rgb(182, 225, 153); - background-color: rgba(182, 225, 153, 0.2); -} - -.pattern-color-meadow { - fill: rgba(182, 225, 153, 0.2); -} -path.stroke.tag-landuse-meadow { - stroke: rgb(182, 225, 153); -} -.preset-icon-fill-area.tag-landuse-meadow { - border-color: rgb(182, 225, 153); - background-color: rgba(182, 225, 153, 0.2); -} - -.pattern-color-beach, -.pattern-color-sand { - fill: rgba(255, 255, 126, 0.2); -} -path.stroke.tag-natural-beach, -path.stroke.tag-natural-sand { - stroke: rgb(255, 255, 126); -} -.preset-icon-fill-area.tag-natural-beach, -.preset-icon-fill-area.tag-natural-sand { - border-color: rgb(255, 255, 126); - background-color: rgba(255, 255, 126, 0.2); -} - -.pattern-color-scrub { - fill: rgba(219, 240, 139, 0.2); -} -path.stroke.tag-natural-scrub { - stroke: rgb(219, 240, 139); -} -.preset-icon-fill-area.tag-natural-scrub { - border-color: rgb(219, 240, 139); - background-color: rgba(219, 240, 139, 0.2); + border-color: rgb(153, 225, 170); + background-color: rgba(153, 225, 170, 0.2); } +/* Light Green things */ +.pattern-color-cemetery, +.pattern-color-orchard, +.pattern-color-meadow, .pattern-color-farm, .pattern-color-farmland { - fill: rgba(140, 208, 95, 0.2); + fill: rgba(191, 232, 63, 0.2); } +path.stroke.tag-landuse-cemetery, +path.stroke.tag-landuse-orchard, +path.stroke.tag-landuse-meadow, path.stroke.tag-landuse-farm, path.stroke.tag-landuse-farmland { - stroke: rgb(140, 208, 95); + stroke: rgb(191, 232, 63); } +.preset-icon-fill-area.tag-landuse-cemetery, +.preset-icon-fill-area.tag-landuse-orchard, +.preset-icon-fill-area.tag-landuse-meadow, .preset-icon-fill-area.tag-landuse-farm, .preset-icon-fill-area.tag-landuse-farmland { - background-color: rgba(140, 208, 95, 0.2); + background-color: rgba(191, 232, 63, 0.2); } +/* Tan things */ path.stroke.tag-landuse-farmyard { stroke: rgb(245, 220, 186); } @@ -729,29 +663,51 @@ path.fill.tag-landuse-farmyard { background: rgba(245, 220, 186, 0.3); } -.pattern-color-cemetery, -.pattern-color-orchard { - fill: rgba(140, 208, 95, 0.2); +/* Dark Gray things */ +path.stroke.tag-amenity-parking, +path.stroke.tag-leisure-pitch.tag-sport-basketball, +path.stroke.tag-leisure-pitch.tag-sport-skateboard, +path.stroke.tag-natural-bare_rock, +path.stroke.tag-natural-scree, +path.stroke.tag-landuse-railway, +path.stroke.tag-landuse-quarry { + stroke: #bbb; } -path.stroke.tag-landuse-cemetery, -path.stroke.tag-landuse-orchard { - stroke: rgb(140, 208, 95); +path.fill.tag-amenity-parking, +path.fill.tag-leisure-pitch.tag-sport-basketball, +path.fill.tag-leisure-pitch.tag-sport-skateboard, +path.fill.tag-natural-bare_rock, +path.fill.tag-natural-scree, +path.fill.tag-landuse-railway, +path.fill.tag-landuse-quarry { + stroke: rgba(140, 140, 140, 0.5); + fill: rgba(140, 140, 140, 0.5); } -.preset-icon-fill-area.tag-landuse-cemetery, -.preset-icon-fill-area.tag-landuse-orchard { - background-color: rgba(140, 208, 95, 0.2); +.preset-icon-fill-area.tag-amenity-parking, +.preset-icon-fill-area.tag-leisure-pitch.tag-sport-basketball, +.preset-icon-fill-area.tag-leisure-pitch.tag-sport-skateboard, +.preset-icon-fill-area.tag-natural-bare_rock, +.preset-icon-fill-area.tag-natural-scree, +.preset-icon-fill-area.tag-landuse-railway, +.preset-icon-fill-area.tag-landuse-quarry { + border-color: rgb(170, 170, 170); + background-color: rgba(140, 140, 140, 0.5); } -path.stroke.tag-amenity-parking { - stroke: rgb(170, 170, 170); +/* Light gray overrides */ +path.stroke.tag-natural-cave_entrance, +path.stroke.tag-natural-glacier { + stroke: #ddd; } -path.fill.tag-amenity-parking { - stroke: rgba(170, 170, 170, 0.3); - fill: rgba(170, 170, 170, 0.3); +path.fill.tag-natural-cave_entrance, +path.fill.tag-natural-glacier { + stroke: rgba(255, 255, 255, 0.3); + fill: rgba(255, 255, 255, 0.3); } -.preset-icon-fill-area.tag-amenity-parking { +.preset-icon-fill-area.tag-natural-cave_entrance, +.preset-icon-fill-area.tag-natural-glacier { border-color: rgb(170, 170, 170); - background-color: rgba(170, 170, 170, 0.3); + background: rgba(170, 170, 170, 0.3); } /* highways */ @@ -769,10 +725,11 @@ path.stroke.tag-highway { /* highway areas */ -path.stroke.area.tag-highway { +path.stroke.area.tag-highway, +.low-zoom path.stroke.area.tag-highway { stroke: #fff; stroke-dasharray: none; - stroke-width: 2; + stroke-width: 1; } /* wide highways */ @@ -1217,6 +1174,20 @@ path.casing.tag-service { stroke:#666; } +/* with `service=* tag` (e.g. parking_aisle, alley, drive-through */ +.preset-icon .icon.highway-service.tag-service { + color: #dcd9b9; + fill: #666; +} +path.stroke.tag-highway-service.tag-service, +path.stroke.tag-service.tag-service { + stroke: #dcd9b9; +} +path.casing.tag-highway-service.tag-service, +path.casing.tag-service.tag-service { + stroke: #666; +} + .preset-icon .icon.highway-track { color: #eaeaea; fill: #c5b59f; @@ -1346,10 +1317,11 @@ g.midpoint.tag-highway-bridleway .fill { /* aeroways */ /* areas */ -path.stroke.area.tag-aeroway { - stroke:#fff; +path.stroke.area.tag-aeroway, +.low-zoom path.stroke.area.tag-aeroway { + stroke: #fff; stroke-dasharray: none; - stroke-width: 2; + stroke-width: 1; } /* narrow aeroways (taxiway) */ @@ -1444,6 +1416,20 @@ path.fill.tag-aeroway-runway { fill: #eee; } +/* railway areas */ + +path.stroke.area.tag-railway, +.low-zoom path.stroke.area.tag-railway { + stroke: white; + stroke-width: 1; + stroke-dasharray: none; +} + +path.casing.area.tag-railway, +.low-zoom path.casing.area.tag-railway { + stroke: none; +} + /* narrow widths */ path.shadow.tag-railway { @@ -1505,23 +1491,45 @@ path.stroke.tag-railway-subway { } +/* railway platforms - like sidewalks */ + +.preset-icon .icon.highway-footway.tag-railway-platform { + color: #ae8681; + fill: #dcd9b9; +} +path.shadow.tag-railway-platform { + stroke-width: 16; +} path.casing.tag-railway-platform { - stroke: none; + stroke: #dcd9b9; + stroke-width: 5; + stroke-linecap: round; + stroke-dasharray: none; } path.stroke.tag-railway-platform { - stroke: #999; - stroke-width: 4; - stroke-dasharray: none; + stroke: #ae8681; + stroke-width: 3; + stroke-linecap: butt; + stroke-dasharray: 6, 6; } - -.area.stroke.tag-railway { - stroke: white; +.low-zoom path.shadow.tag-railway-platform { + stroke-width: 12; +} +.low-zoom path.casing.tag-railway-platform { + stroke-width: 3; +} +.low-zoom path.stroke.tag-railway-platform { stroke-width: 1; - stroke-dasharray: none; + stroke-linecap: butt; + stroke-dasharray: 3, 3; } -.area.casing.tag-railway { - stroke: none; + +g.midpoint.tag-railway-platform .fill { + fill: #fff; + stroke: #333; + stroke-opacity: .8; + opacity: .8; } /* waterways */ @@ -1531,6 +1539,7 @@ path.stroke.tag-railway-platform { } .preset-icon .icon.category-water, .preset-icon .icon.tag-route-ferry, +.preset-icon .icon.tag-type-waterway, .preset-icon .icon.tag-waterway { color: #77d3de; fill: #fff; @@ -1932,8 +1941,7 @@ path.fill.tag-amenity-shelter { .turn rect, .turn circle { - cursor: pointer; /* Opera */ - cursor: url(<%= asset_path("iD/img/cursor-pointer.png") %>) 6 1, pointer; /* FF */ + cursor: pointer; } /* Mapillary Image Layer */ @@ -1983,9 +1991,9 @@ path.fill.tag-amenity-shelter { .layer-mapillary-signs .icon-sign .icon-sign-body { min-width: 20px; - height: 28px; - width: 28px; - border: 2px solid transparent; + height: 24px; + width: 24px; + outline: 2px solid transparent; pointer-events: visible; cursor: pointer; /* Opera */ cursor: url(<%= asset_path("iD/img/cursor-select-mapillary.png") %>) 6 1, pointer; /* FF */ @@ -1994,23 +2002,61 @@ path.fill.tag-amenity-shelter { } .layer-mapillary-signs .icon-sign:hover .icon-sign-body { - border: 2px solid rgba(255,198,0,0.8); + outline: 2px solid rgba(255,198,0,0.8); z-index: 80; - } +} .layer-mapillary-signs .icon-sign.selected .icon-sign-body { - border: 2px solid rgba(255,0,0,0.8); + outline: 2px solid rgba(255,0,0,0.8); z-index: 80; - } +} -.layer-mapillary-signs .icon-sign .t { - font-size: 28px; - z-index: 70; + +/* Mapillary viewer */ +#mly .domRenderer .TagSymbol { + font-size: 10px; + background-color: rgba(0, 0, 0, 0.4); + padding: 0 4px; + border-radius: 4px; + top: -25px; } -.layer-mapillary-signs .icon-sign:hover .t, -.layer-mapillary-signs .icon-sign.selected .t { - z-index: 80; +#mly .domRenderer .Attribution { + width: 100%; + font-size: 10px; + text-align: right; +} + +.mapillary-wrap { + position: absolute; + bottom: 30px; + width: 330px; + height: 250px; + padding: 5px; + background-color: #fff; +} + +.mapillary-wrap.hidden { + visibility: hidden; +} + +.mapillary-wrap button.thumb-hide { + border-radius: 0; + padding: 5px; + position: absolute; + right: 0; + top: 0; + z-index: 500; +} + +.mly-wrapper { + visibility: hidden; + width: 100%; + height: 100%; +} + +.mly-wrapper.active { + visibility: visible; } /* Fill Styles */ @@ -2131,6 +2177,22 @@ body { transition-duration: 200ms; } +/* Firefox has its own ideas about fixed positioning when a css filter is active - #4348 */ +/* https://stackoverflow.com/questions/37949942/firefox-position-bug-by-parent-with-filter */ +@-moz-document url-prefix() { + #content > #bar { + width: 100vw; + } + #content.inactive > #bar > .spacer.col4 { + width: 0px; + } + #content.active > #bar > .spacer.col4 { + width: 33.3333%; + transition-duration: 200ms; + transition-timing-function: step-end; + } +} + #defs { /* Can't be display: none or the clippaths are ignored. */ position: absolute; @@ -2191,8 +2253,7 @@ button, .checkselect label:hover, .opacity-options li, .radial-menu-item { - cursor: pointer; /* Opera */ - cursor: url(<%= asset_path("iD/img/cursor-pointer.png") %>) 6 1, pointer; /* FF */ + cursor: pointer; } h2 { @@ -2300,6 +2361,12 @@ input[type="radio"] { margin-right: 5px; margin-top: 3px; } +[dir='rtl'] input[type="checkbox"], +[dir='rtl'] input[type="radio"] { + float: right; + margin-left: 5px; + margin-right: 0; +} /* remove bottom border radius when combobox is open */ .combobox + * textarea:focus, @@ -2528,23 +2595,37 @@ button.minor:hover { .button-wrap:last-of-type { padding-right: 0; } +[dir='rtl'] .button-wrap:last-of-type { + padding-left: 0; + padding-right: 10px; +} .joined button { border-radius:0; border-right: 1px solid rgba(0,0,0,.5); } +[dir='rtl'] .joined button { + border-left: 1px solid rgba(0,0,0,.5); + border-right: none; +} .fillL .joined button { border-right: 1px solid white; } .joined button:first-child { - border-radius:4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +[dir='rtl'] .joined button:first-child { + border-radius: 0 4px 4px 0; } .joined button:last-child { border-right-width: 0; - border-radius:0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +[dir='rtl'] .joined button:last-child { + border-radius: 4px 0 0 4px; } button.action { @@ -2591,6 +2672,10 @@ button.save.has-count .count { margin: auto; margin-left: 9.3333%; } +[dir='rtl'] button.save.has-count .count { + margin-left: auto; + margin-right: 8%; +} button.save.has-count .count::before { content: ""; @@ -2607,6 +2692,12 @@ button.save.has-count .count::before { border-right-style: solid; border-right-color: inherit; } +[dir='rtl'] button.save.has-count .count::before { + border-left: 6px solid rgba(255,255,255,.5); + border-right: none; + left: auto; + right: -6px; +} /* Icons */ @@ -2626,6 +2717,10 @@ button.save.has-count .count::before { .icon.pre-text { margin-right: 5px; } +[dir='rtl'] .icon.pre-text { + margin-left: 5px; + margin-right: 0; +} .icon.light { color: #fff; @@ -2658,18 +2753,24 @@ button.save.has-count .count::before { #bar { position: fixed; padding: 10px 0; - left:0; - top:0; - right:0; - height:60px; + left: 0; + top: 0; + right: 0; + height: 60px; z-index: 9; min-width: 768px; } +[dir='rtl'] #bar .spacer, +[dir='rtl'] #bar .button-wrap, +[dir='rtl'] #bar .button-wrap button { + float: right; +} + + +/* Header for modals / panes +------------------------------------------------------- */ -/* Header for modals / panes -------------------------------------------------------- */ - .header { border-bottom: 1px solid #ccc; height: 60px; @@ -2684,6 +2785,10 @@ button.save.has-count .count::before { overflow: hidden; padding: 20px 20px 20px 40px; } +[dir='rtl'] .header h3 { + text-align: right; + padding: 20px 40px 20px 20px; +} .header button, .modal > button { @@ -2704,12 +2809,21 @@ button.save.has-count .count::before { right: 0; top: 0; } +[dir='rtl'] .entity-editor-pane .header button.preset-close, +[dir='rtl'] .preset-list-pane .header button.preset-choose { + left: 0; + right: auto; +} .entity-editor-pane .header button.preset-choose { position: absolute; left: 0; top: 0; } +[dir='rtl'] .entity-editor-pane .header button.preset-choose { + left: auto; + right: 0; +} .preset-choose { font-size: 16px; @@ -2724,6 +2838,10 @@ button.save.has-count .count::before { height: 60px; z-index: 50; } +[dir='rtl'] .modal > button { + left: 0; + right: unset; +} .footer { position: absolute; @@ -2755,6 +2873,9 @@ button.save.has-count .count::before { background: #f6f6f6; -ms-user-select: element; } +[dir='rtl'] #sidebar { + float: right; +} .sidebar-component { position: absolute; @@ -2811,6 +2932,10 @@ button.save.has-count .count::before { top: 80px; pointer-events: none; } +[dir='rtl'] #sidebar .search-header .icon { + left: auto; + right: 10px; +} #sidebar .search-header input { position: absolute; @@ -2864,6 +2989,9 @@ button.save.has-count .count::before { overflow: hidden; border-left: 1px solid rgba(0, 0, 0, .1); } +[dir='rtl'] .feature-list-item .label { + text-align: right; +} .feature-list-item .label .icon { opacity: .5; @@ -2891,6 +3019,11 @@ button.save.has-count .count::before { color: #666; padding-left: 10px; } +[dir='rtl'] .feature-list-item .entity-name { + padding-left: 0; + padding-right: 10px; +} + /* Presets ------------------------------------------------------- */ @@ -2940,6 +3073,7 @@ button.save.has-count .count::before { border: 1.5px solid #333; border-radius: 20px; background-color: #efefef; + backface-visibility: hidden; } [dir='rtl'] .preset-icon-fill-vertex, @@ -3014,6 +3148,19 @@ button.save.has-count .count::before { height: 24px; } +[dir='rtl'] .preset-list-button-wrap .preset-icon { + left: auto; + right: auto; +} + +[dir='rtl'] .preset-list-button-wrap .preset-icon-28 { + right: 16px; +} + +[dir='rtl'] .preset-list-button-wrap .preset-icon-24 { + right: 18px; +} + .preset-list-button .label { background-color: #f6f6f6; text-align: left; @@ -3029,7 +3176,15 @@ button.save.has-count .count::before { overflow: hidden; border-left: 1px solid rgba(0, 0, 0, .1); border-radius: 0 3px 3px 0; - } +} +[dir='rtl'] .preset-list-button .label { + text-align: right; + left: 0; + right: 60px; + border-left: none; + border-right: 1px solid rgba(0, 0, 0, .1); + border-radius: 3px 0 0 3px; +} .preset-list-button:hover .label { background-color: #ececec; @@ -3042,9 +3197,14 @@ button.save.has-count .count::before { position: absolute; top: 0; right: 0; - width: 10%; + width: 32px; background: #fafafa; } +[dir='rtl'] .preset-list-item button.tag-reference-button { + left: 0; + right: auto; + border-radius: 3px 0 0 3px; +} .preset-list-item button.tag-reference-button:hover { background: #f1f1f1; @@ -3098,21 +3258,25 @@ button.save.has-count .count::before { /* preset form basics */ -.inspector-preset { +.preset-editor { overflow: hidden; padding-bottom: 10px; } -.inspector-preset a.hide-toggle { +.preset-editor a.hide-toggle { margin: 0 20px 10px 20px; } -.inspector-preset .preset-form { +.preset-editor .form-fields-container { padding: 10px; margin: 0 10px 10px 10px; border-radius: 8px; } +.preset-editor .form-fields-container:empty { + display: none; +} + .entity-editor-pane .preset-list-item .preset-list-button-wrap { margin-bottom: 0; } @@ -3126,7 +3290,8 @@ button.save.has-count .count::before { transition: margin-bottom 200ms; } -.form-field:last-child { +.form-field.nowrap, +.wrap-form-field:last-child .form-field { margin-bottom: 0; } @@ -3167,7 +3332,7 @@ button.save.has-count .count::before { .form-label button { border-left: 1px solid #ccc; - width: 10%; + width: 32px; height: 100%; border-radius: 0; background: #f6f6f6; @@ -3176,6 +3341,7 @@ button.save.has-count .count::before { border-left: none; border-right: 1px solid #CCC; border-radius: 4px 0 0 0; + width: 31px; } .form-label button:hover { background: #f1f1f1; @@ -3216,6 +3382,7 @@ button.save.has-count .count::before { .inspector-hover .form-field-multicombo, .inspector-hover .structure-extras-wrap, .inspector-hover input, +.inspector-hover textarea, .inspector-hover label { background: #ececec; } @@ -3339,6 +3506,9 @@ button.save.has-count .count::before { padding: 0 20px 20px 20px; font-weight: bold; } +.changeset-editor .more-fields { + padding: 15px 20px 0 20px; +} .more-fields label { display: flex; @@ -3362,17 +3532,21 @@ button.save.has-count .count::before { padding: 5px 10px; } +[dir='rtl'] .preset-input-wrap .col6 { + float: right; +} /* preset form access */ /* preset form cycleway */ +/* preset form structure extras */ -.form-field-structure .structure-extras-wrap li, +.structure-extras-wrap li, .form-field-cycleway .preset-input-wrap li, .form-field-access .preset-input-wrap li { border-bottom: 1px solid #ccc; } -.form-field-structure .structure-extras-wrap li:last-child, +.structure-extras-wrap li:last-child, .form-field-cycleway .preset-input-wrap li:last-child, .form-field-access .preset-input-wrap li:last-child { border-bottom: 0; @@ -3405,6 +3579,34 @@ button.save.has-count .count::before { border: 1px solid #ccc; border-radius: 4px; } +.structure-extras-wrap li:first-child span { + border-top-left-radius: 4px; +} +.structure-extras-wrap li:first-child input { + border-top-right-radius: 4px; +} +.structure-extras-wrap li:last-child span { + border-bottom-left-radius: 4px; +} +.structure-extras-wrap li:last-child input { + border-bottom-right-radius: 4px; +} +[dir='rtl'] .structure-extras-wrap li:first-child span { + border-top-left-radius: 0; + border-top-right-radius: 4px; +} +[dir='rtl'] .structure-extras-wrap li:first-child input { + border-top-right-radius: 0; + border-top-left-radius: 4px; +} +[dir='rtl'] .structure-extras-wrap li:last-child span { + border-bottom-left-radius: 0; + border-bottom-right-radius: 4px; +} +[dir='rtl'] .structure-extras-wrap li:last-child input { + border-bottom-right-radius: 0; + border-bottom-left-radius: 4px; +} /* preset form multicombo */ @@ -3429,14 +3631,15 @@ button.save.has-count .count::before { } .form-field-multicombo li { + display: inline-flex; + flex-flow: row nowrap; + align-items: center; background-color: #eff2f7; border: 1px solid #ccd5e3; border-radius: 4px; line-height: 25px; - display: inline-block; padding: 2px 5px; margin: 3px; - height: 30px; } .form-field-multicombo a { @@ -3454,6 +3657,7 @@ button.save.has-count .count::before { border: 1px solid #ddd; width: 100px; margin: 3px; + height: 31px; } .form-field-multicombo .combobox-caret { @@ -3473,28 +3677,43 @@ input[type=number] { } .spin-control { - width: 20%; - height: 29px; + width: 64px; + height: 30px; display: inline-block; - margin-left: -20%; + margin-left: -64px; margin-bottom: -11px; position: relative; } +[dir='rtl'] .spin-control{ + margin-left: 0; + margin-right: -64px; +} .spin-control button { right: 1px; position: relative; float: left; height: 100%; - width: 50%; + width: 32px; border-left: 1px solid #CCC; border-radius: 0; background: rgba(0, 0, 0, 0); } +[dir='rtl'] .spin-control button{ + border-left: 0; + border-right: 1px solid #CCC; +} .spin-control button.decrement { border-bottom-right-radius: 3px; } +[dir='rtl'] .spin-control button.decrement { + border-bottom-right-radius: 0; +} +[dir='rtl'] .spin-control button.increment { + border-bottom-left-radius: 3px; + right: 0; +} .spin-control button.decrement::after, .spin-control button.increment::after { @@ -3517,6 +3736,7 @@ input[type=number] { border-right: 5px solid transparent; } + /* preset form checkbox */ .checkselect label:last-of-type { @@ -3600,11 +3820,11 @@ input[type=number] { } .form-field .wiki-title ~ .combobox-caret { - right: 10%; + right: 32px; } [dir='rtl'] .form-field .wiki-title ~ .combobox-caret { right: auto; - left: 10%; + left: 32px; } /* Localized field */ @@ -3619,8 +3839,8 @@ input[type=number] { .form-field .button-input-action { position: relative; right: 1px; - width: 10%; - margin-left: -10%; + width: 32px; + margin-left: -32px; border: 1px solid #CCC; border-top-width: 0; border-right-width: 0; @@ -3630,7 +3850,7 @@ input[type=number] { } [dir='rtl'] .form-field .button-input-action { margin-left: 0; - margin-right: -10%; + margin-right: -32px; border-right-width: 1px; border-radius: 0 0 0 4px; } @@ -3776,6 +3996,10 @@ div.combobox { margin-left: -30px; vertical-align: top; } +[dir='rtl'] .combobox-caret { + margin-left: 0; + margin-right: -30px; +} .combobox-caret::after { content:""; @@ -3948,18 +4172,17 @@ button.minor.tag-reference-loading { clear: both; } -.tag-reference-body p, -.tag-reference-body img { - margin-top: 20px; -} - -.tag-reference-body p:last-child { - padding-bottom: 10px; +.tag-reference-body .tag-reference-description { + margin: 10px 5px 0 5px; } .tag-reference-body a { display: block; - padding-bottom: 10px; +} + +.tag-reference-body .tag-reference-description:last-child, +.tag-reference-body a:last-child { + margin-bottom: 15px; } .preset-list .tag-reference-body { @@ -3967,41 +4190,35 @@ button.minor.tag-reference-loading { width: 100%; } -.preset-list .tag-reference-body a { - padding-bottom: 20px; -} - -.preset-list .tag-reference-body p, -.preset-list .tag-reference-body img { - margin-top: 10px; -} - .raw-tag-editor .tag-reference-body { - border-bottom: 1px solid #ccc; float: left; width: 100%; } -.raw-tag-editor .tag-reference-body p:last-child { - padding-bottom: 20px; +.raw-tag-editor .tag-row.readonly .tag-reference-body { + background: #f6f6f6; + color: #333; } -.raw-tag-editor .tag-reference-body a { - padding-bottom: 20px; +.raw-tag-editor .tag-row:not(:last-child) .tag-reference-body { + border-bottom: 1px solid #ccc; +} + +.raw-tag-editor .tag-row.readonly .tag-reference-body.expanded { + border-top: 1px solid #ccc; } -img.wiki-image { +img.tag-reference-wiki-image { float: right; width: 33.3333%; width: -webkit-calc(33.3333% - 10px); width: calc(33.3333% - 10px); - margin-left: 20px; - margin-right: 10px; border-radius: 4px; max-height: 200px; - margin-bottom: 20px; + margin: 10px 5px 15px 20px; } + /* Raw relation membership editor */ .raw-member-editor .member-list li:first-child, @@ -4041,6 +4258,14 @@ img.wiki-image { background: rgba(0,0,0,.8); } +/* hidden field to prevent user from tabbing out of the sidebar */ +input.key-trap { + height: 0px; + width: 0px; + padding: 0px; + border: 1px solid rgba(0,0,0,0); +} + /* Fullscreen button */ div.full-screen { float: right; @@ -4071,6 +4296,10 @@ div.full-screen > button:hover { position: fixed; z-index: 100; } +[dir='rtl'] .map-controls { + left: 0; + right: auto; +} .map-control > button { width: 40px; @@ -4092,6 +4321,9 @@ div.full-screen > button:hover { .zoombuttons button.zoom-in { border-radius: 4px 0 0 0; } +[dir='rtl'] .zoombuttons button.zoom-in { + border-radius: 0 4px 0 0; +} /* Background / Map Data Settings */ @@ -4102,6 +4334,9 @@ div.full-screen > button:hover { .background-control button { border-radius: 4px 0 0 0; } +[dir='rtl'] .background-control button { + border-radius: 0 4px 0 0; +} .map-data-control, .background-control { @@ -4165,6 +4400,10 @@ div.full-screen > button:hover { float: right; } +[dir='rtl'] .list-item-gpx-browse svg { + transform: rotateY(180deg); +} + /* make sure tooltip fits in map-control panel */ /* if too wide, placement will be wrong the first time it displays */ .layer-list li.best .tooltip-inner { @@ -4202,9 +4441,13 @@ div.full-screen > button:hover { .hide-toggle { display: block; - padding-left:12px; + padding-left: 12px; position: relative; } +[dir='rtl'] .hide-toggle { + padding-left: 0; + padding-right: 12px; +} .hide-toggle:before { content: ''; @@ -4218,6 +4461,12 @@ div.full-screen > button:hover { border-bottom: 4px solid transparent; border-left: 8px solid #7092ff; } +[dir='rtl'] .hide-toggle:before { + left: auto; + right: 0; + border-left: none; + border-right: 8px solid #7092ff; +} .hide-toggle.expanded:before { border-top: 8px solid #7092ff; @@ -4225,6 +4474,11 @@ div.full-screen > button:hover { border-right: 4px solid transparent; border-left: 4px solid transparent; } +[dir='rtl'] .hide-toggle.expanded:before { + border-left: 4px solid transparent; + border-right: 4px solid transparent; +} + /* Adjust Alignment controls */ @@ -4355,13 +4609,17 @@ div.full-screen > button:hover { .opacity-options { background: url(<%= asset_path("iD/img/background-pattern-opacity.png") %>) 0 0 repeat; - height:20px; - width:82px; + height: 20px; + width: 82px; position: absolute; right: 50px; top: 20px; border: 1px solid #ccc; } +[dir='rtl'] .opacity-options { + left: 50px; + right: auto; +} .opacity-options li { height: 100%; @@ -4371,8 +4629,8 @@ div.full-screen > button:hover { .opacity-options li .select-box{ position: absolute; - width:20px; - height:18px; + width: 20px; + height: 18px; z-index: 9999; } @@ -4407,6 +4665,12 @@ div.full-screen > button:hover { border-left: 1px solid #CCC; border-radius: 0; } +[dir='rtl'] .map-data-control .layer-list button, +[dir='rtl'] .background-control .layer-list button { + float: left; + border-left: none; + border-right: 1px solid #CCC; +} .map-data-control .layer-list button .icon, .background-control .layer-list button .icon { @@ -4417,6 +4681,10 @@ div.full-screen > button:hover { .background-control .layer-list button:first-of-type { border-radius: 0 3px 3px 0; } +[dir='rtl'] .map-data-control .layer-list button:first-of-type, +[dir='rtl'] .background-control .layer-list button:first-of-type { + border-radius: 3px 0 0 3px; +} .map-data-control .map-overlay, .background-control .map-overlay, @@ -4424,7 +4692,6 @@ div.full-screen > button:hover { z-index: -1; } - /* Geolocator */ .geolocate-control { @@ -4434,6 +4701,9 @@ div.full-screen > button:hover { .geolocate-control button { border-radius: 0 0 0 4px; } +[dir='rtl'] .geolocate-control button { + border-radius: 0 0 4px 0; +} .map-overlay.content { position: fixed; @@ -4443,12 +4713,20 @@ div.full-screen > button:hover { right: 0; overflow: auto; } +[dir='rtl'] .map-overlay.content { + padding: 20px 20px 20px 50px; + left: 0; + right: auto !important; +} /* Help */ .help-control button { border-radius: 0 0 0 4px; } +[dir='rtl'] .help-control button { + border-radius: 0 0 4px 0; +} .help-wrap p { font-size: 15px; @@ -4770,6 +5048,9 @@ img.tile-removing { background: none; color: #ddd; } +[dir='rtl'] .panel-title button.close { + float: left; +} .panel-title button.close:hover { color: #fff; @@ -5359,32 +5640,55 @@ img.tile-removing { float: left; height: 12px; min-width: 12px; - font-size:12px; + font-size: 12px; line-height: 12px; - border-radius:24px; - padding:5px; - background:#7092ff; - color:#fff; + border-radius: 24px; + padding: 5px; + background: #7092ff; + color: #fff; } +.mode-save .field-warning { + background: #ffb; + border: 1px solid #ccc; + border-radius: 4px; + padding: 10px; +} + +.mode-save .field-warning:empty { + display: none; +} + +.mode-save .field-warning, +.mode-save .changeset-info, +.mode-save .request-review, .mode-save .commit-info { margin-bottom: 10px; } +.mode-save .request-review label { + cursor: pointer; +} + .mode-save .changeset-list { - border:1px solid #ccc; + border: 1px solid #ccc; border-radius: 4px; - background:#fff; + background: #fff; + margin-bottom: 10px; +} + +.mode-save .warning-section { + background: #ffb; } .mode-save .warning-section .changeset-list button { - border-left: 1px solid #CCC; + border-left: 1px solid #ccc; } .mode-save .changeset-list li { position: relative; - border-top:1px solid #ccc; - padding:5px 10px; + border-top: 1px solid #ccc; + padding: 5px 10px; cursor: pointer; } @@ -5397,8 +5701,8 @@ img.tile-removing { } .changeset-list li span.count { - font-size:10px; - color:#555; + font-size: 10px; + color: #555; } .mode-save .commit-section .changeset-list button { @@ -5466,31 +5770,34 @@ img.tile-removing { .notice { position: absolute; - top: 0; - bottom: 0; + top: 50%; + bottom: 50%; left: 0; right: 0; text-align: center; - background: #fff; } .notice .zoom-to { margin: auto; - width: 80%; - height: 100px; - border-radius: 5px; - line-height: 40px; - color: #000; - opacity: 0.9; + width: 300px; + height: 80px; + font-size: 150%; + border-radius: 8px; } .notice .zoom-to:hover { - background: #d8e1ff; + background: rgba(0,0,0,0.6); } .notice .zoom-to .icon { - margin-top:10px; - margin-right:10px; + width: 30px; + height: 30px; + vertical-align: middle; + margin-right: 10px; +} +[dir='rtl'] .notice .zoom-to .icon { + margin-left: 10px; + margin-right: 0; } /* Tooltips @@ -5702,6 +6009,10 @@ img.tile-removing { .add-point .tooltip { left: 33.3333% !important; } +[dir='rtl'] .add-point .tooltip { + left: inherit !important; +} + .add-point .tooltip .tooltip-arrow { left: 60px; } @@ -6033,253 +6344,3 @@ li.hide + li.version .badge .tooltip .tooltip-arrow { width: 100px; color: #7092FF; } - -.mapillary-wrap { - position: absolute; - bottom: 30px; - width: 330px; - height: 250px; - padding: 5px; - background-color: #fff; -} - -.mapillary-wrap.hidden { - visibility: hidden; -} - -.mapillary-wrap button.thumb-hide { - border-radius: 0; - padding: 5px; - position: absolute; - right: 0; - top: 0; - z-index: 500; -} - -.mly-wrapper { - visibility: hidden; - width: 100%; - height: 100%; -} - -.mly-wrapper.active { - visibility: visible; -} - -/* Right-to-left localization settings */ - -[dir='rtl'] #sidebar { - float: right; -} - -[dir='rtl'] #sidebar .search-header .icon { - left: auto; - right: 10px; -} - -/* header */ -[dir='rtl'] .header h3 { - text-align: right; - padding: 20px 40px 20px 20px; -} - -[dir='rtl'] .entity-editor-pane .header button.preset-choose { - left: auto; - right: 0; -} - -[dir='rtl'] .entity-editor-pane .header button.preset-close, [dir='rtl'] .preset-list-pane .header button.preset-choose { - left: 0; - right: auto; -} - -[dir='rtl'] .map-data-control .layer-list button, [dir='rtl'] .background-control .layer-list button { - float: left; - border-left: none; - border-right: 1px solid #CCC; -} - -[dir='rtl'] .map-data-control .layer-list button:first-of-type, [dir='rtl'] .background-control .layer-list button:first-of-type { - border-radius: 3px 0 0 3px; -} - -/* search */ -[dir='rtl'] .feature-list-item .label { - text-align: right; -} - -[dir='rtl'] .feature-list-item .entity-name { - padding-left: 0; - padding-right: 10px; -} - -/* preset form */ - -[dir='rtl'] .combobox-caret { - margin-left: 0; - margin-right: -30px; -} - -[dir='rtl'] .icon.pre-text { - margin-left: 5px; - margin-right: 0; -} - -[dir='rtl'] .notice .zoom-to .icon { - margin-left: 10px; - margin-right: 0; -} - -[dir='rtl'] .preset-list-button .label { - text-align: right; - left: 0; - right: 60px; - border-left: none; - border-right: 1px solid rgba(0, 0, 0, .1); - border-radius: 3px 0 0 3px; -} - -[dir='rtl'] .preset-list-item button.tag-reference-button { - left: 0; - right: auto; - border-radius: 3px 0 0 3px; -} - -[dir='rtl'] .preset-list-button-wrap .preset-icon { - left: auto; - right: auto; -} - -[dir='rtl'] .preset-list-button-wrap .preset-icon-28 { - right: 16px; -} - -[dir='rtl'] .preset-list-button-wrap .preset-icon-24 { - right: 18px; -} - -[dir='rtl'] input[type="checkbox"], [dir='rtl'] input[type="radio"] { - float: right; - margin-left: 5px; - margin-right: 0; -} - -[dir='rtl'] .preset-input-wrap .col6 { - float: right; -} - -/* map control buttons */ -[dir='rtl'] .map-controls { - left: 0; - right: auto; -} - -[dir='rtl'] .background-control button, -[dir='rtl'] .zoombuttons button.zoom-in { - border-radius: 0 4px 0 0; -} - -[dir='rtl'] .help-control button, -[dir='rtl'] .geolocate-control button { - border-radius: 0 0 4px 0; -} - -[dir='rtl'] .list-item-gpx-browse svg { - transform: rotateY(180deg); -} - -/* map control button overlays */ -[dir='rtl'] .map-overlay { - padding: 20px 20px 20px 50px; - left: 0; - right: auto !important; -} - -[dir='rtl'] .opacity-options { - left: 50px; - right: auto; -} - -[dir='rtl'] .hide-toggle { - padding-left: 0; - padding-right: 12px; -} - -[dir='rtl'] .hide-toggle:before { - left: auto; - right: 0; - border-left: none; - border-right: 8px solid #7092ff; -} - -[dir='rtl'] .hide-toggle.expanded:before { - border-left: 4px solid transparent; - border-right: 4px solid transparent; -} - -/* navbar */ -[dir='rtl'] #bar .spacer, -[dir='rtl'] #bar .button-wrap, -[dir='rtl'] #bar .button-wrap button { - float: right; -} - -[dir='rtl'] .add-point .tooltip { - left: inherit !important; -} - -[dir='rtl'] .button-wrap:last-of-type { - padding-left: 0; - padding-right: 10px; -} - -[dir='rtl'] button.save.has-count .count { - margin-left: auto; - margin-right: 8%; -} - -[dir='rtl'] button.save.has-count .count::before { - border-left: 6px solid rgba(255,255,255,.5); - border-right: none; - left: auto; - right: -6px; -} - -[dir='rtl'] .joined button { - border-left: 1px solid rgba(0,0,0,.5); - border-right: none; -} - -[dir='rtl'] .joined button:first-child { - border-radius: 0 4px 4px 0; -} - -[dir='rtl'] .joined button:last-child { - border-radius: 4px 0 0 4px; -} - - -/* increment / decrement control - code by Naoufel Razouane */ - -[dir='rtl'] .spin-control{ - margin-left: 0; - margin-right: -20%; -} -[dir='rtl'] .spin-control button{ - border-left: 0; - border-right: 1px solid #CCC; -} -[dir='rtl'] .spin-control button.decrement{ - border-bottom-right-radius: 0; -} -[dir='rtl'] .spin-control button.increment{ - border-bottom-left-radius: 3px; -} -/* modal */ -[dir='rtl'] .modal > button { - position: absolute; - left: 0; - right: unset; - top: 0; -} - diff --git a/vendor/assets/iD/iD.js b/vendor/assets/iD/iD.js index 49c018691..9ff9b3907 100644 --- a/vendor/assets/iD/iD.js +++ b/vendor/assets/iD/iD.js @@ -1,36142 +1,23989 @@ (function () { -function actionAddEntity(way) { - return function(graph) { - return graph.replace(way); - }; -} +var version = "4.11.0"; -var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; +var d3_ascending = function(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; +}; +var d3_bisector = function(compare) { + if (compare.length === 1) compare = ascendingComparator(compare); + return { + left: function(a, x, lo, hi) { + if (lo == null) lo = 0; + if (hi == null) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (compare(a[mid], x) < 0) lo = mid + 1; + else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (lo == null) lo = 0; + if (hi == null) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (compare(a[mid], x) > 0) hi = mid; + else lo = mid + 1; + } + return lo; + } + }; +}; +function ascendingComparator(f) { + return function(d, x) { + return d3_ascending(f(d), x); + }; +} +var ascendingBisect = d3_bisector(d3_ascending); +var bisectRight = ascendingBisect.right; +var bisectLeft = ascendingBisect.left; +var pairs = function(array, f) { + if (f == null) f = pair; + var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n); + while (i < n) pairs[i] = f(p, p = array[++i]); + return pairs; +}; -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; +function pair(a, b) { + return [a, b]; } -var lodash = createCommonjsModule(function (module, exports) { -/** - * @license - * Lodash - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -(function() { +var cross = function(values0, values1, reduce) { + var n0 = values0.length, + n1 = values1.length, + values = new Array(n0 * n1), + i0, + i1, + i, + value0; - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '4.17.4'; - - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Error message constants. */ - var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', - FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED = '__lodash_hash_undefined__'; - - /** Used as the maximum memoize cache size. */ - var MAX_MEMOIZE_SIZE = 500; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** Used to compose bitmasks for cloning. */ - var CLONE_DEEP_FLAG = 1, - CLONE_FLAT_FLAG = 2, - CLONE_SYMBOLS_FLAG = 4; - - /** Used to compose bitmasks for value comparisons. */ - var COMPARE_PARTIAL_FLAG = 1, - COMPARE_UNORDERED_FLAG = 2; - - /** Used to compose bitmasks for function metadata. */ - var WRAP_BIND_FLAG = 1, - WRAP_BIND_KEY_FLAG = 2, - WRAP_CURRY_BOUND_FLAG = 4, - WRAP_CURRY_FLAG = 8, - WRAP_CURRY_RIGHT_FLAG = 16, - WRAP_PARTIAL_FLAG = 32, - WRAP_PARTIAL_RIGHT_FLAG = 64, - WRAP_ARY_FLAG = 128, - WRAP_REARG_FLAG = 256, - WRAP_FLIP_FLAG = 512; - - /** Used as default options for `_.truncate`. */ - var DEFAULT_TRUNC_LENGTH = 30, - DEFAULT_TRUNC_OMISSION = '...'; - - /** Used to detect hot functions by number of calls within a span of milliseconds. */ - var HOT_COUNT = 800, - HOT_SPAN = 16; - - /** Used to indicate the type of lazy iteratees. */ - var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2, - LAZY_WHILE_FLAG = 3; - - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308, - NAN = 0 / 0; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - - /** Used to associate wrap methods with their bit flags. */ - var wrapFlags = [ - ['ary', WRAP_ARY_FLAG], - ['bind', WRAP_BIND_FLAG], - ['bindKey', WRAP_BIND_KEY_FLAG], - ['curry', WRAP_CURRY_FLAG], - ['curryRight', WRAP_CURRY_RIGHT_FLAG], - ['flip', WRAP_FLIP_FLAG], - ['partial', WRAP_PARTIAL_FLAG], - ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], - ['rearg', WRAP_REARG_FLAG] - ]; + if (reduce == null) reduce = pair; - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - asyncTag = '[object AsyncFunction]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - domExcTag = '[object DOMException]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - mapTag = '[object Map]', - numberTag = '[object Number]', - nullTag = '[object Null]', - objectTag = '[object Object]', - promiseTag = '[object Promise]', - proxyTag = '[object Proxy]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]', - undefinedTag = '[object Undefined]', - weakMapTag = '[object WeakMap]', - weakSetTag = '[object WeakSet]'; - - var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - /** Used to match empty string literals in compiled template source. */ - var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, - reUnescapedHtml = /[&<>"']/g, - reHasEscapedHtml = RegExp(reEscapedHtml.source), - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to match template delimiters. */ - var reEscape = /<%-([\s\S]+?)%>/g, - reEvaluate = /<%([\s\S]+?)%>/g, - reInterpolate = /<%=([\s\S]+?)%>/g; - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/, - reLeadingDot = /^\./, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + for (i0 = i = 0; i0 < n0; ++i0) { + for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) { + values[i] = reduce(value0, values1[i1]); + } + } - /** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, - reHasRegExpChar = RegExp(reRegExpChar.source); + return values; +}; - /** Used to match leading and trailing whitespace. */ - var reTrim = /^\s+|\s+$/g, - reTrimStart = /^\s+/, - reTrimEnd = /\s+$/; +var d3_descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; +}; - /** Used to match wrap detail comments. */ - var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, - reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, - reSplitDetails = /,? & /; +var number = function(x) { + return x === null ? NaN : +x; +}; - /** Used to match words composed of alphanumeric characters. */ - var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; +var variance = function(values, valueof) { + var n = values.length, + m = 0, + i = -1, + mean = 0, + value, + delta, + sum = 0; - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; + if (valueof == null) { + while (++i < n) { + if (!isNaN(value = number(values[i]))) { + delta = value - mean; + mean += delta / ++m; + sum += delta * (value - mean); + } + } + } - /** - * Used to match - * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). - */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - - /** Used to detect bad signed hexadecimal string values. */ - var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - - /** Used to detect binary string values. */ - var reIsBinary = /^0b[01]+$/i; - - /** Used to detect host constructors (Safari). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used to detect octal string values. */ - var reIsOctal = /^0o[0-7]+$/i; - - /** Used to detect unsigned integer values. */ - var reIsUint = /^(?:0|[1-9]\d*)$/; - - /** Used to match Latin Unicode letters (excluding mathematical operators). */ - var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; - - /** Used to ensure capturing order of template delimiters. */ - var reNoMatch = /($^)/; - - /** Used to match unescaped characters in compiled string literals. */ - var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - - /** Used to compose unicode character classes. */ - var rsAstralRange = '\\ud800-\\udfff', - rsComboMarksRange = '\\u0300-\\u036f', - reComboHalfMarksRange = '\\ufe20-\\ufe2f', - rsComboSymbolsRange = '\\u20d0-\\u20ff', - rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, - rsDingbatRange = '\\u2700-\\u27bf', - rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', - rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', - rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', - rsPunctuationRange = '\\u2000-\\u206f', - rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', - rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', - rsVarRange = '\\ufe0e\\ufe0f', - rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; - - /** Used to compose unicode capture groups. */ - var rsApos = "['\u2019]", - rsAstral = '[' + rsAstralRange + ']', - rsBreak = '[' + rsBreakRange + ']', - rsCombo = '[' + rsComboRange + ']', - rsDigits = '\\d+', - rsDingbat = '[' + rsDingbatRange + ']', - rsLower = '[' + rsLowerRange + ']', - rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', - rsFitz = '\\ud83c[\\udffb-\\udfff]', - rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', - rsNonAstral = '[^' + rsAstralRange + ']', - rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', - rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', - rsUpper = '[' + rsUpperRange + ']', - rsZWJ = '\\u200d'; - - /** Used to compose unicode regexes. */ - var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', - rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', - rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', - rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', - reOptMod = rsModifier + '?', - rsOptVar = '[' + rsVarRange + ']?', - rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', - rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)', - rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)', - rsSeq = rsOptVar + reOptMod + rsOptJoin, - rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, - rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; - - /** Used to match apostrophes. */ - var reApos = RegExp(rsApos, 'g'); + else { + while (++i < n) { + if (!isNaN(value = number(valueof(values[i], i, values)))) { + delta = value - mean; + mean += delta / ++m; + sum += delta * (value - mean); + } + } + } - /** - * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and - * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). - */ - var reComboMark = RegExp(rsCombo, 'g'); - - /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ - var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); - - /** Used to match complex or compound words. */ - var reUnicodeWord = RegExp([ - rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', - rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', - rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, - rsUpper + '+' + rsOptContrUpper, - rsOrdUpper, - rsOrdLower, - rsDigits, - rsEmoji - ].join('|'), 'g'); - - /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ - var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); - - /** Used to detect strings that need a more robust regexp to match words. */ - var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; - - /** Used to assign default `context` object properties. */ - var contextProps = [ - 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', - 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', - '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' - ]; + if (m > 1) return sum / (m - 1); +}; - /** Used to make template sourceURLs easier to identify. */ - var templateCounter = -1; - - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = - typedArrayTags[errorTag] = typedArrayTags[funcTag] = - typedArrayTags[mapTag] = typedArrayTags[numberTag] = - typedArrayTags[objectTag] = typedArrayTags[regexpTag] = - typedArrayTags[setTag] = typedArrayTags[stringTag] = - typedArrayTags[weakMapTag] = false; - - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = - cloneableTags[boolTag] = cloneableTags[dateTag] = - cloneableTags[float32Tag] = cloneableTags[float64Tag] = - cloneableTags[int8Tag] = cloneableTags[int16Tag] = - cloneableTags[int32Tag] = cloneableTags[mapTag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[setTag] = - cloneableTags[stringTag] = cloneableTags[symbolTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[weakMapTag] = false; - - /** Used to map Latin Unicode letters to basic Latin letters. */ - var deburredLetters = { - // Latin-1 Supplement block. - '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', - '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', - '\xc7': 'C', '\xe7': 'c', - '\xd0': 'D', '\xf0': 'd', - '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', - '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', - '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', - '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', - '\xd1': 'N', '\xf1': 'n', - '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', - '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', - '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', - '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', - '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', - '\xc6': 'Ae', '\xe6': 'ae', - '\xde': 'Th', '\xfe': 'th', - '\xdf': 'ss', - // Latin Extended-A block. - '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', - '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', - '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', - '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', - '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', - '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', - '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', - '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', - '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', - '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', - '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', - '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', - '\u0134': 'J', '\u0135': 'j', - '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', - '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', - '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', - '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', - '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', - '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', - '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', - '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', - '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', - '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', - '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', - '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', - '\u0163': 't', '\u0165': 't', '\u0167': 't', - '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', - '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', - '\u0174': 'W', '\u0175': 'w', - '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', - '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', - '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', - '\u0132': 'IJ', '\u0133': 'ij', - '\u0152': 'Oe', '\u0153': 'oe', - '\u0149': "'n", '\u017f': 's' - }; +var deviation = function(array, f) { + var v = variance(array, f); + return v ? Math.sqrt(v) : v; +}; - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' - }; +var extent = function(values, valueof) { + var n = values.length, + i = -1, + value, + min, + max; - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'" - }; + if (valueof == null) { + while (++i < n) { // Find the first comparable value. + if ((value = values[i]) != null && value >= value) { + min = max = value; + while (++i < n) { // Compare the remaining values. + if ((value = values[i]) != null) { + if (min > value) min = value; + if (max < value) max = value; + } + } + } + } + } - /** Used to escape characters for inclusion in compiled string literals. */ - var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; + else { + while (++i < n) { // Find the first comparable value. + if ((value = valueof(values[i], i, values)) != null && value >= value) { + min = max = value; + while (++i < n) { // Compare the remaining values. + if ((value = valueof(values[i], i, values)) != null) { + if (min > value) min = value; + if (max < value) max = value; + } + } + } + } + } - /** Built-in method references without a dependency on `root`. */ - var freeParseFloat = parseFloat, - freeParseInt = parseInt; + return [min, max]; +}; - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; +var array = Array.prototype; - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; +var slice = array.slice; +var map = array.map; - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); +var constant = function(x) { + return function() { + return x; + }; +}; - /** Detect free variable `exports`. */ - var freeExports = 'object' == 'object' && exports && !exports.nodeType && exports; +var identity = function(x) { + return x; +}; - /** Detect free variable `module`. */ - var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module; +var d3_range = function(start, stop, step) { + start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step; - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports; + var i = -1, + n = Math.max(0, Math.ceil((stop - start) / step)) | 0, + range = new Array(n); - /** Detect free variable `process` from Node.js. */ - var freeProcess = moduleExports && freeGlobal.process; + while (++i < n) { + range[i] = start + i * step; + } - /** Used to access faster Node.js helpers. */ - var nodeUtil = (function() { - try { - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} - }()); + return range; +}; - /* Node.js helper references. */ - var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, - nodeIsDate = nodeUtil && nodeUtil.isDate, - nodeIsMap = nodeUtil && nodeUtil.isMap, - nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, - nodeIsSet = nodeUtil && nodeUtil.isSet, - nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; +var e10 = Math.sqrt(50); +var e5 = Math.sqrt(10); +var e2 = Math.sqrt(2); - /*--------------------------------------------------------------------------*/ +var ticks = function(start, stop, count) { + var reverse, + i = -1, + n, + ticks, + step; - /** - * Adds the key-value `pair` to `map`. - * - * @private - * @param {Object} map The map to modify. - * @param {Array} pair The key-value pair to add. - * @returns {Object} Returns `map`. - */ - function addMapEntry(map, pair) { - // Don't return `map.set` because it's not chainable in IE 11. - map.set(pair[0], pair[1]); - return map; - } + stop = +stop, start = +start, count = +count; + if (start === stop && count > 0) return [start]; + if (reverse = stop < start) n = start, start = stop, stop = n; + if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return []; - /** - * Adds `value` to `set`. - * - * @private - * @param {Object} set The set to modify. - * @param {*} value The value to add. - * @returns {Object} Returns `set`. - */ - function addSetEntry(set, value) { - // Don't return `set.add` because it's not chainable in IE 11. - set.add(value); - return set; + if (step > 0) { + start = Math.ceil(start / step); + stop = Math.floor(stop / step); + ticks = new Array(n = Math.ceil(stop - start + 1)); + while (++i < n) ticks[i] = (start + i) * step; + } else { + start = Math.floor(start * step); + stop = Math.ceil(stop * step); + ticks = new Array(n = Math.ceil(start - stop + 1)); + while (++i < n) ticks[i] = (start - i) / step; } - /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ - function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); - } + if (reverse) ticks.reverse(); - /** - * A specialized version of `baseAggregator` for arrays. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function arrayAggregator(array, setter, iteratee, accumulator) { - var index = -1, - length = array == null ? 0 : array.length; + return ticks; +}; - while (++index < length) { - var value = array[index]; - setter(accumulator, value, iteratee(value), array); - } - return accumulator; - } +function tickIncrement(start, stop, count) { + var step = (stop - start) / Math.max(0, count), + power = Math.floor(Math.log(step) / Math.LN10), + error = step / Math.pow(10, power); + return power >= 0 + ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) + : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1); +} - /** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEach(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length; +function tickStep(start, stop, count) { + var step0 = Math.abs(stop - start) / Math.max(0, count), + step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), + error = step0 / step1; + if (error >= e10) step1 *= 10; + else if (error >= e5) step1 *= 5; + else if (error >= e2) step1 *= 2; + return stop < start ? -step1 : step1; +} - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } +var sturges = function(values) { + return Math.ceil(Math.log(values.length) / Math.LN2) + 1; +}; - /** - * A specialized version of `_.forEachRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEachRight(array, iteratee) { - var length = array == null ? 0 : array.length; +var histogram = function() { + var value = identity, + domain = extent, + threshold = sturges; - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; - } + function histogram(data) { + var i, + n = data.length, + x, + values = new Array(n); + + for (i = 0; i < n; ++i) { + values[i] = value(data[i], i, data); } - return array; - } - /** - * A specialized version of `_.every` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; + var xz = domain(values), + x0 = xz[0], + x1 = xz[1], + tz = threshold(values, x0, x1); - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } + // Convert number of thresholds into uniform thresholds. + if (!Array.isArray(tz)) { + tz = tickStep(x0, x1, tz); + tz = d3_range(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive } - return true; - } - /** - * A specialized version of `_.filter` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function arrayFilter(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; + // Remove any thresholds outside the domain. + var m = tz.length; + while (tz[0] <= x0) tz.shift(), --m; + while (tz[m - 1] > x1) tz.pop(), --m; - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[resIndex++] = value; + var bins = new Array(m + 1), + bin; + + // Initialize bins. + for (i = 0; i <= m; ++i) { + bin = bins[i] = []; + bin.x0 = i > 0 ? tz[i - 1] : x0; + bin.x1 = i < m ? tz[i] : x1; + } + + // Assign data to bins by value, ignoring any outside the domain. + for (i = 0; i < n; ++i) { + x = values[i]; + if (x0 <= x && x <= x1) { + bins[bisectRight(tz, x, 0, m)].push(data[i]); } } - return result; - } - /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludes(array, value) { - var length = array == null ? 0 : array.length; - return !!length && baseIndexOf(array, value, 0) > -1; + return bins; } - /** - * This function is like `arrayIncludes` except that it accepts a comparator. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @param {Function} comparator The comparator invoked per element. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludesWith(array, value, comparator) { - var index = -1, - length = array == null ? 0 : array.length; + histogram.value = function(_) { + return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value; + }; - while (++index < length) { - if (comparator(value, array[index])) { - return true; - } - } - return false; - } + histogram.domain = function(_) { + return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain; + }; - /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length, - result = Array(length); + histogram.thresholds = function(_) { + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold; + }; - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } + return histogram; +}; - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; +var threshold = function(values, p, valueof) { + if (valueof == null) valueof = number; + if (!(n = values.length)) return; + if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values); + if (p >= 1) return +valueof(values[n - 1], n - 1, values); + var n, + i = (n - 1) * p, + i0 = Math.floor(i), + value0 = +valueof(values[i0], i0, values), + value1 = +valueof(values[i0 + 1], i0 + 1, values); + return value0 + (value1 - value0) * (i - i0); +}; - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } +var freedmanDiaconis = function(values, min, max) { + values = map.call(values, number).sort(d3_ascending); + return Math.ceil((max - min) / (2 * (threshold(values, 0.75) - threshold(values, 0.25)) * Math.pow(values.length, -1 / 3))); +}; - /** - * A specialized version of `_.reduce` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initAccum] Specify using the first element of `array` as - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initAccum) { - var index = -1, - length = array == null ? 0 : array.length; +var scott = function(values, min, max) { + return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3))); +}; - if (initAccum && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } +var max = function(values, valueof) { + var n = values.length, + i = -1, + value, + max; - /** - * A specialized version of `_.reduceRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initAccum] Specify using the last element of `array` as - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initAccum) { - var length = array == null ? 0 : array.length; - if (initAccum && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); + if (valueof == null) { + while (++i < n) { // Find the first comparable value. + if ((value = values[i]) != null && value >= value) { + max = value; + while (++i < n) { // Compare the remaining values. + if ((value = values[i]) != null && value > max) { + max = value; + } + } + } } - return accumulator; } - /** - * A specialized version of `_.some` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function arraySome(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; + else { + while (++i < n) { // Find the first comparable value. + if ((value = valueof(values[i], i, values)) != null && value >= value) { + max = value; + while (++i < n) { // Compare the remaining values. + if ((value = valueof(values[i], i, values)) != null && value > max) { + max = value; + } + } } } - return false; } - /** - * Gets the size of an ASCII `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - var asciiSize = baseProperty('length'); + return max; +}; - /** - * Converts an ASCII `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function asciiToArray(string) { - return string.split(''); - } +var mean = function(values, valueof) { + var n = values.length, + m = n, + i = -1, + value, + sum = 0; - /** - * Splits an ASCII `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function asciiWords(string) { - return string.match(reAsciiWord) || []; + if (valueof == null) { + while (++i < n) { + if (!isNaN(value = number(values[i]))) sum += value; + else --m; + } } - /** - * The base implementation of methods like `_.findKey` and `_.findLastKey`, - * without support for iteratee shorthands, which iterates over `collection` - * using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFindKey(collection, predicate, eachFunc) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = key; - return false; - } - }); - return result; + else { + while (++i < n) { + if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value; + else --m; + } } - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseFindIndex(array, predicate, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); + if (m) return sum / m; +}; - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; +var d3_median = function(values, valueof) { + var n = values.length, + i = -1, + value, + numbers = []; + + if (valueof == null) { + while (++i < n) { + if (!isNaN(value = number(values[i]))) { + numbers.push(value); } } - return -1; - } - - /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - return value === value - ? strictIndexOf(array, value, fromIndex) - : baseFindIndex(array, baseIsNaN, fromIndex); } - /** - * This function is like `baseIndexOf` except that it accepts a comparator. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @param {Function} comparator The comparator invoked per element. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOfWith(array, value, fromIndex, comparator) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (comparator(array[index], value)) { - return index; + else { + while (++i < n) { + if (!isNaN(value = number(valueof(values[i], i, values)))) { + numbers.push(value); } } - return -1; } - /** - * The base implementation of `_.isNaN` without support for number objects. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - */ - function baseIsNaN(value) { - return value !== value; - } + return threshold(numbers.sort(d3_ascending), 0.5); +}; - /** - * The base implementation of `_.mean` and `_.meanBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the mean. - */ - function baseMean(array, iteratee) { - var length = array == null ? 0 : array.length; - return length ? (baseSum(array, iteratee) / length) : NAN; - } +var merge = function(arrays) { + var n = arrays.length, + m, + i = -1, + j = 0, + merged, + array; - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } + while (++i < n) j += arrays[i].length; + merged = new Array(j); - /** - * The base implementation of `_.propertyOf` without support for deep paths. - * - * @private - * @param {Object} object The object to query. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyOf(object) { - return function(key) { - return object == null ? undefined : object[key]; - }; + while (--n >= 0) { + array = arrays[n]; + m = array.length; + while (--m >= 0) { + merged[--j] = array[m]; + } } - /** - * The base implementation of `_.reduce` and `_.reduceRight`, without support - * for iteratee shorthands, which iterates over `collection` using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initAccum Specify using the first or last element of - * `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initAccum - ? (initAccum = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } + return merged; +}; - /** - * The base implementation of `_.sortBy` which uses `comparer` to define the - * sort order of `array` and replaces criteria objects with their corresponding - * values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; +var min = function(values, valueof) { + var n = values.length, + i = -1, + value, + min; - array.sort(comparer); - while (length--) { - array[length] = array[length].value; + if (valueof == null) { + while (++i < n) { // Find the first comparable value. + if ((value = values[i]) != null && value >= value) { + min = value; + while (++i < n) { // Compare the remaining values. + if ((value = values[i]) != null && min > value) { + min = value; + } + } + } } - return array; } - /** - * The base implementation of `_.sum` and `_.sumBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(array, iteratee) { - var result, - index = -1, - length = array.length; - - while (++index < length) { - var current = iteratee(array[index]); - if (current !== undefined) { - result = result === undefined ? current : (result + current); - } + else { + while (++i < n) { // Find the first comparable value. + if ((value = valueof(values[i], i, values)) != null && value >= value) { + min = value; + while (++i < n) { // Compare the remaining values. + if ((value = valueof(values[i], i, values)) != null && min > value) { + min = value; + } + } + } } - return result; } - /** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ - function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); + return min; +}; - while (++index < n) { - result[index] = iteratee(index); +var permute = function(array, indexes) { + var i = indexes.length, permutes = new Array(i); + while (i--) permutes[i] = array[indexes[i]]; + return permutes; +}; + +var scan = function(values, compare) { + if (!(n = values.length)) return; + var n, + i = 0, + j = 0, + xi, + xj = values[j]; + + if (compare == null) compare = d3_ascending; + + while (++i < n) { + if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) { + xj = xi, j = i; } - return result; } - /** - * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array - * of key-value pairs for `object` corresponding to the property names of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the key-value pairs. - */ - function baseToPairs(object, props) { - return arrayMap(props, function(key) { - return [key, object[key]]; - }); - } + if (compare(xj, xj) === 0) return j; +}; - /** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ - function baseUnary(func) { - return function(value) { - return func(value); - }; - } +var shuffle = function(array, i0, i1) { + var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0), + t, + i; - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - return arrayMap(props, function(key) { - return object[key]; - }); + while (m) { + i = Math.random() * m-- | 0; + t = array[m + i0]; + array[m + i0] = array[i + i0]; + array[i + i0] = t; } - /** - * Checks if a `cache` value for `key` exists. - * - * @private - * @param {Object} cache The cache to query. - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function cacheHas(cache, key) { - return cache.has(key); - } + return array; +}; - /** - * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the first unmatched string symbol. - */ - function charsStartIndex(strSymbols, chrSymbols) { - var index = -1, - length = strSymbols.length; +var sum = function(values, valueof) { + var n = values.length, + i = -1, + value, + sum = 0; - while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; + if (valueof == null) { + while (++i < n) { + if (value = +values[i]) sum += value; // Note: zero and null are equivalent. + } } - /** - * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the last unmatched string symbol. - */ - function charsEndIndex(strSymbols, chrSymbols) { - var index = strSymbols.length; - - while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; + else { + while (++i < n) { + if (value = +valueof(values[i], i, values)) sum += value; + } } - /** - * Gets the number of `placeholder` occurrences in `array`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} placeholder The placeholder to search for. - * @returns {number} Returns the placeholder count. - */ - function countHolders(array, placeholder) { - var length = array.length, - result = 0; + return sum; +}; - while (length--) { - if (array[length] === placeholder) { - ++result; - } +var transpose = function(matrix) { + if (!(n = matrix.length)) return []; + for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) { + for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) { + row[j] = matrix[j][i]; } - return result; } + return transpose; +}; - /** - * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A - * letters to basic Latin letters. - * - * @private - * @param {string} letter The matched letter to deburr. - * @returns {string} Returns the deburred letter. - */ - var deburrLetter = basePropertyOf(deburredLetters); +function length(d) { + return d.length; +} - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - var escapeHtmlChar = basePropertyOf(htmlEscapes); +var zip = function() { + return transpose(arguments); +}; - /** - * Used by `_.template` to escape characters for inclusion in compiled string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(chr) { - return '\\' + stringEscapes[chr]; - } +var slice$1 = Array.prototype.slice; - /** - * Gets the value at `key` of `object`. - * - * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ - function getValue(object, key) { - return object == null ? undefined : object[key]; - } +var identity$1 = function(x) { + return x; +}; - /** - * Checks if `string` contains Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a symbol is found, else `false`. - */ - function hasUnicode(string) { - return reHasUnicode.test(string); - } +var top = 1; +var right = 2; +var bottom = 3; +var left = 4; +var epsilon = 1e-6; - /** - * Checks if `string` contains a word composed of Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a word is found, else `false`. - */ - function hasUnicodeWord(string) { - return reHasUnicodeWord.test(string); - } +function translateX(x) { + return "translate(" + (x + 0.5) + ",0)"; +} - /** - * Converts `iterator` to an array. - * - * @private - * @param {Object} iterator The iterator to convert. - * @returns {Array} Returns the converted array. - */ - function iteratorToArray(iterator) { - var data, - result = []; +function translateY(y) { + return "translate(0," + (y + 0.5) + ")"; +} - while (!(data = iterator.next()).done) { - result.push(data.value); - } - return result; - } +function number$1(scale) { + return function(d) { + return +scale(d); + }; +} - /** - * Converts `map` to its key-value pairs. - * - * @private - * @param {Object} map The map to convert. - * @returns {Array} Returns the key-value pairs. - */ - function mapToArray(map) { - var index = -1, - result = Array(map.size); +function center(scale) { + var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset. + if (scale.round()) offset = Math.round(offset); + return function(d) { + return +scale(d) + offset; + }; +} - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; - } +function entering() { + return !this.__axis; +} - /** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; - } +function axis(orient, scale) { + var tickArguments = [], + tickValues = null, + tickFormat = null, + tickSizeInner = 6, + tickSizeOuter = 6, + tickPadding = 3, + k = orient === top || orient === left ? -1 : 1, + x = orient === left || orient === right ? "x" : "y", + transform = orient === top || orient === bottom ? translateX : translateY; - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; + function axis(context) { + var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues, + format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$1) : tickFormat, + spacing = Math.max(tickSizeInner, 0) + tickPadding, + range = scale.range(), + range0 = +range[0] + 0.5, + range1 = +range[range.length - 1] + 0.5, + position = (scale.bandwidth ? center : number$1)(scale.copy()), + selection = context.selection ? context.selection() : context, + path = selection.selectAll(".domain").data([null]), + tick = selection.selectAll(".tick").data(values, scale).order(), + tickExit = tick.exit(), + tickEnter = tick.enter().append("g").attr("class", "tick"), + line = tick.select("line"), + text = tick.select("text"); - while (++index < length) { - var value = array[index]; - if (value === placeholder || value === PLACEHOLDER) { - array[index] = PLACEHOLDER; - result[resIndex++] = index; - } - } - return result; - } + path = path.merge(path.enter().insert("path", ".tick") + .attr("class", "domain") + .attr("stroke", "#000")); - /** - * Converts `set` to an array of its values. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the values. - */ - function setToArray(set) { - var index = -1, - result = Array(set.size); + tick = tick.merge(tickEnter); - set.forEach(function(value) { - result[++index] = value; - }); - return result; - } + line = line.merge(tickEnter.append("line") + .attr("stroke", "#000") + .attr(x + "2", k * tickSizeInner)); - /** - * Converts `set` to its value-value pairs. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the value-value pairs. - */ - function setToPairs(set) { - var index = -1, - result = Array(set.size); + text = text.merge(tickEnter.append("text") + .attr("fill", "#000") + .attr(x, k * spacing) + .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em")); - set.forEach(function(value) { - result[++index] = [value, value]; - }); - return result; - } + if (context !== selection) { + path = path.transition(context); + tick = tick.transition(context); + line = line.transition(context); + text = text.transition(context); - /** - * A specialized version of `_.indexOf` which performs strict equality - * comparisons of values, i.e. `===`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function strictIndexOf(array, value, fromIndex) { - var index = fromIndex - 1, - length = array.length; + tickExit = tickExit.transition(context) + .attr("opacity", epsilon) + .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); }); - while (++index < length) { - if (array[index] === value) { - return index; - } + tickEnter + .attr("opacity", epsilon) + .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); }); } - return -1; - } - /** - * A specialized version of `_.lastIndexOf` which performs strict equality - * comparisons of values, i.e. `===`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function strictLastIndexOf(array, value, fromIndex) { - var index = fromIndex + 1; - while (index--) { - if (array[index] === value) { - return index; - } - } - return index; - } + tickExit.remove(); - /** - * Gets the number of symbols in `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the string size. - */ - function stringSize(string) { - return hasUnicode(string) - ? unicodeSize(string) - : asciiSize(string); - } + path + .attr("d", orient === left || orient == right + ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter + : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter); - /** - * Converts `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function stringToArray(string) { - return hasUnicode(string) - ? unicodeToArray(string) - : asciiToArray(string); - } + tick + .attr("opacity", 1) + .attr("transform", function(d) { return transform(position(d)); }); - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - var unescapeHtmlChar = basePropertyOf(htmlUnescapes); + line + .attr(x + "2", k * tickSizeInner); - /** - * Gets the size of a Unicode `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - function unicodeSize(string) { - var result = reUnicode.lastIndex = 0; - while (reUnicode.test(string)) { - ++result; - } - return result; - } + text + .attr(x, k * spacing) + .text(format); - /** - * Converts a Unicode `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function unicodeToArray(string) { - return string.match(reUnicode) || []; - } + selection.filter(entering) + .attr("fill", "none") + .attr("font-size", 10) + .attr("font-family", "sans-serif") + .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle"); - /** - * Splits a Unicode `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function unicodeWords(string) { - return string.match(reUnicodeWord) || []; + selection + .each(function() { this.__axis = position; }); } - /*--------------------------------------------------------------------------*/ - - /** - * Create a new pristine `lodash` function using the `context` object. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Util - * @param {Object} [context=root] The context object. - * @returns {Function} Returns a new `lodash` function. - * @example - * - * _.mixin({ 'foo': _.constant('foo') }); - * - * var lodash = _.runInContext(); - * lodash.mixin({ 'bar': lodash.constant('bar') }); - * - * _.isFunction(_.foo); - * // => true - * _.isFunction(_.bar); - * // => false - * - * lodash.isFunction(lodash.foo); - * // => false - * lodash.isFunction(lodash.bar); - * // => true - * - * // Create a suped-up `defer` in Node.js. - * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; - */ - var runInContext = (function runInContext(context) { - context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); - - /** Built-in constructor references. */ - var Array = context.Array, - Date = context.Date, - Error = context.Error, - Function = context.Function, - Math = context.Math, - Object = context.Object, - RegExp = context.RegExp, - String = context.String, - TypeError = context.TypeError; - - /** Used for built-in method references. */ - var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.prototype; - - /** Used to detect overreaching core-js shims. */ - var coreJsData = context['__core-js_shared__']; - - /** Used to resolve the decompiled source of functions. */ - var funcToString = funcProto.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** Used to detect methods masquerading as native. */ - var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; - }()); - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var nativeObjectToString = objectProto.toString; - - /** Used to infer the `Object` constructor. */ - var objectCtorString = funcToString.call(Object); + axis.scale = function(_) { + return arguments.length ? (scale = _, axis) : scale; + }; - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; + axis.ticks = function() { + return tickArguments = slice$1.call(arguments), axis; + }; - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); + axis.tickArguments = function(_) { + return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice(); + }; - /** Built-in value references. */ - var Buffer = moduleExports ? context.Buffer : undefined, - Symbol = context.Symbol, - Uint8Array = context.Uint8Array, - allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, - getPrototype = overArg(Object.getPrototypeOf, Object), - objectCreate = Object.create, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - splice = arrayProto.splice, - spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, - symIterator = Symbol ? Symbol.iterator : undefined, - symToStringTag = Symbol ? Symbol.toStringTag : undefined; - - var defineProperty = (function() { - try { - var func = getNative(Object, 'defineProperty'); - func({}, '', {}); - return func; - } catch (e) {} - }()); - - /** Mocked built-ins. */ - var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, - ctxNow = Date && Date.now !== root.Date.now && Date.now, - ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; - - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil, - nativeFloor = Math.floor, - nativeGetSymbols = Object.getOwnPropertySymbols, - nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, - nativeIsFinite = context.isFinite, - nativeJoin = arrayProto.join, - nativeKeys = overArg(Object.keys, Object), - nativeMax = Math.max, - nativeMin = Math.min, - nativeNow = Date.now, - nativeParseInt = context.parseInt, - nativeRandom = Math.random, - nativeReverse = arrayProto.reverse; - - /* Built-in method references that are verified to be native. */ - var DataView = getNative(context, 'DataView'), - Map = getNative(context, 'Map'), - Promise = getNative(context, 'Promise'), - Set = getNative(context, 'Set'), - WeakMap = getNative(context, 'WeakMap'), - nativeCreate = getNative(Object, 'create'); - - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap; - - /** Used to lookup unminified function names. */ - var realNames = {}; - - /** Used to detect maps, sets, and weakmaps. */ - var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - - /** Used to convert symbols to primitives and strings. */ - var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - - /*------------------------------------------------------------------------*/ + axis.tickValues = function(_) { + return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice(); + }; - /** - * Creates a `lodash` object which wraps `value` to enable implicit method - * chain sequences. Methods that operate on and return arrays, collections, - * and functions can be chained together. Methods that retrieve a single value - * or may return a primitive value will automatically end the chain sequence - * and return the unwrapped value. Otherwise, the value must be unwrapped - * with `_#value`. - * - * Explicit chain sequences, which must be unwrapped with `_#value`, may be - * enabled using `_.chain`. - * - * The execution of chained methods is lazy, that is, it's deferred until - * `_#value` is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. - * Shortcut fusion is an optimization to merge iteratee calls; this avoids - * the creation of intermediate arrays and can greatly reduce the number of - * iteratee executions. Sections of a chain sequence qualify for shortcut - * fusion if the section is applied to an array and iteratees accept only - * one argument. The heuristic for whether a section qualifies for shortcut - * fusion is subject to change. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, - * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, - * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, - * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, - * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, - * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, - * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, - * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, - * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, - * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, - * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, - * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, - * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, - * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, - * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, - * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, - * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, - * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, - * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, - * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, - * `zipObject`, `zipObjectDeep`, and `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, - * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, - * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, - * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, - * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, - * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, - * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, - * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, - * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, - * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, - * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, - * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, - * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, - * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, - * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, - * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, - * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, - * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, - * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, - * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, - * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, - * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, - * `upperFirst`, `value`, and `words` - * - * @name _ - * @constructor - * @category Seq - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2, 3]); - * - * // Returns an unwrapped value. - * wrapped.reduce(_.add); - * // => 6 - * - * // Returns a wrapped value. - * var squares = wrapped.map(square); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); - } - } - return new LodashWrapper(value); - } + axis.tickFormat = function(_) { + return arguments.length ? (tickFormat = _, axis) : tickFormat; + }; - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} proto The object to inherit from. - * @returns {Object} Returns the new object. - */ - var baseCreate = (function() { - function object() {} - return function(proto) { - if (!isObject(proto)) { - return {}; - } - if (objectCreate) { - return objectCreate(proto); - } - object.prototype = proto; - var result = new object; - object.prototype = undefined; - return result; - }; - }()); + axis.tickSize = function(_) { + return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner; + }; - /** - * The function whose prototype chain sequence wrappers inherit from. - * - * @private - */ - function baseLodash() { - // No operation performed. - } + axis.tickSizeInner = function(_) { + return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner; + }; - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable explicit method chain sequences. - */ - function LodashWrapper(value, chainAll) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__chain__ = !!chainAll; - this.__index__ = 0; - this.__values__ = undefined; - } + axis.tickSizeOuter = function(_) { + return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter; + }; - /** - * By default, the template delimiters used by lodash are like those in - * embedded Ruby (ERB) as well as ES2015 template strings. Change the - * following template settings to use alternative delimiters. - * - * @static - * @memberOf _ - * @type {Object} - */ - lodash.templateSettings = { + axis.tickPadding = function(_) { + return arguments.length ? (tickPadding = +_, axis) : tickPadding; + }; - /** - * Used to detect `data` property values to be HTML-escaped. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'escape': reEscape, + return axis; +} - /** - * Used to detect code to be evaluated. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'evaluate': reEvaluate, +function axisTop(scale) { + return axis(top, scale); +} - /** - * Used to detect `data` property values to inject. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'interpolate': reInterpolate, +function axisRight(scale) { + return axis(right, scale); +} - /** - * Used to reference the data object in the template text. - * - * @memberOf _.templateSettings - * @type {string} - */ - 'variable': '', +function axisBottom(scale) { + return axis(bottom, scale); +} - /** - * Used to import variables into the compiled template. - * - * @memberOf _.templateSettings - * @type {Object} - */ - 'imports': { - - /** - * A reference to the `lodash` function. - * - * @memberOf _.templateSettings.imports - * @type {Function} - */ - '_': lodash - } - }; +function axisLeft(scale) { + return axis(left, scale); +} - // Ensure wrappers are instances of `baseLodash`. - lodash.prototype = baseLodash.prototype; - lodash.prototype.constructor = lodash; +var noop = {value: function() {}}; - LodashWrapper.prototype = baseCreate(baseLodash.prototype); - LodashWrapper.prototype.constructor = LodashWrapper; +function dispatch() { + for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) { + if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t); + _[t] = []; + } + return new Dispatch(_); +} - /*------------------------------------------------------------------------*/ +function Dispatch(_) { + this._ = _; +} - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @constructor - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__dir__ = 1; - this.__filtered__ = false; - this.__iteratees__ = []; - this.__takeCount__ = MAX_ARRAY_LENGTH; - this.__views__ = []; - } +function parseTypenames(typenames, types) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name = "", i = t.indexOf("."); + if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); + if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t); + return {type: t, name: name}; + }); +} - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = copyArray(this.__actions__); - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = copyArray(this.__iteratees__); - result.__takeCount__ = this.__takeCount__; - result.__views__ = copyArray(this.__views__); - return result; - } +Dispatch.prototype = dispatch.prototype = { + constructor: Dispatch, + on: function(typename, callback) { + var _ = this._, + T = parseTypenames(typename + "", _), + t, + i = -1, + n = T.length; - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; + // If no callback was specified, return the callback of the given type and name. + if (arguments.length < 2) { + while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t; + return; } - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(), - dir = this.__dir__, - isArr = isArray(array), - isRight = dir < 0, - arrLength = isArr ? array.length : 0, - view = getView(0, arrLength, this.__views__), - start = view.start, - end = view.end, - length = end - start, - index = isRight ? end : (start - 1), - iteratees = this.__iteratees__, - iterLength = iteratees.length, - resIndex = 0, - takeCount = nativeMin(length, this.__takeCount__); - - if (!isArr || (!isRight && arrLength == length && takeCount == length)) { - return baseWrapperValue(array, this.__actions__); - } - var result = []; - - outer: - while (length-- && resIndex < takeCount) { - index += dir; - - var iterIndex = -1, - value = array[index]; - - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], - iteratee = data.iteratee, - type = data.type, - computed = iteratee(value); - - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; - } else { - break outer; - } - } - } - result[resIndex++] = value; - } - return result; + // If a type was specified, set the callback for the given type and name. + // Otherwise, if a null callback was specified, remove callbacks of the given name. + if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback); + while (++i < n) { + if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback); + else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null); } - // Ensure `LazyWrapper` is an instance of `baseLodash`. - LazyWrapper.prototype = baseCreate(baseLodash.prototype); - LazyWrapper.prototype.constructor = LazyWrapper; - - /*------------------------------------------------------------------------*/ + return this; + }, + copy: function() { + var copy = {}, _ = this._; + for (var t in _) copy[t] = _[t].slice(); + return new Dispatch(copy); + }, + call: function(type, that) { + if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2]; + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + }, + apply: function(type, that, args) { + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + } +}; - /** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Hash(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } +function get(type, name) { + for (var i = 0, n = type.length, c; i < n; ++i) { + if ((c = type[i]).name === name) { + return c.value; } + } +} - /** - * Removes all key-value entries from the hash. - * - * @private - * @name clear - * @memberOf Hash - */ - function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; +function set(type, name, callback) { + for (var i = 0, n = type.length; i < n; ++i) { + if (type[i].name === name) { + type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1)); + break; } + } + if (callback != null) type.push({name: name, value: callback}); + return type; +} - /** - * Removes `key` and its value from the hash. - * - * @private - * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; - this.size -= result ? 1 : 0; - return result; - } +var xhtml = "http://www.w3.org/1999/xhtml"; - /** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; - } +var namespaces = { + svg: "http://www.w3.org/2000/svg", + xhtml: xhtml, + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" +}; - /** - * Checks if a hash value for `key` exists. - * - * @private - * @name has - * @memberOf Hash - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); - } +var namespace = function(name) { + var prefix = name += "", i = prefix.indexOf(":"); + if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); + return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; +}; - /** - * Sets the hash `key` to `value`. - * - * @private - * @name set - * @memberOf Hash - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. - */ - function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; - } - - // Add methods to `Hash`. - Hash.prototype.clear = hashClear; - Hash.prototype['delete'] = hashDelete; - Hash.prototype.get = hashGet; - Hash.prototype.has = hashHas; - Hash.prototype.set = hashSet; +function creatorInherit(name) { + return function() { + var document = this.ownerDocument, + uri = this.namespaceURI; + return uri === xhtml && document.documentElement.namespaceURI === xhtml + ? document.createElement(name) + : document.createElementNS(uri, name); + }; +} - /*------------------------------------------------------------------------*/ +function creatorFixed(fullname) { + return function() { + return this.ownerDocument.createElementNS(fullname.space, fullname.local); + }; +} - /** - * Creates an list cache object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } +var creator = function(name) { + var fullname = namespace(name); + return (fullname.local + ? creatorFixed + : creatorInherit)(fullname); +}; - /** - * Removes all key-value entries from the list cache. - * - * @private - * @name clear - * @memberOf ListCache - */ - function listCacheClear() { - this.__data__ = []; - this.size = 0; - } +var nextId = 0; - /** - * Removes `key` and its value from the list cache. - * - * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); +function local$1() { + return new Local; +} - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - --this.size; - return true; - } +function Local() { + this._ = "@" + (++nextId).toString(36); +} - /** - * Gets the list cache value for `key`. - * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); +Local.prototype = local$1.prototype = { + constructor: Local, + get: function(node) { + var id = this._; + while (!(id in node)) if (!(node = node.parentNode)) return; + return node[id]; + }, + set: function(node, value) { + return node[this._] = value; + }, + remove: function(node) { + return this._ in node && delete node[this._]; + }, + toString: function() { + return this._; + } +}; - return index < 0 ? undefined : data[index][1]; - } +var matcher = function(selector) { + return function() { + return this.matches(selector); + }; +}; - /** - * Checks if a list cache value for `key` exists. - * - * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; - } +if (typeof document !== "undefined") { + var element = document.documentElement; + if (!element.matches) { + var vendorMatches = element.webkitMatchesSelector + || element.msMatchesSelector + || element.mozMatchesSelector + || element.oMatchesSelector; + matcher = function(selector) { + return function() { + return vendorMatches.call(this, selector); + }; + }; + } +} - /** - * Sets the list cache `key` to `value`. - * - * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. - */ - function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); +var matcher$1 = matcher; - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; - } +var filterEvents = {}; - // Add methods to `ListCache`. - ListCache.prototype.clear = listCacheClear; - ListCache.prototype['delete'] = listCacheDelete; - ListCache.prototype.get = listCacheGet; - ListCache.prototype.has = listCacheHas; - ListCache.prototype.set = listCacheSet; +var event = null; - /*------------------------------------------------------------------------*/ +if (typeof document !== "undefined") { + var element$1 = document.documentElement; + if (!("onmouseenter" in element$1)) { + filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"}; + } +} - /** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function MapCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } +function filterContextListener(listener, index, group) { + listener = contextListener(listener, index, group); + return function(event) { + var related = event.relatedTarget; + if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) { + listener.call(this, event); } + }; +} - /** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ - function mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; +function contextListener(listener, index, group) { + return function(event1) { + var event0 = event; // Events can be reentrant (e.g., focus). + event = event1; + try { + listener.call(this, this.__data__, index, group); + } finally { + event = event0; } + }; +} - /** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; - } +function parseTypenames$1(typenames) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name = "", i = t.indexOf("."); + if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); + return {type: t, name: name}; + }); +} - /** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function mapCacheGet(key) { - return getMapData(this, key).get(key); +function onRemove(typename) { + return function() { + var on = this.__on; + if (!on) return; + for (var j = 0, i = -1, m = on.length, o; j < m; ++j) { + if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.capture); + } else { + on[++i] = o; + } } + if (++i) on.length = i; + else delete this.__on; + }; +} - /** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapCacheHas(key) { - return getMapData(this, key).has(key); +function onAdd(typename, value, capture) { + var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener; + return function(d, i, group) { + var on = this.__on, o, listener = wrap(value, i, group); + if (on) for (var j = 0, m = on.length; j < m; ++j) { + if ((o = on[j]).type === typename.type && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.capture); + this.addEventListener(o.type, o.listener = listener, o.capture = capture); + o.value = value; + return; + } } + this.addEventListener(typename.type, listener, capture); + o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture}; + if (!on) this.__on = [o]; + else on.push(o); + }; +} - /** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ - function mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; +var selection_on = function(typename, value, capture) { + var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t; - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; + if (arguments.length < 2) { + var on = this.node().__on; + if (on) for (var j = 0, m = on.length, o; j < m; ++j) { + for (i = 0, o = on[j]; i < n; ++i) { + if ((t = typenames[i]).type === o.type && t.name === o.name) { + return o.value; + } + } } + return; + } - // Add methods to `MapCache`. - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype['delete'] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; + on = value ? onAdd : onRemove; + if (capture == null) capture = false; + for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture)); + return this; +}; - /*------------------------------------------------------------------------*/ +function customEvent(event1, listener, that, args) { + var event0 = event; + event1.sourceEvent = event; + event = event1; + try { + return listener.apply(that, args); + } finally { + event = event0; + } +} - /** - * - * Creates an array cache object to store unique values. - * - * @private - * @constructor - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var index = -1, - length = values == null ? 0 : values.length; +var sourceEvent = function() { + var current = event, source; + while (source = current.sourceEvent) current = source; + return current; +}; - this.__data__ = new MapCache; - while (++index < length) { - this.add(values[index]); - } - } +var point = function(node, event) { + var svg = node.ownerSVGElement || node; - /** - * Adds `value` to the array cache. - * - * @private - * @name add - * @memberOf SetCache - * @alias push - * @param {*} value The value to cache. - * @returns {Object} Returns the cache instance. - */ - function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; - } + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + point.x = event.clientX, point.y = event.clientY; + point = point.matrixTransform(node.getScreenCTM().inverse()); + return [point.x, point.y]; + } - /** - * Checks if `value` is in the array cache. - * - * @private - * @name has - * @memberOf SetCache - * @param {*} value The value to search for. - * @returns {number} Returns `true` if `value` is found, else `false`. - */ - function setCacheHas(value) { - return this.__data__.has(value); - } + var rect = node.getBoundingClientRect(); + return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop]; +}; + +var d3_mouse = function(node) { + var event = sourceEvent(); + if (event.changedTouches) event = event.changedTouches[0]; + return point(node, event); +}; - // Add methods to `SetCache`. - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; +function none() {} - /*------------------------------------------------------------------------*/ +var selector = function(selector) { + return selector == null ? none : function() { + return this.querySelector(selector); + }; +}; - /** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Stack(entries) { - var data = this.__data__ = new ListCache(entries); - this.size = data.size; - } +var selection_select = function(select) { + if (typeof select !== "function") select = selector(select); - /** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ - function stackClear() { - this.__data__ = new ListCache; - this.size = 0; + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { + if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + subgroup[i] = subnode; + } } + } - /** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function stackDelete(key) { - var data = this.__data__, - result = data['delete'](key); + return new Selection(subgroups, this._parents); +}; - this.size = data.size; - return result; - } +function empty$1() { + return []; +} - /** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function stackGet(key) { - return this.__data__.get(key); - } +var selectorAll = function(selector) { + return selector == null ? empty$1 : function() { + return this.querySelectorAll(selector); + }; +}; - /** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function stackHas(key) { - return this.__data__.has(key); - } +var selection_selectAll = function(select) { + if (typeof select !== "function") select = selectorAll(select); - /** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ - function stackSet(key, value) { - var data = this.__data__; - if (data instanceof ListCache) { - var pairs = data.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - this.size = ++data.size; - return this; - } - data = this.__data__ = new MapCache(pairs); + for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + subgroups.push(select.call(node, node.__data__, i, group)); + parents.push(node); } - data.set(key, value); - this.size = data.size; - return this; } + } - // Add methods to `Stack`. - Stack.prototype.clear = stackClear; - Stack.prototype['delete'] = stackDelete; - Stack.prototype.get = stackGet; - Stack.prototype.has = stackHas; - Stack.prototype.set = stackSet; + return new Selection(subgroups, parents); +}; - /*------------------------------------------------------------------------*/ +var selection_filter = function(match) { + if (typeof match !== "function") match = matcher$1(match); - /** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ - function arrayLikeKeys(value, inherited) { - var isArr = isArray(value), - isArg = !isArr && isArguments(value), - isBuff = !isArr && !isArg && isBuffer(value), - isType = !isArr && !isArg && !isBuff && isTypedArray(value), - skipIndexes = isArr || isArg || isBuff || isType, - result = skipIndexes ? baseTimes(value.length, String) : [], - length = result.length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && ( - // Safari 9 has enumerable `arguments.length` in strict mode. - key == 'length' || - // Node.js 0.10 has enumerable non-index properties on buffers. - (isBuff && (key == 'offset' || key == 'parent')) || - // PhantomJS 2 has enumerable non-index properties on typed arrays. - (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || - // Skip index properties. - isIndex(key, length) - ))) { - result.push(key); - } + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { + if ((node = group[i]) && match.call(node, node.__data__, i, group)) { + subgroup.push(node); } - return result; } + } - /** - * A specialized version of `_.sample` for arrays. - * - * @private - * @param {Array} array The array to sample. - * @returns {*} Returns the random element. - */ - function arraySample(array) { - var length = array.length; - return length ? array[baseRandom(0, length - 1)] : undefined; - } + return new Selection(subgroups, this._parents); +}; - /** - * A specialized version of `_.sampleSize` for arrays. - * - * @private - * @param {Array} array The array to sample. - * @param {number} n The number of elements to sample. - * @returns {Array} Returns the random elements. - */ - function arraySampleSize(array, n) { - return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); - } +var sparse = function(update) { + return new Array(update.length); +}; - /** - * A specialized version of `_.shuffle` for arrays. - * - * @private - * @param {Array} array The array to shuffle. - * @returns {Array} Returns the new shuffled array. - */ - function arrayShuffle(array) { - return shuffleSelf(copyArray(array)); - } +var selection_enter = function() { + return new Selection(this._enter || this._groups.map(sparse), this._parents); +}; - /** - * This function is like `assignValue` except that it doesn't assign - * `undefined` values. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignMergeValue(object, key, value) { - if ((value !== undefined && !eq(object[key], value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } +function EnterNode(parent, datum) { + this.ownerDocument = parent.ownerDocument; + this.namespaceURI = parent.namespaceURI; + this._next = null; + this._parent = parent; + this.__data__ = datum; +} - /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } +EnterNode.prototype = { + constructor: EnterNode, + appendChild: function(child) { return this._parent.insertBefore(child, this._next); }, + insertBefore: function(child, next) { return this._parent.insertBefore(child, next); }, + querySelector: function(selector) { return this._parent.querySelector(selector); }, + querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); } +}; - /** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; - } +var constant$1 = function(x) { + return function() { + return x; + }; +}; - /** - * Aggregates elements of `collection` on `accumulator` with keys transformed - * by `iteratee` and values set by `setter`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function baseAggregator(collection, setter, iteratee, accumulator) { - baseEach(collection, function(value, key, collection) { - setter(accumulator, value, iteratee(value), collection); - }); - return accumulator; - } +var keyPrefix = "$"; // Protect against keys like “__proto__”. - /** - * The base implementation of `_.assign` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssign(object, source) { - return object && copyObject(source, keys(source), object); +function bindIndex(parent, group, enter, update, exit, data) { + var i = 0, + node, + groupLength = group.length, + dataLength = data.length; + + // Put any non-null nodes that fit into update. + // Put any null nodes into enter. + // Put any remaining data into enter. + for (; i < dataLength; ++i) { + if (node = group[i]) { + node.__data__ = data[i]; + update[i] = node; + } else { + enter[i] = new EnterNode(parent, data[i]); } + } - /** - * The base implementation of `_.assignIn` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssignIn(object, source) { - return object && copyObject(source, keysIn(source), object); + // Put any non-null nodes that don’t fit into exit. + for (; i < groupLength; ++i) { + if (node = group[i]) { + exit[i] = node; } + } +} - /** - * The base implementation of `assignValue` and `assignMergeValue` without - * value checks. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function baseAssignValue(object, key, value) { - if (key == '__proto__' && defineProperty) { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': true, - 'value': value, - 'writable': true - }); +function bindKey(parent, group, enter, update, exit, data, key) { + var i, + node, + nodeByKeyValue = {}, + groupLength = group.length, + dataLength = data.length, + keyValues = new Array(groupLength), + keyValue; + + // Compute the key for each node. + // If multiple nodes have the same key, the duplicates are added to exit. + for (i = 0; i < groupLength; ++i) { + if (node = group[i]) { + keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group); + if (keyValue in nodeByKeyValue) { + exit[i] = node; } else { - object[key] = value; + nodeByKeyValue[keyValue] = node; } } + } - /** - * The base implementation of `_.at` without support for individual paths. - * - * @private - * @param {Object} object The object to iterate over. - * @param {string[]} paths The property paths to pick. - * @returns {Array} Returns the picked elements. - */ - function baseAt(object, paths) { - var index = -1, - length = paths.length, - result = Array(length), - skip = object == null; - - while (++index < length) { - result[index] = skip ? undefined : get(object, paths[index]); - } - return result; + // Compute the key for each datum. + // If there a node associated with this key, join and add it to update. + // If there is not (or the key is a duplicate), add it to enter. + for (i = 0; i < dataLength; ++i) { + keyValue = keyPrefix + key.call(parent, data[i], i, data); + if (node = nodeByKeyValue[keyValue]) { + update[i] = node; + node.__data__ = data[i]; + nodeByKeyValue[keyValue] = null; + } else { + enter[i] = new EnterNode(parent, data[i]); } + } - /** - * The base implementation of `_.clamp` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - */ - function baseClamp(number, lower, upper) { - if (number === number) { - if (upper !== undefined) { - number = number <= upper ? number : upper; - } - if (lower !== undefined) { - number = number >= lower ? number : lower; - } - } - return number; + // Add any remaining nodes that were not bound to data to exit. + for (i = 0; i < groupLength; ++i) { + if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) { + exit[i] = node; } + } +} - /** - * The base implementation of `_.clone` and `_.cloneDeep` which tracks - * traversed objects. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} bitmask The bitmask flags. - * 1 - Deep clone - * 2 - Flatten inherited properties - * 4 - Clone symbols - * @param {Function} [customizer] The function to customize cloning. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The parent object of `value`. - * @param {Object} [stack] Tracks traversed objects and their clone counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, bitmask, customizer, key, object, stack) { - var result, - isDeep = bitmask & CLONE_DEEP_FLAG, - isFlat = bitmask & CLONE_FLAT_FLAG, - isFull = bitmask & CLONE_SYMBOLS_FLAG; +var selection_data = function(value, key) { + if (!value) { + data = new Array(this.size()), j = -1; + this.each(function(d) { data[++j] = d; }); + return data; + } - if (customizer) { - result = object ? customizer(value, key, object, stack) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return copyArray(value, result); - } - } else { - var tag = getTag(value), - isFunc = tag == funcTag || tag == genTag; - - if (isBuffer(value)) { - return cloneBuffer(value, isDeep); - } - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = (isFlat || isFunc) ? {} : initCloneObject(value); - if (!isDeep) { - return isFlat - ? copySymbolsIn(value, baseAssignIn(result, value)) - : copySymbols(value, baseAssign(result, value)); - } - } else { - if (!cloneableTags[tag]) { - return object ? value : {}; - } - result = initCloneByTag(value, tag, baseClone, isDeep); - } - } - // Check for circular references and return its corresponding clone. - stack || (stack = new Stack); - var stacked = stack.get(value); - if (stacked) { - return stacked; - } - stack.set(value, result); + var bind = key ? bindKey : bindIndex, + parents = this._parents, + groups = this._groups; - var keysFunc = isFull - ? (isFlat ? getAllKeysIn : getAllKeys) - : (isFlat ? keysIn : keys); + if (typeof value !== "function") value = constant$1(value); - var props = isArr ? undefined : keysFunc(value); - arrayEach(props || value, function(subValue, key) { - if (props) { - key = subValue; - subValue = value[key]; - } - // Recursively populate clone (susceptible to call stack limits). - assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - return result; - } + for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) { + var parent = parents[j], + group = groups[j], + groupLength = group.length, + data = value.call(parent, parent && parent.__data__, j, parents), + dataLength = data.length, + enterGroup = enter[j] = new Array(dataLength), + updateGroup = update[j] = new Array(dataLength), + exitGroup = exit[j] = new Array(groupLength); - /** - * The base implementation of `_.conforms` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property predicates to conform to. - * @returns {Function} Returns the new spec function. - */ - function baseConforms(source) { - var props = keys(source); - return function(object) { - return baseConformsTo(object, source, props); - }; - } - - /** - * The base implementation of `_.conformsTo` which accepts `props` to check. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - */ - function baseConformsTo(object, source, props) { - var length = props.length; - if (object == null) { - return !length; - } - object = Object(object); - while (length--) { - var key = props[length], - predicate = source[key], - value = object[key]; - - if ((value === undefined && !(key in object)) || !predicate(value)) { - return false; - } - } - return true; - } + bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); - /** - * The base implementation of `_.delay` and `_.defer` which accepts `args` - * to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Array} args The arguments to provide to `func`. - * @returns {number|Object} Returns the timer id or timeout object. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); + // Now connect the enter nodes to their following update node, such that + // appendChild can insert the materialized enter node before this node, + // rather than at the end of the parent node. + for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) { + if (previous = enterGroup[i0]) { + if (i0 >= i1) i1 = i0 + 1; + while (!(next = updateGroup[i1]) && ++i1 < dataLength); + previous._next = next || null; } - return setTimeout(function() { func.apply(undefined, args); }, wait); } + } - /** - * The base implementation of methods like `_.difference` without support - * for excluding multiple arrays or iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - isCommon = true, - length = array.length, - result = [], - valuesLength = values.length; - - if (!length) { - return result; - } - if (iteratee) { - values = arrayMap(values, baseUnary(iteratee)); - } - if (comparator) { - includes = arrayIncludesWith; - isCommon = false; - } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee == null ? value : iteratee(value); - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === computed) { - continue outer; - } - } - result.push(value); - } - else if (!includes(values, computed, comparator)) { - result.push(value); - } - } - return result; - } + update = new Selection(update, parents); + update._enter = enter; + update._exit = exit; + return update; +}; - /** - * The base implementation of `_.forEach` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); +var selection_exit = function() { + return new Selection(this._exit || this._groups.map(sparse), this._parents); +}; - /** - * The base implementation of `_.forEachRight` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEachRight = createBaseEach(baseForOwnRight, true); +var selection_merge = function(selection$$1) { - /** - * The base implementation of `_.every` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` - */ - function baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; + for (var groups0 = this._groups, groups1 = selection$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group0[i] || group1[i]) { + merge[i] = node; + } } + } - /** - * The base implementation of methods like `_.max` and `_.min` which accepts a - * `comparator` to determine the extremum value. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The iteratee invoked per iteration. - * @param {Function} comparator The comparator used to compare values. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(array, iteratee, comparator) { - var index = -1, - length = array.length; + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } + + return new Selection(merges, this._parents); +}; - while (++index < length) { - var value = array[index], - current = iteratee(value); +var selection_order = function() { - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : comparator(current, computed) - )) { - var computed = current, - result = value; - } + for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) { + for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; } - return result; } + } - /** - * The base implementation of `_.fill` without an iteratee call guard. - * - * @private - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - */ - function baseFill(array, value, start, end) { - var length = array.length; + return this; +}; - start = toInteger(start); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : toInteger(end); - if (end < 0) { - end += length; - } - end = start > end ? 0 : toLength(end); - while (start < end) { - array[start++] = value; - } - return array; - } +var selection_sort = function(compare) { + if (!compare) compare = ascending; - /** - * The base implementation of `_.filter` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } + function compareNode(a, b) { + return a && b ? compare(a.__data__, b.__data__) : !a - !b; + } - /** - * The base implementation of `_.flatten` with support for restricting flattening. - * - * @private - * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); - - while (++index < length) { - var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } + for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group[i]) { + sortgroup[i] = node; } - return result; } + sortgroup.sort(compareNode); + } - /** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); + return new Selection(sortgroups, this._parents).order(); +}; - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); +function ascending(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; +} - /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); - } +var selection_call = function() { + var callback = arguments[0]; + arguments[0] = this; + callback.apply(null, arguments); + return this; +}; - /** - * The base implementation of `_.forOwnRight` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return object && baseForRight(object, iteratee, keys); - } +var selection_nodes = function() { + var nodes = new Array(this.size()), i = -1; + this.each(function() { nodes[++i] = this; }); + return nodes; +}; - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from `props`. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the function names. - */ - function baseFunctions(object, props) { - return arrayFilter(props, function(key) { - return isFunction(object[key]); - }); +var selection_node = function() { + + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length; i < n; ++i) { + var node = group[i]; + if (node) return node; } + } - /** - * The base implementation of `_.get` without support for default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path) { - path = castPath(path, object); + return null; +}; - var index = 0, - length = path.length; +var selection_size = function() { + var size = 0; + this.each(function() { ++size; }); + return size; +}; - while (object != null && index < length) { - object = object[toKey(path[index++])]; - } - return (index && index == length) ? object : undefined; - } +var selection_empty = function() { + return !this.node(); +}; - /** - * The base implementation of `getAllKeys` and `getAllKeysIn` which uses - * `keysFunc` and `symbolsFunc` to get the enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Function} keysFunc The function to get the keys of `object`. - * @param {Function} symbolsFunc The function to get the symbols of `object`. - * @returns {Array} Returns the array of property names and symbols. - */ - function baseGetAllKeys(object, keysFunc, symbolsFunc) { - var result = keysFunc(object); - return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); - } +var selection_each = function(callback) { - /** - * The base implementation of `getTag` without fallbacks for buggy environments. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - function baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) { + if (node = group[i]) callback.call(node, node.__data__, i, group); } + } - /** - * The base implementation of `_.gt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - */ - function baseGt(value, other) { - return value > other; - } + return this; +}; - /** - * The base implementation of `_.has` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHas(object, key) { - return object != null && hasOwnProperty.call(object, key); - } +function attrRemove(name) { + return function() { + this.removeAttribute(name); + }; +} - /** - * The base implementation of `_.hasIn` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHasIn(object, key) { - return object != null && key in Object(object); - } +function attrRemoveNS(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; +} - /** - * The base implementation of `_.inRange` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to check. - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - */ - function baseInRange(number, start, end) { - return number >= nativeMin(start, end) && number < nativeMax(start, end); - } +function attrConstant(name, value) { + return function() { + this.setAttribute(name, value); + }; +} - /** - * The base implementation of methods like `_.intersection`, without support - * for iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of shared values. - */ - function baseIntersection(arrays, iteratee, comparator) { - var includes = comparator ? arrayIncludesWith : arrayIncludes, - length = arrays[0].length, - othLength = arrays.length, - othIndex = othLength, - caches = Array(othLength), - maxLength = Infinity, - result = []; - - while (othIndex--) { - var array = arrays[othIndex]; - if (othIndex && iteratee) { - array = arrayMap(array, baseUnary(iteratee)); - } - maxLength = nativeMin(array.length, maxLength); - caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) - ? new SetCache(othIndex && array) - : undefined; - } - array = arrays[0]; - - var index = -1, - seen = caches[0]; - - outer: - while (++index < length && result.length < maxLength) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (!(seen - ? cacheHas(seen, computed) - : includes(result, computed, comparator) - )) { - othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if (!(cache - ? cacheHas(cache, computed) - : includes(arrays[othIndex], computed, comparator)) - ) { - continue outer; - } - } - if (seen) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } +function attrConstantNS(fullname, value) { + return function() { + this.setAttributeNS(fullname.space, fullname.local, value); + }; +} - /** - * The base implementation of `_.invert` and `_.invertBy` which inverts - * `object` with values transformed by `iteratee` and set by `setter`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform values. - * @param {Object} accumulator The initial inverted object. - * @returns {Function} Returns `accumulator`. - */ - function baseInverter(object, setter, iteratee, accumulator) { - baseForOwn(object, function(value, key, object) { - setter(accumulator, iteratee(value), key, object); - }); - return accumulator; - } +function attrFunction(name, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.removeAttribute(name); + else this.setAttribute(name, v); + }; +} - /** - * The base implementation of `_.invoke` without support for individual - * method arguments. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function baseInvoke(object, path, args) { - path = castPath(path, object); - object = parent(object, path); - var func = object == null ? object : object[toKey(last(path))]; - return func == null ? undefined : apply(func, object, args); - } +function attrFunctionNS(fullname, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.removeAttributeNS(fullname.space, fullname.local); + else this.setAttributeNS(fullname.space, fullname.local, v); + }; +} - /** - * The base implementation of `_.isArguments`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - */ - function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; - } +var selection_attr = function(name, value) { + var fullname = namespace(name); - /** - * The base implementation of `_.isArrayBuffer` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - */ - function baseIsArrayBuffer(value) { - return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; - } + if (arguments.length < 2) { + var node = this.node(); + return fullname.local + ? node.getAttributeNS(fullname.space, fullname.local) + : node.getAttribute(fullname); + } - /** - * The base implementation of `_.isDate` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - */ - function baseIsDate(value) { - return isObjectLike(value) && baseGetTag(value) == dateTag; - } + return this.each((value == null + ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function" + ? (fullname.local ? attrFunctionNS : attrFunction) + : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value)); +}; - /** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {boolean} bitmask The bitmask flags. - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Function} [customizer] The function to customize comparisons. - * @param {Object} [stack] Tracks traversed `value` and `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, bitmask, customizer, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); - } +var defaultView = function(node) { + return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node + || (node.document && node) // node is a Window + || node.defaultView; // node is a Document +}; - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = objIsArr ? arrayTag : getTag(object), - othTag = othIsArr ? arrayTag : getTag(other); +function styleRemove(name) { + return function() { + this.style.removeProperty(name); + }; +} - objTag = objTag == argsTag ? objectTag : objTag; - othTag = othTag == argsTag ? objectTag : othTag; +function styleConstant(name, value, priority) { + return function() { + this.style.setProperty(name, value, priority); + }; +} - var objIsObj = objTag == objectTag, - othIsObj = othTag == objectTag, - isSameTag = objTag == othTag; +function styleFunction(name, value, priority) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.style.removeProperty(name); + else this.style.setProperty(name, v, priority); + }; +} - if (isSameTag && isBuffer(object)) { - if (!isBuffer(other)) { - return false; - } - objIsArr = true; - objIsObj = false; - } - if (isSameTag && !objIsObj) { - stack || (stack = new Stack); - return (objIsArr || isTypedArray(object)) - ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) - : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); - } - if (!(bitmask & COMPARE_PARTIAL_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); +var selection_style = function(name, value, priority) { + return arguments.length > 1 + ? this.each((value == null + ? styleRemove : typeof value === "function" + ? styleFunction + : styleConstant)(name, value, priority == null ? "" : priority)) + : styleValue(this.node(), name); +}; - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; +function styleValue(node, name) { + return node.style.getPropertyValue(name) + || defaultView(node).getComputedStyle(node, null).getPropertyValue(name); +} - stack || (stack = new Stack); - return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); - } - } - if (!isSameTag) { - return false; - } - stack || (stack = new Stack); - return equalObjects(object, other, bitmask, customizer, equalFunc, stack); - } +function propertyRemove(name) { + return function() { + delete this[name]; + }; +} - /** - * The base implementation of `_.isMap` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - */ - function baseIsMap(value) { - return isObjectLike(value) && getTag(value) == mapTag; - } +function propertyConstant(name, value) { + return function() { + this[name] = value; + }; +} - /** - * The base implementation of `_.isMatch` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Array} matchData The property names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, source, matchData, customizer) { - var index = matchData.length, - length = index, - noCustomizer = !customizer; +function propertyFunction(name, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) delete this[name]; + else this[name] = v; + }; +} - if (object == null) { - return !length; - } - object = Object(object); - while (index--) { - var data = matchData[index]; - if ((noCustomizer && data[2]) - ? data[1] !== object[data[0]] - : !(data[0] in object) - ) { - return false; - } - } - while (++index < length) { - data = matchData[index]; - var key = data[0], - objValue = object[key], - srcValue = data[1]; - - if (noCustomizer && data[2]) { - if (objValue === undefined && !(key in object)) { - return false; - } - } else { - var stack = new Stack; - if (customizer) { - var result = customizer(objValue, srcValue, key, object, source, stack); - } - if (!(result === undefined - ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) - : result - )) { - return false; - } - } - } - return true; - } +var selection_property = function(name, value) { + return arguments.length > 1 + ? this.each((value == null + ? propertyRemove : typeof value === "function" + ? propertyFunction + : propertyConstant)(name, value)) + : this.node()[name]; +}; - /** - * The base implementation of `_.isNative` without bad shim checks. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - */ - function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); - } +function classArray(string) { + return string.trim().split(/^|\s+/); +} - /** - * The base implementation of `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObjectLike(value) && baseGetTag(value) == regexpTag; - } +function classList(node) { + return node.classList || new ClassList(node); +} - /** - * The base implementation of `_.isSet` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - */ - function baseIsSet(value) { - return isObjectLike(value) && getTag(value) == setTag; - } +function ClassList(node) { + this._node = node; + this._names = classArray(node.getAttribute("class") || ""); +} - /** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ - function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; +ClassList.prototype = { + add: function(name) { + var i = this._names.indexOf(name); + if (i < 0) { + this._names.push(name); + this._node.setAttribute("class", this._names.join(" ")); } - - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [value=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(value) { - // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. - // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. - if (typeof value == 'function') { - return value; - } - if (value == null) { - return identity; - } - if (typeof value == 'object') { - return isArray(value) - ? baseMatchesProperty(value[0], value[1]) - : baseMatches(value); - } - return property(value); + }, + remove: function(name) { + var i = this._names.indexOf(name); + if (i >= 0) { + this._names.splice(i, 1); + this._node.setAttribute("class", this._names.join(" ")); } + }, + contains: function(name) { + return this._names.indexOf(name) >= 0; + } +}; - /** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; - } +function classedAdd(node, names) { + var list = classList(node), i = -1, n = names.length; + while (++i < n) list.add(names[i]); +} - /** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; +function classedRemove(node, names) { + var list = classList(node), i = -1, n = names.length; + while (++i < n) list.remove(names[i]); +} - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } +function classedTrue(names) { + return function() { + classedAdd(this, names); + }; +} - /** - * The base implementation of `_.lt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - */ - function baseLt(value, other) { - return value < other; - } +function classedFalse(names) { + return function() { + classedRemove(this, names); + }; +} - /** - * The base implementation of `_.map` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; +function classedFunction(names, value) { + return function() { + (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names); + }; +} - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } +var selection_classed = function(name, value) { + var names = classArray(name + ""); - /** - * The base implementation of `_.matches` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatches(source) { - var matchData = getMatchData(source); - if (matchData.length == 1 && matchData[0][2]) { - return matchesStrictComparable(matchData[0][0], matchData[0][1]); - } - return function(object) { - return object === source || baseIsMatch(object, source, matchData); - }; - } + if (arguments.length < 2) { + var list = classList(this.node()), i = -1, n = names.length; + while (++i < n) if (!list.contains(names[i])) return false; + return true; + } - /** - * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatchesProperty(path, srcValue) { - if (isKey(path) && isStrictComparable(srcValue)) { - return matchesStrictComparable(toKey(path), srcValue); - } - return function(object) { - var objValue = get(object, path); - return (objValue === undefined && objValue === srcValue) - ? hasIn(object, path) - : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); - }; - } + return this.each((typeof value === "function" + ? classedFunction : value + ? classedTrue + : classedFalse)(names, value)); +}; - /** - * The base implementation of `_.merge` without support for multiple sources. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {number} srcIndex The index of `source`. - * @param {Function} [customizer] The function to customize merged values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMerge(object, source, srcIndex, customizer, stack) { - if (object === source) { - return; - } - baseFor(source, function(srcValue, key) { - if (isObject(srcValue)) { - stack || (stack = new Stack); - baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); - } - else { - var newValue = customizer - ? customizer(object[key], srcValue, (key + ''), object, source, stack) - : undefined; +function textRemove() { + this.textContent = ""; +} - if (newValue === undefined) { - newValue = srcValue; - } - assignMergeValue(object, key, newValue); - } - }, keysIn); - } +function textConstant(value) { + return function() { + this.textContent = value; + }; +} - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {number} srcIndex The index of `source`. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize assigned values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { - var objValue = object[key], - srcValue = source[key], - stacked = stack.get(srcValue); +function textFunction(value) { + return function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + }; +} - if (stacked) { - assignMergeValue(object, key, stacked); - return; - } - var newValue = customizer - ? customizer(objValue, srcValue, (key + ''), object, source, stack) - : undefined; +var selection_text = function(value) { + return arguments.length + ? this.each(value == null + ? textRemove : (typeof value === "function" + ? textFunction + : textConstant)(value)) + : this.node().textContent; +}; - var isCommon = newValue === undefined; +function htmlRemove() { + this.innerHTML = ""; +} - if (isCommon) { - var isArr = isArray(srcValue), - isBuff = !isArr && isBuffer(srcValue), - isTyped = !isArr && !isBuff && isTypedArray(srcValue); +function htmlConstant(value) { + return function() { + this.innerHTML = value; + }; +} - newValue = srcValue; - if (isArr || isBuff || isTyped) { - if (isArray(objValue)) { - newValue = objValue; - } - else if (isArrayLikeObject(objValue)) { - newValue = copyArray(objValue); - } - else if (isBuff) { - isCommon = false; - newValue = cloneBuffer(srcValue, true); - } - else if (isTyped) { - isCommon = false; - newValue = cloneTypedArray(srcValue, true); - } - else { - newValue = []; - } - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - newValue = objValue; - if (isArguments(objValue)) { - newValue = toPlainObject(objValue); - } - else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { - newValue = initCloneObject(srcValue); - } - } - else { - isCommon = false; - } - } - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, newValue); - mergeFunc(newValue, srcValue, srcIndex, customizer, stack); - stack['delete'](srcValue); - } - assignMergeValue(object, key, newValue); - } +function htmlFunction(value) { + return function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + }; +} - /** - * The base implementation of `_.nth` which doesn't coerce arguments. - * - * @private - * @param {Array} array The array to query. - * @param {number} n The index of the element to return. - * @returns {*} Returns the nth element of `array`. - */ - function baseNth(array, n) { - var length = array.length; - if (!length) { - return; - } - n += n < 0 ? length : 0; - return isIndex(n, length) ? array[n] : undefined; - } +var selection_html = function(value) { + return arguments.length + ? this.each(value == null + ? htmlRemove : (typeof value === "function" + ? htmlFunction + : htmlConstant)(value)) + : this.node().innerHTML; +}; - /** - * The base implementation of `_.orderBy` without param guards. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {string[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseOrderBy(collection, iteratees, orders) { - var index = -1; - iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); +function raise() { + if (this.nextSibling) this.parentNode.appendChild(this); +} - var result = baseMap(collection, function(value, key, collection) { - var criteria = arrayMap(iteratees, function(iteratee) { - return iteratee(value); - }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; - }); +var selection_raise = function() { + return this.each(raise); +}; - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } +function lower() { + if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild); +} - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, paths) { - return basePickBy(object, paths, function(value, path) { - return hasIn(object, path); - }); - } +var selection_lower = function() { + return this.each(lower); +}; - /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. - */ - function basePickBy(object, paths, predicate) { - var index = -1, - length = paths.length, - result = {}; +var selection_append = function(name) { + var create = typeof name === "function" ? name : creator(name); + return this.select(function() { + return this.appendChild(create.apply(this, arguments)); + }); +}; - while (++index < length) { - var path = paths[index], - value = baseGet(object, path); +function constantNull() { + return null; +} - if (predicate(value, path)) { - baseSet(result, castPath(path, object), value); - } - } - return result; - } +var selection_insert = function(name, before) { + var create = typeof name === "function" ? name : creator(name), + select = before == null ? constantNull : typeof before === "function" ? before : selector(before); + return this.select(function() { + return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null); + }); +}; - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyDeep(path) { - return function(object) { - return baseGet(object, path); - }; - } +function remove() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); +} - /** - * The base implementation of `_.pullAllBy` without support for iteratee - * shorthands. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - */ - function basePullAll(array, values, iteratee, comparator) { - var indexOf = comparator ? baseIndexOfWith : baseIndexOf, - index = -1, - length = values.length, - seen = array; - - if (array === values) { - values = copyArray(values); - } - if (iteratee) { - seen = arrayMap(array, baseUnary(iteratee)); - } - while (++index < length) { - var fromIndex = 0, - value = values[index], - computed = iteratee ? iteratee(value) : value; - - while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { - if (seen !== array) { - splice.call(seen, fromIndex, 1); - } - splice.call(array, fromIndex, 1); - } - } - return array; - } +var selection_remove = function() { + return this.each(remove); +}; - /** - * The base implementation of `_.pullAt` without support for individual - * indexes or capturing the removed elements. - * - * @private - * @param {Array} array The array to modify. - * @param {number[]} indexes The indexes of elements to remove. - * @returns {Array} Returns `array`. - */ - function basePullAt(array, indexes) { - var length = array ? indexes.length : 0, - lastIndex = length - 1; - - while (length--) { - var index = indexes[length]; - if (length == lastIndex || index !== previous) { - var previous = index; - if (isIndex(index)) { - splice.call(array, index, 1); - } else { - baseUnset(array, index); - } - } - } - return array; - } +var selection_datum = function(value) { + return arguments.length + ? this.property("__data__", value) + : this.node().__data__; +}; - /** - * The base implementation of `_.random` without support for returning - * floating-point numbers. - * - * @private - * @param {number} lower The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the random number. - */ - function baseRandom(lower, upper) { - return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); - } +function dispatchEvent(node, type, params) { + var window = defaultView(node), + event = window.CustomEvent; - /** - * The base implementation of `_.range` and `_.rangeRight` which doesn't - * coerce arguments. - * - * @private - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @param {number} step The value to increment or decrement by. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the range of numbers. - */ - function baseRange(start, end, step, fromRight) { - var index = -1, - length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), - result = Array(length); - - while (length--) { - result[fromRight ? length : ++index] = start; - start += step; - } - return result; - } + if (typeof event === "function") { + event = new event(type, params); + } else { + event = window.document.createEvent("Event"); + if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail; + else event.initEvent(type, false, false); + } - /** - * The base implementation of `_.repeat` which doesn't coerce arguments. - * - * @private - * @param {string} string The string to repeat. - * @param {number} n The number of times to repeat the string. - * @returns {string} Returns the repeated string. - */ - function baseRepeat(string, n) { - var result = ''; - if (!string || n < 1 || n > MAX_SAFE_INTEGER) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = nativeFloor(n / 2); - if (n) { - string += string; - } - } while (n); + node.dispatchEvent(event); +} - return result; - } +function dispatchConstant(type, params) { + return function() { + return dispatchEvent(this, type, params); + }; +} - /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ - function baseRest(func, start) { - return setToString(overRest(func, start, identity), func + ''); - } +function dispatchFunction(type, params) { + return function() { + return dispatchEvent(this, type, params.apply(this, arguments)); + }; +} - /** - * The base implementation of `_.sample`. - * - * @private - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. - */ - function baseSample(collection) { - return arraySample(values(collection)); - } +var selection_dispatch = function(type, params) { + return this.each((typeof params === "function" + ? dispatchFunction + : dispatchConstant)(type, params)); +}; - /** - * The base implementation of `_.sampleSize` without param guards. - * - * @private - * @param {Array|Object} collection The collection to sample. - * @param {number} n The number of elements to sample. - * @returns {Array} Returns the random elements. - */ - function baseSampleSize(collection, n) { - var array = values(collection); - return shuffleSelf(array, baseClamp(n, 0, array.length)); - } +var root = [null]; - /** - * The base implementation of `_.set`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; - } - path = castPath(path, object); - - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; - - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; - - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } - } - assignValue(nested, key, newValue); - nested = nested[key]; - } - return object; - } +function Selection(groups, parents) { + this._groups = groups; + this._parents = parents; +} - /** - * The base implementation of `setData` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function(func, data) { - metaMap.set(func, data); - return func; - }; +function selection() { + return new Selection([[document.documentElement]], root); +} - /** - * The base implementation of `setToString` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var baseSetToString = !defineProperty ? identity : function(func, string) { - return defineProperty(func, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(string), - 'writable': true - }); - }; +Selection.prototype = selection.prototype = { + constructor: Selection, + select: selection_select, + selectAll: selection_selectAll, + filter: selection_filter, + data: selection_data, + enter: selection_enter, + exit: selection_exit, + merge: selection_merge, + order: selection_order, + sort: selection_sort, + call: selection_call, + nodes: selection_nodes, + node: selection_node, + size: selection_size, + empty: selection_empty, + each: selection_each, + attr: selection_attr, + style: selection_style, + property: selection_property, + classed: selection_classed, + text: selection_text, + html: selection_html, + raise: selection_raise, + lower: selection_lower, + append: selection_append, + insert: selection_insert, + remove: selection_remove, + datum: selection_datum, + on: selection_on, + dispatch: selection_dispatch +}; - /** - * The base implementation of `_.shuffle`. - * - * @private - * @param {Array|Object} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - */ - function baseShuffle(collection) { - return shuffleSelf(values(collection)); - } +var d3_select = function(selector) { + return typeof selector === "string" + ? new Selection([[document.querySelector(selector)]], [document.documentElement]) + : new Selection([[selector]], root); +}; - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; +var d3_selectAll = function(selector) { + return typeof selector === "string" + ? new Selection([document.querySelectorAll(selector)], [document.documentElement]) + : new Selection([selector == null ? [] : selector], root); +}; - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = end > length ? length : end; - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; +var touch = function(node, touches, identifier) { + if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches; - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; + for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) { + if ((touch = touches[i]).identifier === identifier) { + return point(node, touch); } + } - /** - * The base implementation of `_.some` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function baseSome(collection, predicate) { - var result; + return null; +}; - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } +var d3_touches = function(node, touches) { + if (touches == null) touches = sourceEvent().touches; - /** - * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which - * performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndex(array, value, retHighest) { - var low = 0, - high = array == null ? low : array.length; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; - - if (computed !== null && !isSymbol(computed) && - (retHighest ? (computed <= value) : (computed < value))) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return baseSortedIndexBy(array, value, identity, retHighest); - } + for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) { + points[i] = point(node, touches[i]); + } - /** - * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` - * which invokes `iteratee` for `value` and each element of `array` to compute - * their sort ranking. The iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The iteratee invoked per element. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - - var low = 0, - high = array == null ? 0 : array.length, - valIsNaN = value !== value, - valIsNull = value === null, - valIsSymbol = isSymbol(value), - valIsUndefined = value === undefined; - - while (low < high) { - var mid = nativeFloor((low + high) / 2), - computed = iteratee(array[mid]), - othIsDefined = computed !== undefined, - othIsNull = computed === null, - othIsReflexive = computed === computed, - othIsSymbol = isSymbol(computed); - - if (valIsNaN) { - var setLow = retHighest || othIsReflexive; - } else if (valIsUndefined) { - setLow = othIsReflexive && (retHighest || othIsDefined); - } else if (valIsNull) { - setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); - } else if (valIsSymbol) { - setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); - } else if (othIsNull || othIsSymbol) { - setLow = false; - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } + return points; +}; - /** - * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseSortedUniq(array, iteratee) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; +function nopropagation() { + event.stopImmediatePropagation(); +} - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; +var noevent = function() { + event.preventDefault(); + event.stopImmediatePropagation(); +}; - if (!index || !eq(computed, seen)) { - var seen = computed; - result[resIndex++] = value === 0 ? 0 : value; - } - } - return result; - } +var dragDisable = function(view) { + var root = view.document.documentElement, + selection$$1 = d3_select(view).on("dragstart.drag", noevent, true); + if ("onselectstart" in root) { + selection$$1.on("selectstart.drag", noevent, true); + } else { + root.__noselect = root.style.MozUserSelect; + root.style.MozUserSelect = "none"; + } +}; - /** - * The base implementation of `_.toNumber` which doesn't ensure correct - * conversions of binary, hexadecimal, or octal string values. - * - * @private - * @param {*} value The value to process. - * @returns {number} Returns the number. - */ - function baseToNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - return +value; - } +function yesdrag(view, noclick) { + var root = view.document.documentElement, + selection$$1 = d3_select(view).on("dragstart.drag", null); + if (noclick) { + selection$$1.on("click.drag", noevent, true); + setTimeout(function() { selection$$1.on("click.drag", null); }, 0); + } + if ("onselectstart" in root) { + selection$$1.on("selectstart.drag", null); + } else { + root.style.MozUserSelect = root.__noselect; + delete root.__noselect; + } +} - /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return arrayMap(value, baseToString) + ''; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } +var constant$2 = function(x) { + return function() { + return x; + }; +}; - /** - * The base implementation of `_.uniqBy` without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseUniq(array, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - length = array.length, - isCommon = true, - result = [], - seen = result; - - if (comparator) { - isCommon = false; - includes = arrayIncludesWith; - } - else if (length >= LARGE_ARRAY_SIZE) { - var set = iteratee ? null : createSet(array); - if (set) { - return setToArray(set); - } - isCommon = false; - includes = cacheHas; - seen = new SetCache; - } - else { - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (!includes(seen, computed, comparator)) { - if (seen !== result) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } +function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) { + this.target = target; + this.type = type; + this.subject = subject; + this.identifier = id; + this.active = active; + this.x = x; + this.y = y; + this.dx = dx; + this.dy = dy; + this._ = dispatch; +} - /** - * The base implementation of `_.unset`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The property path to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - */ - function baseUnset(object, path) { - path = castPath(path, object); - object = parent(object, path); - return object == null || delete object[toKey(last(path))]; - } +DragEvent.prototype.on = function() { + var value = this._.on.apply(this._, arguments); + return value === this._ ? this : value; +}; - /** - * The base implementation of `_.update`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to update. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseUpdate(object, path, updater, customizer) { - return baseSet(object, path, updater(baseGet(object, path)), customizer); - } +// Ignore right-click, since that should open the context menu. +function defaultFilter$1() { + return !event.button; +} - /** - * The base implementation of methods like `_.dropWhile` and `_.takeWhile` - * without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, - index = fromRight ? length : -1; +function defaultContainer() { + return this.parentNode; +} - while ((fromRight ? index-- : ++index < length) && - predicate(array[index], index, array)) {} +function defaultSubject(d) { + return d == null ? {x: event.x, y: event.y} : d; +} - return isDrop - ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) - : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); - } +function defaultTouchable() { + return "ontouchstart" in this; +} - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to perform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - return arrayReduce(actions, function(result, action) { - return action.func.apply(action.thisArg, arrayPush([result], action.args)); - }, result); +var drag = function() { + var filter = defaultFilter$1, + container = defaultContainer, + subject = defaultSubject, + touchable = defaultTouchable, + gestures = {}, + listeners = dispatch("start", "drag", "end"), + active = 0, + mousedownx, + mousedowny, + mousemoving, + touchending, + clickDistance2 = 0; + + function drag(selection) { + selection + .on("mousedown.drag", mousedowned) + .filter(touchable) + .on("touchstart.drag", touchstarted) + .on("touchmove.drag", touchmoved) + .on("touchend.drag touchcancel.drag", touchended) + .style("touch-action", "none") + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); + } + + function mousedowned() { + if (touchending || !filter.apply(this, arguments)) return; + var gesture = beforestart("mouse", container.apply(this, arguments), d3_mouse, this, arguments); + if (!gesture) return; + d3_select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true); + dragDisable(event.view); + nopropagation(); + mousemoving = false; + mousedownx = event.clientX; + mousedowny = event.clientY; + gesture("start"); + } + + function mousemoved() { + noevent(); + if (!mousemoving) { + var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny; + mousemoving = dx * dx + dy * dy > clickDistance2; } + gestures.mouse("drag"); + } - /** - * The base implementation of methods like `_.xor`, without support for - * iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of values. - */ - function baseXor(arrays, iteratee, comparator) { - var length = arrays.length; - if (length < 2) { - return length ? baseUniq(arrays[0]) : []; - } - var index = -1, - result = Array(length); + function mouseupped() { + d3_select(event.view).on("mousemove.drag mouseup.drag", null); + yesdrag(event.view, mousemoving); + noevent(); + gestures.mouse("end"); + } - while (++index < length) { - var array = arrays[index], - othIndex = -1; + function touchstarted() { + if (!filter.apply(this, arguments)) return; + var touches = event.changedTouches, + c = container.apply(this, arguments), + n = touches.length, i, gesture; - while (++othIndex < length) { - if (othIndex != index) { - result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); - } - } + for (i = 0; i < n; ++i) { + if (gesture = beforestart(touches[i].identifier, c, touch, this, arguments)) { + nopropagation(); + gesture("start"); } - return baseUniq(baseFlatten(result, 1), iteratee, comparator); } + } - /** - * This base implementation of `_.zipObject` which assigns values using `assignFunc`. - * - * @private - * @param {Array} props The property identifiers. - * @param {Array} values The property values. - * @param {Function} assignFunc The function to assign values. - * @returns {Object} Returns the new object. - */ - function baseZipObject(props, values, assignFunc) { - var index = -1, - length = props.length, - valsLength = values.length, - result = {}; - - while (++index < length) { - var value = index < valsLength ? values[index] : undefined; - assignFunc(result, props[index], value); + function touchmoved() { + var touches = event.changedTouches, + n = touches.length, i, gesture; + + for (i = 0; i < n; ++i) { + if (gesture = gestures[touches[i].identifier]) { + noevent(); + gesture("drag"); } - return result; } + } - /** - * Casts `value` to an empty array if it's not an array like object. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array|Object} Returns the cast array-like object. - */ - function castArrayLikeObject(value) { - return isArrayLikeObject(value) ? value : []; - } - - /** - * Casts `value` to `identity` if it's not a function. - * - * @private - * @param {*} value The value to inspect. - * @returns {Function} Returns cast function. - */ - function castFunction(value) { - return typeof value == 'function' ? value : identity; - } + function touchended() { + var touches = event.changedTouches, + n = touches.length, i, gesture; - /** - * Casts `value` to a path array if it's not one. - * - * @private - * @param {*} value The value to inspect. - * @param {Object} [object] The object to query keys on. - * @returns {Array} Returns the cast property path array. - */ - function castPath(value, object) { - if (isArray(value)) { - return value; + if (touchending) clearTimeout(touchending); + touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! + for (i = 0; i < n; ++i) { + if (gesture = gestures[touches[i].identifier]) { + nopropagation(); + gesture("end"); } - return isKey(value, object) ? [value] : stringToPath(toString(value)); } + } - /** - * A `baseRest` alias which can be replaced with `identity` by module - * replacement plugins. - * - * @private - * @type {Function} - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. - */ - var castRest = baseRest; + function beforestart(id, container, point, that, args) { + var p = point(container, id), s, dx, dy, + sublisteners = listeners.copy(); - /** - * Casts `array` to a slice if it's needed. - * - * @private - * @param {Array} array The array to inspect. - * @param {number} start The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the cast slice. - */ - function castSlice(array, start, end) { - var length = array.length; - end = end === undefined ? length : end; - return (!start && end >= length) ? array : baseSlice(array, start, end); - } + if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() { + if ((event.subject = s = subject.apply(that, args)) == null) return false; + dx = s.x - p[0] || 0; + dy = s.y - p[1] || 0; + return true; + })) return; - /** - * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). - * - * @private - * @param {number|Object} id The timer id or timeout object of the timer to clear. - */ - var clearTimeout = ctxClearTimeout || function(id) { - return root.clearTimeout(id); + return function gesture(type) { + var p0 = p, n; + switch (type) { + case "start": gestures[id] = gesture, n = active++; break; + case "end": delete gestures[id], --active; // nobreak + case "drag": p = point(container, id), n = active; break; + } + customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]); }; + } - /** - * Creates a clone of `buffer`. - * - * @private - * @param {Buffer} buffer The buffer to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Buffer} Returns the cloned buffer. - */ - function cloneBuffer(buffer, isDeep) { - if (isDeep) { - return buffer.slice(); - } - var length = buffer.length, - result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + drag.filter = function(_) { + return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter; + }; - buffer.copy(result); - return result; - } + drag.container = function(_) { + return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container; + }; - /** - * Creates a clone of `arrayBuffer`. - * - * @private - * @param {ArrayBuffer} arrayBuffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function cloneArrayBuffer(arrayBuffer) { - var result = new arrayBuffer.constructor(arrayBuffer.byteLength); - new Uint8Array(result).set(new Uint8Array(arrayBuffer)); - return result; - } + drag.subject = function(_) { + return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject; + }; - /** - * Creates a clone of `dataView`. - * - * @private - * @param {Object} dataView The data view to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned data view. - */ - function cloneDataView(dataView, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; - return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); - } + drag.touchable = function(_) { + return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$2(!!_), drag) : touchable; + }; - /** - * Creates a clone of `map`. - * - * @private - * @param {Object} map The map to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned map. - */ - function cloneMap(map, isDeep, cloneFunc) { - var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map); - return arrayReduce(array, addMapEntry, new map.constructor); - } + drag.on = function() { + var value = listeners.on.apply(listeners, arguments); + return value === listeners ? drag : value; + }; - /** - * Creates a clone of `regexp`. - * - * @private - * @param {Object} regexp The regexp to clone. - * @returns {Object} Returns the cloned regexp. - */ - function cloneRegExp(regexp) { - var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); - result.lastIndex = regexp.lastIndex; - return result; - } + drag.clickDistance = function(_) { + return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2); + }; - /** - * Creates a clone of `set`. - * - * @private - * @param {Object} set The set to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned set. - */ - function cloneSet(set, isDeep, cloneFunc) { - var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set); - return arrayReduce(array, addSetEntry, new set.constructor); - } + return drag; +}; - /** - * Creates a clone of the `symbol` object. - * - * @private - * @param {Object} symbol The symbol object to clone. - * @returns {Object} Returns the cloned symbol object. - */ - function cloneSymbol(symbol) { - return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; - } +var define = function(constructor, factory, prototype) { + constructor.prototype = factory.prototype = prototype; + prototype.constructor = constructor; +}; - /** - * Creates a clone of `typedArray`. - * - * @private - * @param {Object} typedArray The typed array to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned typed array. - */ - function cloneTypedArray(typedArray, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; - return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); - } +function extend(parent, definition) { + var prototype = Object.create(parent.prototype); + for (var key in definition) prototype[key] = definition[key]; + return prototype; +} - /** - * Compares values to sort them in ascending order. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function compareAscending(value, other) { - if (value !== other) { - var valIsDefined = value !== undefined, - valIsNull = value === null, - valIsReflexive = value === value, - valIsSymbol = isSymbol(value); - - var othIsDefined = other !== undefined, - othIsNull = other === null, - othIsReflexive = other === other, - othIsSymbol = isSymbol(other); - - if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || - (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || - (valIsNull && othIsDefined && othIsReflexive) || - (!valIsDefined && othIsReflexive) || - !valIsReflexive) { - return 1; - } - if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || - (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || - (othIsNull && valIsDefined && valIsReflexive) || - (!othIsDefined && valIsReflexive) || - !othIsReflexive) { - return -1; - } - } - return 0; - } +function Color() {} - /** - * Used by `_.orderBy` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, - * specify an order of "desc" for descending or "asc" for ascending sort order - * of corresponding values. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]|string[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = compareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - var order = orders[index]; - return result * (order == 'desc' ? -1 : 1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } +var darker = 0.7; +var brighter = 1 / darker; - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to prepend to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersLength = holders.length, - leftIndex = -1, - leftLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(leftLength + rangeLength), - isUncurried = !isCurried; - - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - } - while (rangeLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } +var reI = "\\s*([+-]?\\d+)\\s*"; +var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*"; +var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*"; +var reHex3 = /^#([0-9a-f]{3})$/; +var reHex6 = /^#([0-9a-f]{6})$/; +var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"); +var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"); +var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"); +var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"); +var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"); +var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$"); - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to append to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersIndex = -1, - holdersLength = holders.length, - rightIndex = -1, - rightLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(rangeLength + rightLength), - isUncurried = !isCurried; - - while (++argsIndex < rangeLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - } - return result; - } +var named = { + aliceblue: 0xf0f8ff, + antiquewhite: 0xfaebd7, + aqua: 0x00ffff, + aquamarine: 0x7fffd4, + azure: 0xf0ffff, + beige: 0xf5f5dc, + bisque: 0xffe4c4, + black: 0x000000, + blanchedalmond: 0xffebcd, + blue: 0x0000ff, + blueviolet: 0x8a2be2, + brown: 0xa52a2a, + burlywood: 0xdeb887, + cadetblue: 0x5f9ea0, + chartreuse: 0x7fff00, + chocolate: 0xd2691e, + coral: 0xff7f50, + cornflowerblue: 0x6495ed, + cornsilk: 0xfff8dc, + crimson: 0xdc143c, + cyan: 0x00ffff, + darkblue: 0x00008b, + darkcyan: 0x008b8b, + darkgoldenrod: 0xb8860b, + darkgray: 0xa9a9a9, + darkgreen: 0x006400, + darkgrey: 0xa9a9a9, + darkkhaki: 0xbdb76b, + darkmagenta: 0x8b008b, + darkolivegreen: 0x556b2f, + darkorange: 0xff8c00, + darkorchid: 0x9932cc, + darkred: 0x8b0000, + darksalmon: 0xe9967a, + darkseagreen: 0x8fbc8f, + darkslateblue: 0x483d8b, + darkslategray: 0x2f4f4f, + darkslategrey: 0x2f4f4f, + darkturquoise: 0x00ced1, + darkviolet: 0x9400d3, + deeppink: 0xff1493, + deepskyblue: 0x00bfff, + dimgray: 0x696969, + dimgrey: 0x696969, + dodgerblue: 0x1e90ff, + firebrick: 0xb22222, + floralwhite: 0xfffaf0, + forestgreen: 0x228b22, + fuchsia: 0xff00ff, + gainsboro: 0xdcdcdc, + ghostwhite: 0xf8f8ff, + gold: 0xffd700, + goldenrod: 0xdaa520, + gray: 0x808080, + green: 0x008000, + greenyellow: 0xadff2f, + grey: 0x808080, + honeydew: 0xf0fff0, + hotpink: 0xff69b4, + indianred: 0xcd5c5c, + indigo: 0x4b0082, + ivory: 0xfffff0, + khaki: 0xf0e68c, + lavender: 0xe6e6fa, + lavenderblush: 0xfff0f5, + lawngreen: 0x7cfc00, + lemonchiffon: 0xfffacd, + lightblue: 0xadd8e6, + lightcoral: 0xf08080, + lightcyan: 0xe0ffff, + lightgoldenrodyellow: 0xfafad2, + lightgray: 0xd3d3d3, + lightgreen: 0x90ee90, + lightgrey: 0xd3d3d3, + lightpink: 0xffb6c1, + lightsalmon: 0xffa07a, + lightseagreen: 0x20b2aa, + lightskyblue: 0x87cefa, + lightslategray: 0x778899, + lightslategrey: 0x778899, + lightsteelblue: 0xb0c4de, + lightyellow: 0xffffe0, + lime: 0x00ff00, + limegreen: 0x32cd32, + linen: 0xfaf0e6, + magenta: 0xff00ff, + maroon: 0x800000, + mediumaquamarine: 0x66cdaa, + mediumblue: 0x0000cd, + mediumorchid: 0xba55d3, + mediumpurple: 0x9370db, + mediumseagreen: 0x3cb371, + mediumslateblue: 0x7b68ee, + mediumspringgreen: 0x00fa9a, + mediumturquoise: 0x48d1cc, + mediumvioletred: 0xc71585, + midnightblue: 0x191970, + mintcream: 0xf5fffa, + mistyrose: 0xffe4e1, + moccasin: 0xffe4b5, + navajowhite: 0xffdead, + navy: 0x000080, + oldlace: 0xfdf5e6, + olive: 0x808000, + olivedrab: 0x6b8e23, + orange: 0xffa500, + orangered: 0xff4500, + orchid: 0xda70d6, + palegoldenrod: 0xeee8aa, + palegreen: 0x98fb98, + paleturquoise: 0xafeeee, + palevioletred: 0xdb7093, + papayawhip: 0xffefd5, + peachpuff: 0xffdab9, + peru: 0xcd853f, + pink: 0xffc0cb, + plum: 0xdda0dd, + powderblue: 0xb0e0e6, + purple: 0x800080, + rebeccapurple: 0x663399, + red: 0xff0000, + rosybrown: 0xbc8f8f, + royalblue: 0x4169e1, + saddlebrown: 0x8b4513, + salmon: 0xfa8072, + sandybrown: 0xf4a460, + seagreen: 0x2e8b57, + seashell: 0xfff5ee, + sienna: 0xa0522d, + silver: 0xc0c0c0, + skyblue: 0x87ceeb, + slateblue: 0x6a5acd, + slategray: 0x708090, + slategrey: 0x708090, + snow: 0xfffafa, + springgreen: 0x00ff7f, + steelblue: 0x4682b4, + tan: 0xd2b48c, + teal: 0x008080, + thistle: 0xd8bfd8, + tomato: 0xff6347, + turquoise: 0x40e0d0, + violet: 0xee82ee, + wheat: 0xf5deb3, + white: 0xffffff, + whitesmoke: 0xf5f5f5, + yellow: 0xffff00, + yellowgreen: 0x9acd32 +}; - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function copyArray(source, array) { - var index = -1, - length = source.length; +define(Color, color, { + displayable: function() { + return this.rgb().displayable(); + }, + toString: function() { + return this.rgb() + ""; + } +}); - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } +function color(format) { + var m; + format = (format + "").trim().toLowerCase(); + return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00 + : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000 + : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0) + : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%) + : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1) + : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1) + : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%) + : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1) + : named.hasOwnProperty(format) ? rgbn(named[format]) + : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) + : null; +} - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ - function copyObject(source, props, object, customizer) { - var isNew = !object; - object || (object = {}); +function rgbn(n) { + return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1); +} - var index = -1, - length = props.length; +function rgba(r, g, b, a) { + if (a <= 0) r = g = b = NaN; + return new Rgb(r, g, b, a); +} - while (++index < length) { - var key = props[index]; +function rgbConvert(o) { + if (!(o instanceof Color)) o = color(o); + if (!o) return new Rgb; + o = o.rgb(); + return new Rgb(o.r, o.g, o.b, o.opacity); +} - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; +function rgb(r, g, b, opacity) { + return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity); +} - if (newValue === undefined) { - newValue = source[key]; - } - if (isNew) { - baseAssignValue(object, key, newValue); - } else { - assignValue(object, key, newValue); - } - } - return object; - } +function Rgb(r, g, b, opacity) { + this.r = +r; + this.g = +g; + this.b = +b; + this.opacity = +opacity; +} - /** - * Copies own symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbols(source, object) { - return copyObject(source, getSymbols(source), object); - } +define(Rgb, rgb, extend(Color, { + brighter: function(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + darker: function(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + rgb: function() { + return this; + }, + displayable: function() { + return (0 <= this.r && this.r <= 255) + && (0 <= this.g && this.g <= 255) + && (0 <= this.b && this.b <= 255) + && (0 <= this.opacity && this.opacity <= 1); + }, + toString: function() { + var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a)); + return (a === 1 ? "rgb(" : "rgba(") + + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " + + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " + + Math.max(0, Math.min(255, Math.round(this.b) || 0)) + + (a === 1 ? ")" : ", " + a + ")"); + } +})); - /** - * Copies own and inherited symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbolsIn(source, object) { - return copyObject(source, getSymbolsIn(source), object); - } +function hsla(h, s, l, a) { + if (a <= 0) h = s = l = NaN; + else if (l <= 0 || l >= 1) h = s = NaN; + else if (s <= 0) h = NaN; + return new Hsl(h, s, l, a); +} - /** - * Creates a function like `_.groupBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} [initializer] The accumulator object initializer. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function(collection, iteratee) { - var func = isArray(collection) ? arrayAggregator : baseAggregator, - accumulator = initializer ? initializer() : {}; +function hslConvert(o) { + if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity); + if (!(o instanceof Color)) o = color(o); + if (!o) return new Hsl; + if (o instanceof Hsl) return o; + o = o.rgb(); + var r = o.r / 255, + g = o.g / 255, + b = o.b / 255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + h = NaN, + s = max - min, + l = (max + min) / 2; + if (s) { + if (r === max) h = (g - b) / s + (g < b) * 6; + else if (g === max) h = (b - r) / s + 2; + else h = (r - g) / s + 4; + s /= l < 0.5 ? max + min : 2 - max - min; + h *= 60; + } else { + s = l > 0 && l < 1 ? 0 : h; + } + return new Hsl(h, s, l, o.opacity); +} - return func(collection, setter, getIteratee(iteratee, 2), accumulator); - }; - } +function hsl(h, s, l, opacity) { + return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity); +} - /** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; - }); - } +function Hsl(h, s, l, opacity) { + this.h = +h; + this.s = +s; + this.l = +l; + this.opacity = +opacity; +} - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - if (collection == null) { - return collection; - } - if (!isArrayLike(collection)) { - return eachFunc(collection, iteratee); - } - var length = collection.length, - index = fromRight ? length : -1, - iterable = Object(collection); +define(Hsl, hsl, extend(Color, { + brighter: function(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + darker: function(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + rgb: function() { + var h = this.h % 360 + (this.h < 0) * 360, + s = isNaN(h) || isNaN(this.s) ? 0 : this.s, + l = this.l, + m2 = l + (l < 0.5 ? l : 1 - l) * s, + m1 = 2 * l - m2; + return new Rgb( + hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), + hsl2rgb(h, m1, m2), + hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), + this.opacity + ); + }, + displayable: function() { + return (0 <= this.s && this.s <= 1 || isNaN(this.s)) + && (0 <= this.l && this.l <= 1) + && (0 <= this.opacity && this.opacity <= 1); + } +})); - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } +/* From FvD 13.37, CSS Color Module Level 3 */ +function hsl2rgb(h, m1, m2) { + return (h < 60 ? m1 + (m2 - m1) * h / 60 + : h < 180 ? m2 + : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 + : m1) * 255; +} - /** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; - - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } +var deg2rad = Math.PI / 180; +var rad2deg = 180 / Math.PI; - /** - * Creates a function that wraps `func` to invoke it with the optional `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createBind(func, bitmask, thisArg) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, arguments); - } - return wrapper; - } +var Kn = 18; +var Xn = 0.950470; +var Yn = 1; +var Zn = 1.088830; +var t0 = 4 / 29; +var t1 = 6 / 29; +var t2 = 3 * t1 * t1; +var t3 = t1 * t1 * t1; - /** - * Creates a function like `_.lowerFirst`. - * - * @private - * @param {string} methodName The name of the `String` case method to use. - * @returns {Function} Returns the new case function. - */ - function createCaseFirst(methodName) { - return function(string) { - string = toString(string); +function labConvert(o) { + if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity); + if (o instanceof Hcl) { + var h = o.h * deg2rad; + return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity); + } + if (!(o instanceof Rgb)) o = rgbConvert(o); + var b = rgb2xyz(o.r), + a = rgb2xyz(o.g), + l = rgb2xyz(o.b), + x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn), + y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn), + z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn); + return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity); +} - var strSymbols = hasUnicode(string) - ? stringToArray(string) - : undefined; +function lab(l, a, b, opacity) { + return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity); +} - var chr = strSymbols - ? strSymbols[0] - : string.charAt(0); +function Lab(l, a, b, opacity) { + this.l = +l; + this.a = +a; + this.b = +b; + this.opacity = +opacity; +} - var trailing = strSymbols - ? castSlice(strSymbols, 1).join('') - : string.slice(1); +define(Lab, lab, extend(Color, { + brighter: function(k) { + return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity); + }, + darker: function(k) { + return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity); + }, + rgb: function() { + var y = (this.l + 16) / 116, + x = isNaN(this.a) ? y : y + this.a / 500, + z = isNaN(this.b) ? y : y - this.b / 200; + y = Yn * lab2xyz(y); + x = Xn * lab2xyz(x); + z = Zn * lab2xyz(z); + return new Rgb( + xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB + xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z), + xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z), + this.opacity + ); + } +})); - return chr[methodName]() + trailing; - }; - } +function xyz2lab(t) { + return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0; +} - /** - * Creates a function like `_.camelCase`. - * - * @private - * @param {Function} callback The function to combine each word. - * @returns {Function} Returns the new compounder function. - */ - function createCompounder(callback) { - return function(string) { - return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); - }; - } +function lab2xyz(t) { + return t > t1 ? t * t * t : t2 * (t - t0); +} - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtor(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. See - // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - switch (args.length) { - case 0: return new Ctor; - case 1: return new Ctor(args[0]); - case 2: return new Ctor(args[0], args[1]); - case 3: return new Ctor(args[0], args[1], args[2]); - case 4: return new Ctor(args[0], args[1], args[2], args[3]); - case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); - case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } +function xyz2rgb(x) { + return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055); +} - /** - * Creates a function that wraps `func` to enable currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {number} arity The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createCurry(func, bitmask, arity) { - var Ctor = createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length, - placeholder = getHolder(wrapper); - - while (index--) { - args[index] = arguments[index]; - } - var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) - ? [] - : replaceHolders(args, placeholder); - - length -= holders.length; - if (length < arity) { - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, undefined, - args, holders, undefined, undefined, arity - length); - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return apply(fn, this, args); - } - return wrapper; - } +function rgb2xyz(x) { + return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); +} - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} findIndexFunc The function to find the collection index. - * @returns {Function} Returns the new find function. - */ - function createFind(findIndexFunc) { - return function(collection, predicate, fromIndex) { - var iterable = Object(collection); - if (!isArrayLike(collection)) { - var iteratee = getIteratee(predicate, 3); - collection = keys(collection); - predicate = function(key) { return iteratee(iterable[key], key, iterable); }; - } - var index = findIndexFunc(collection, predicate, fromIndex); - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; - }; - } +function hclConvert(o) { + if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity); + if (!(o instanceof Lab)) o = labConvert(o); + var h = Math.atan2(o.b, o.a) * rad2deg; + return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity); +} - /** - * Creates a `_.flow` or `_.flowRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new flow function. - */ - function createFlow(fromRight) { - return flatRest(function(funcs) { - var length = funcs.length, - index = length, - prereq = LodashWrapper.prototype.thru; - - if (fromRight) { - funcs.reverse(); - } - while (index--) { - var func = funcs[index]; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (prereq && !wrapper && getFuncName(func) == 'wrapper') { - var wrapper = new LodashWrapper([], true); - } - } - index = wrapper ? index : length; - while (++index < length) { - func = funcs[index]; +function hcl(h, c, l, opacity) { + return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity); +} - var funcName = getFuncName(func), - data = funcName == 'wrapper' ? getData(func) : undefined; +function Hcl(h, c, l, opacity) { + this.h = +h; + this.c = +c; + this.l = +l; + this.opacity = +opacity; +} - if (data && isLaziable(data[0]) && - data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && - !data[4].length && data[9] == 1 - ) { - wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); - } else { - wrapper = (func.length == 1 && isLaziable(func)) - ? wrapper[funcName]() - : wrapper.thru(func); - } - } - return function() { - var args = arguments, - value = args[0]; +define(Hcl, hcl, extend(Color, { + brighter: function(k) { + return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity); + }, + darker: function(k) { + return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity); + }, + rgb: function() { + return labConvert(this).rgb(); + } +})); - if (wrapper && args.length == 1 && isArray(value)) { - return wrapper.plant(value).value(); - } - var index = 0, - result = length ? funcs[index].apply(this, args) : value; +var A = -0.14861; +var B = +1.78277; +var C = -0.29227; +var D = -0.90649; +var E = +1.97294; +var ED = E * D; +var EB = E * B; +var BC_DA = B * C - D * A; - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - }); - } +function cubehelixConvert(o) { + if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity); + if (!(o instanceof Rgb)) o = rgbConvert(o); + var r = o.r / 255, + g = o.g / 255, + b = o.b / 255, + l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB), + bl = b - l, + k = (E * (g - l) - C * bl) / D, + s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1 + h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN; + return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity); +} - /** - * Creates a function that wraps `func` to invoke it with optional `this` - * binding of `thisArg`, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided - * to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & WRAP_ARY_FLAG, - isBind = bitmask & WRAP_BIND_FLAG, - isBindKey = bitmask & WRAP_BIND_KEY_FLAG, - isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), - isFlip = bitmask & WRAP_FLIP_FLAG, - Ctor = isBindKey ? undefined : createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length; - - while (index--) { - args[index] = arguments[index]; - } - if (isCurried) { - var placeholder = getHolder(wrapper), - holdersCount = countHolders(args, placeholder); - } - if (partials) { - args = composeArgs(args, partials, holders, isCurried); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight, isCurried); - } - length -= holdersCount; - if (isCurried && length < arity) { - var newHolders = replaceHolders(args, placeholder); - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, thisArg, - args, newHolders, argPos, ary, arity - length - ); - } - var thisBinding = isBind ? thisArg : this, - fn = isBindKey ? thisBinding[func] : func; +function cubehelix(h, s, l, opacity) { + return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity); +} - length = args.length; - if (argPos) { - args = reorder(args, argPos); - } else if (isFlip && length > 1) { - args.reverse(); - } - if (isAry && ary < length) { - args.length = ary; - } - if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtor(fn); - } - return fn.apply(thisBinding, args); - } - return wrapper; - } +function Cubehelix(h, s, l, opacity) { + this.h = +h; + this.s = +s; + this.l = +l; + this.opacity = +opacity; +} - /** - * Creates a function like `_.invertBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} toIteratee The function to resolve iteratees. - * @returns {Function} Returns the new inverter function. - */ - function createInverter(setter, toIteratee) { - return function(object, iteratee) { - return baseInverter(object, setter, toIteratee(iteratee), {}); - }; - } +define(Cubehelix, cubehelix, extend(Color, { + brighter: function(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Cubehelix(this.h, this.s, this.l * k, this.opacity); + }, + darker: function(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Cubehelix(this.h, this.s, this.l * k, this.opacity); + }, + rgb: function() { + var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad, + l = +this.l, + a = isNaN(this.s) ? 0 : this.s * l * (1 - l), + cosh = Math.cos(h), + sinh = Math.sin(h); + return new Rgb( + 255 * (l + a * (A * cosh + B * sinh)), + 255 * (l + a * (C * cosh + D * sinh)), + 255 * (l + a * (E * cosh)), + this.opacity + ); + } +})); - /** - * Creates a function that performs a mathematical operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @param {number} [defaultValue] The value used for `undefined` arguments. - * @returns {Function} Returns the new mathematical operation function. - */ - function createMathOperation(operator, defaultValue) { - return function(value, other) { - var result; - if (value === undefined && other === undefined) { - return defaultValue; - } - if (value !== undefined) { - result = value; - } - if (other !== undefined) { - if (result === undefined) { - return other; - } - if (typeof value == 'string' || typeof other == 'string') { - value = baseToString(value); - other = baseToString(other); - } else { - value = baseToNumber(value); - other = baseToNumber(other); - } - result = operator(value, other); - } - return result; - }; - } +function basis(t1, v0, v1, v2, v3) { + var t2 = t1 * t1, t3 = t2 * t1; + return ((1 - 3 * t1 + 3 * t2 - t3) * v0 + + (4 - 6 * t2 + 3 * t3) * v1 + + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2 + + t3 * v3) / 6; +} - /** - * Creates a function like `_.over`. - * - * @private - * @param {Function} arrayFunc The function to iterate over iteratees. - * @returns {Function} Returns the new over function. - */ - function createOver(arrayFunc) { - return flatRest(function(iteratees) { - iteratees = arrayMap(iteratees, baseUnary(getIteratee())); - return baseRest(function(args) { - var thisArg = this; - return arrayFunc(iteratees, function(iteratee) { - return apply(iteratee, thisArg, args); - }); - }); - }); - } +var basis$1 = function(values) { + var n = values.length - 1; + return function(t) { + var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n), + v1 = values[i], + v2 = values[i + 1], + v0 = i > 0 ? values[i - 1] : 2 * v1 - v2, + v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1; + return basis((t - i / n) * n, v0, v1, v2, v3); + }; +}; - /** - * Creates the padding for `string` based on `length`. The `chars` string - * is truncated if the number of characters exceeds `length`. - * - * @private - * @param {number} length The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padding for `string`. - */ - function createPadding(length, chars) { - chars = chars === undefined ? ' ' : baseToString(chars); +var basisClosed = function(values) { + var n = values.length; + return function(t) { + var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n), + v0 = values[(i + n - 1) % n], + v1 = values[i % n], + v2 = values[(i + 1) % n], + v3 = values[(i + 2) % n]; + return basis((t - i / n) * n, v0, v1, v2, v3); + }; +}; - var charsLength = chars.length; - if (charsLength < 2) { - return charsLength ? baseRepeat(chars, length) : chars; - } - var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); - return hasUnicode(chars) - ? castSlice(stringToArray(result), 0, length).join('') - : result.slice(0, length); - } +var constant$3 = function(x) { + return function() { + return x; + }; +}; - /** - * Creates a function that wraps `func` to invoke it with the `this` binding - * of `thisArg` and `partials` prepended to the arguments it receives. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to - * the new function. - * @returns {Function} Returns the new wrapped function. - */ - function createPartial(func, bitmask, thisArg, partials) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); +function linear(a, d) { + return function(t) { + return a + t * d; + }; +} - function wrapper() { - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength), - fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; +function exponential(a, b, y) { + return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) { + return Math.pow(a + t * b, y); + }; +} - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - return apply(fn, isBind ? thisArg : this, args); - } - return wrapper; - } +function hue(a, b) { + var d = b - a; + return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$3(isNaN(a) ? b : a); +} - /** - * Creates a `_.range` or `_.rangeRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new range function. - */ - function createRange(fromRight) { - return function(start, end, step) { - if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { - end = step = undefined; - } - // Ensure the sign of `-0` is preserved. - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); - return baseRange(start, end, step, fromRight); - }; - } +function gamma(y) { + return (y = +y) === 1 ? nogamma : function(a, b) { + return b - a ? exponential(a, b, y) : constant$3(isNaN(a) ? b : a); + }; +} - /** - * Creates a function that performs a relational operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @returns {Function} Returns the new relational operation function. - */ - function createRelationalOperation(operator) { - return function(value, other) { - if (!(typeof value == 'string' && typeof other == 'string')) { - value = toNumber(value); - other = toNumber(other); - } - return operator(value, other); - }; - } +function nogamma(a, b) { + var d = b - a; + return d ? linear(a, d) : constant$3(isNaN(a) ? b : a); +} - /** - * Creates a function that wraps `func` to continue currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {Function} wrapFunc The function to create the `func` wrapper. - * @param {*} placeholder The placeholder value. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { - var isCurry = bitmask & WRAP_CURRY_FLAG, - newHolders = isCurry ? holders : undefined, - newHoldersRight = isCurry ? undefined : holders, - newPartials = isCurry ? partials : undefined, - newPartialsRight = isCurry ? undefined : partials; - - bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); - - if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { - bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); - } - var newData = [ - func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, - newHoldersRight, argPos, ary, arity - ]; +var d3_interpolateRgb = (function rgbGamma(y) { + var color$$1 = gamma(y); - var result = wrapFunc.apply(undefined, newData); - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return setWrapToString(result, func, bitmask); - } + function rgb$$1(start, end) { + var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r), + g = color$$1(start.g, end.g), + b = color$$1(start.b, end.b), + opacity = nogamma(start.opacity, end.opacity); + return function(t) { + start.r = r(t); + start.g = g(t); + start.b = b(t); + start.opacity = opacity(t); + return start + ""; + }; + } - /** - * Creates a function like `_.round`. - * - * @private - * @param {string} methodName The name of the `Math` method to use when rounding. - * @returns {Function} Returns the new round function. - */ - function createRound(methodName) { - var func = Math[methodName]; - return function(number, precision) { - number = toNumber(number); - precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); - if (precision) { - // Shift with exponential notation to avoid floating-point issues. - // See [MDN](https://mdn.io/round#Examples) for more details. - var pair = (toString(number) + 'e').split('e'), - value = func(pair[0] + 'e' + (+pair[1] + precision)); - - pair = (toString(value) + 'e').split('e'); - return +(pair[0] + 'e' + (+pair[1] - precision)); - } - return func(number); - }; - } + rgb$$1.gamma = rgbGamma; - /** - * Creates a set object of `values`. - * - * @private - * @param {Array} values The values to add to the set. - * @returns {Object} Returns the new set. - */ - var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { - return new Set(values); - }; + return rgb$$1; +})(1); - /** - * Creates a `_.toPairs` or `_.toPairsIn` function. - * - * @private - * @param {Function} keysFunc The function to get the keys of a given object. - * @returns {Function} Returns the new pairs function. - */ - function createToPairs(keysFunc) { - return function(object) { - var tag = getTag(object); - if (tag == mapTag) { - return mapToArray(object); - } - if (tag == setTag) { - return setToPairs(object); - } - return baseToPairs(object, keysFunc(object)); - }; +function rgbSpline(spline) { + return function(colors) { + var n = colors.length, + r = new Array(n), + g = new Array(n), + b = new Array(n), + i, color$$1; + for (i = 0; i < n; ++i) { + color$$1 = rgb(colors[i]); + r[i] = color$$1.r || 0; + g[i] = color$$1.g || 0; + b[i] = color$$1.b || 0; } + r = spline(r); + g = spline(g); + b = spline(b); + color$$1.opacity = 1; + return function(t) { + color$$1.r = r(t); + color$$1.g = g(t); + color$$1.b = b(t); + return color$$1 + ""; + }; + }; +} - /** - * Creates a function that either curries or invokes `func` with optional - * `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 64 - `_.partialRight` - * 128 - `_.rearg` - * 256 - `_.ary` - * 512 - `_.flip` - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to be partially applied. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); - partials = holders = undefined; - } - ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); - arity = arity === undefined ? arity : toInteger(arity); - length -= holders ? holders.length : 0; - - if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, - holdersRight = holders; +var rgbBasis = rgbSpline(basis$1); +var rgbBasisClosed = rgbSpline(basisClosed); - partials = holders = undefined; - } - var data = isBindKey ? undefined : getData(func); +var array$1 = function(a, b) { + var nb = b ? b.length : 0, + na = a ? Math.min(nb, a.length) : 0, + x = new Array(nb), + c = new Array(nb), + i; - var newData = [ - func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, - argPos, ary, arity - ]; + for (i = 0; i < na; ++i) x[i] = d3_interpolate(a[i], b[i]); + for (; i < nb; ++i) c[i] = b[i]; - if (data) { - mergeData(newData, data); - } - func = newData[0]; - bitmask = newData[1]; - thisArg = newData[2]; - partials = newData[3]; - holders = newData[4]; - arity = newData[9] = newData[9] === undefined - ? (isBindKey ? 0 : func.length) - : nativeMax(newData[9] - length, 0); - - if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { - bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); - } - if (!bitmask || bitmask == WRAP_BIND_FLAG) { - var result = createBind(func, bitmask, thisArg); - } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { - result = createCurry(func, bitmask, arity); - } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { - result = createPartial(func, bitmask, thisArg, partials); - } else { - result = createHybrid.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setWrapToString(setter(result, newData), func, bitmask); - } + return function(t) { + for (i = 0; i < na; ++i) c[i] = x[i](t); + return c; + }; +}; - /** - * Used by `_.defaults` to customize its `_.assignIn` use to assign properties - * of source objects to the destination object for all destination properties - * that resolve to `undefined`. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to assign. - * @param {Object} object The parent object of `objValue`. - * @returns {*} Returns the value to assign. - */ - function customDefaultsAssignIn(objValue, srcValue, key, object) { - if (objValue === undefined || - (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { - return srcValue; - } - return objValue; - } +var date = function(a, b) { + var d = new Date; + return a = +a, b -= a, function(t) { + return d.setTime(a + b * t), d; + }; +}; - /** - * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source - * objects into destination objects that are passed thru. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to merge. - * @param {Object} object The parent object of `objValue`. - * @param {Object} source The parent object of `srcValue`. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - * @returns {*} Returns the value to assign. - */ - function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { - if (isObject(objValue) && isObject(srcValue)) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, objValue); - baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); - stack['delete'](srcValue); - } - return objValue; - } +var d3_interpolateNumber = function(a, b) { + return a = +a, b -= a, function(t) { + return a + b * t; + }; +}; - /** - * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain - * objects. - * - * @private - * @param {*} value The value to inspect. - * @param {string} key The key of the property to inspect. - * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. - */ - function customOmitClone(value) { - return isPlainObject(value) ? undefined : value; - } +var object = function(a, b) { + var i = {}, + c = {}, + k; - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `array` and `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - arrLength = array.length, - othLength = other.length; + if (a === null || typeof a !== "object") a = {}; + if (b === null || typeof b !== "object") b = {}; - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(array); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, - result = true, - seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; - - stack.set(array, other); - stack.set(other, array); - - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, arrValue, index, other, array, stack) - : customizer(arrValue, othValue, index, array, other, stack); - } - if (compared !== undefined) { - if (compared) { - continue; - } - result = false; - break; - } - // Recursively compare arrays (susceptible to call stack limits). - if (seen) { - if (!arraySome(other, function(othValue, othIndex) { - if (!cacheHas(seen, othIndex) && - (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { - return seen.push(othIndex); - } - })) { - result = false; - break; - } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, bitmask, customizer, stack) - )) { - result = false; - break; - } - } - stack['delete'](array); - stack['delete'](other); - return result; + for (k in b) { + if (k in a) { + i[k] = d3_interpolate(a[k], b[k]); + } else { + c[k] = b[k]; } + } - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { - switch (tag) { - case dataViewTag: - if ((object.byteLength != other.byteLength) || - (object.byteOffset != other.byteOffset)) { - return false; - } - object = object.buffer; - other = other.buffer; - - case arrayBufferTag: - if ((object.byteLength != other.byteLength) || - !equalFunc(new Uint8Array(object), new Uint8Array(other))) { - return false; - } - return true; - - case boolTag: - case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); - - case errorTag: - return object.name == other.name && object.message == other.message; + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; +}; - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. - return object == (other + ''); +var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; +var reB = new RegExp(reA.source, "g"); - case mapTag: - var convert = mapToArray; +function zero(b) { + return function() { + return b; + }; +} - case setTag: - var isPartial = bitmask & COMPARE_PARTIAL_FLAG; - convert || (convert = setToArray); +function one(b) { + return function(t) { + return b(t) + ""; + }; +} - if (object.size != other.size && !isPartial) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked) { - return stacked == other; - } - bitmask |= COMPARE_UNORDERED_FLAG; +var interpolateString = function(a, b) { + var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b + am, // current match in a + bm, // current match in b + bs, // string preceding current number in b, if any + i = -1, // index in s + s = [], // string constants and placeholders + q = []; // number interpolators - // Recursively compare objects (susceptible to call stack limits). - stack.set(object, other); - var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); - stack['delete'](object); - return result; + // Coerce inputs to strings. + a = a + "", b = b + ""; - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object) == symbolValueOf.call(other); - } - } - return false; + // Interpolate pairs of numbers in a & b. + while ((am = reA.exec(a)) + && (bm = reB.exec(b))) { + if ((bs = bm.index) > bi) { // a string precedes the next number in b + bs = b.slice(bi, bs); + if (s[i]) s[i] += bs; // coalesce with previous string + else s[++i] = bs; + } + if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match + if (s[i]) s[i] += bm; // coalesce with previous string + else s[++i] = bm; + } else { // interpolate non-matching numbers + s[++i] = null; + q.push({i: i, x: d3_interpolateNumber(am, bm)}); } + bi = reB.lastIndex; + } - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - objProps = getAllKeys(object), - objLength = objProps.length, - othProps = getAllKeys(other), - othLength = othProps.length; - - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object, other); - stack.set(other, object); - - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, objValue, key, other, object, stack) - : customizer(objValue, othValue, key, object, other, stack); - } - // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) - : compared - )) { - result = false; - break; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (result && !skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; - } - } - stack['delete'](object); - stack['delete'](other); - return result; - } + // Add remains of b. + if (bi < b.length) { + bs = b.slice(bi); + if (s[i]) s[i] += bs; // coalesce with previous string + else s[++i] = bs; + } - /** - * A specialized version of `baseRest` which flattens the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. - */ - function flatRest(func) { - return setToString(overRest(func, undefined, flatten), func + ''); - } + // Special optimization for only a single match. + // Otherwise, interpolate each of the numbers and rejoin the string. + return s.length < 2 ? (q[0] + ? one(q[0].x) + : zero(b)) + : (b = q.length, function(t) { + for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }); +}; - /** - * Creates an array of own enumerable property names and symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeys(object) { - return baseGetAllKeys(object, keys, getSymbols); - } +var d3_interpolate = function(a, b) { + var t = typeof b, c; + return b == null || t === "boolean" ? constant$3(b) + : (t === "number" ? d3_interpolateNumber + : t === "string" ? ((c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString) + : b instanceof color ? d3_interpolateRgb + : b instanceof Date ? date + : Array.isArray(b) ? array$1 + : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object + : d3_interpolateNumber)(a, b); +}; - /** - * Creates an array of own and inherited enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeysIn(object) { - return baseGetAllKeys(object, keysIn, getSymbolsIn); - } +var interpolateRound = function(a, b) { + return a = +a, b -= a, function(t) { + return Math.round(a + b * t); + }; +}; - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function(func) { - return metaMap.get(func); - }; +var degrees = 180 / Math.PI; - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - function getFuncName(func) { - var result = (func.name + ''), - array = realNames[result], - length = hasOwnProperty.call(realNames, result) ? array.length : 0; +var identity$2 = { + translateX: 0, + translateY: 0, + rotate: 0, + skewX: 0, + scaleX: 1, + scaleY: 1 +}; - while (length--) { - var data = array[length], - otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - return result; - } +var decompose = function(a, b, c, d, e, f) { + var scaleX, scaleY, skewX; + if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX; + if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX; + if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY; + if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX; + return { + translateX: e, + translateY: f, + rotate: Math.atan2(b, a) * degrees, + skewX: Math.atan(skewX) * degrees, + scaleX: scaleX, + scaleY: scaleY + }; +}; - /** - * Gets the argument placeholder value for `func`. - * - * @private - * @param {Function} func The function to inspect. - * @returns {*} Returns the placeholder value. - */ - function getHolder(func) { - var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; - return object.placeholder; - } +var cssNode; +var cssRoot; +var cssView; +var svgNode; - /** - * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, - * this function returns the custom method, otherwise it returns `baseIteratee`. - * If arguments are provided, the chosen function is invoked with them and - * its result is returned. - * - * @private - * @param {*} [value] The value to convert to an iteratee. - * @param {number} [arity] The arity of the created iteratee. - * @returns {Function} Returns the chosen function or its result. - */ - function getIteratee() { - var result = lodash.iteratee || iteratee; - result = result === iteratee ? baseIteratee : result; - return arguments.length ? result(arguments[0], arguments[1]) : result; - } +function parseCss(value) { + if (value === "none") return identity$2; + if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView; + cssNode.style.transform = value; + value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform"); + cssRoot.removeChild(cssNode); + value = value.slice(7, -1).split(","); + return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]); +} - /** - * Gets the data for `map`. - * - * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. - */ - function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; - } +function parseSvg(value) { + if (value == null) return identity$2; + if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g"); + svgNode.setAttribute("transform", value); + if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2; + value = value.matrix; + return decompose(value.a, value.b, value.c, value.d, value.e, value.f); +} - /** - * Gets the property names, values, and compare flags of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the match data of `object`. - */ - function getMatchData(object) { - var result = keys(object), - length = result.length; +function interpolateTransform(parse, pxComma, pxParen, degParen) { - while (length--) { - var key = result[length], - value = object[key]; + function pop(s) { + return s.length ? s.pop() + " " : ""; + } - result[length] = [key, value, isStrictComparable(value)]; - } - return result; + function translate(xa, ya, xb, yb, s, q) { + if (xa !== xb || ya !== yb) { + var i = s.push("translate(", null, pxComma, null, pxParen); + q.push({i: i - 4, x: d3_interpolateNumber(xa, xb)}, {i: i - 2, x: d3_interpolateNumber(ya, yb)}); + } else if (xb || yb) { + s.push("translate(" + xb + pxComma + yb + pxParen); } + } - /** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; + function rotate(a, b, s, q) { + if (a !== b) { + if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path + q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: d3_interpolateNumber(a, b)}); + } else if (b) { + s.push(pop(s) + "rotate(" + b + degParen); } + } - /** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. - */ - function getRawTag(value) { - var isOwn = hasOwnProperty.call(value, symToStringTag), - tag = value[symToStringTag]; + function skewX(a, b, s, q) { + if (a !== b) { + q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: d3_interpolateNumber(a, b)}); + } else if (b) { + s.push(pop(s) + "skewX(" + b + degParen); + } + } - try { - value[symToStringTag] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; + function scale(xa, ya, xb, yb, s, q) { + if (xa !== xb || ya !== yb) { + var i = s.push(pop(s) + "scale(", null, ",", null, ")"); + q.push({i: i - 4, x: d3_interpolateNumber(xa, xb)}, {i: i - 2, x: d3_interpolateNumber(ya, yb)}); + } else if (xb !== 1 || yb !== 1) { + s.push(pop(s) + "scale(" + xb + "," + yb + ")"); } + } - /** - * Creates an array of the own enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbols = !nativeGetSymbols ? stubArray : function(object) { - if (object == null) { - return []; - } - object = Object(object); - return arrayFilter(nativeGetSymbols(object), function(symbol) { - return propertyIsEnumerable.call(object, symbol); - }); + return function(a, b) { + var s = [], // string constants and placeholders + q = []; // number interpolators + a = parse(a), b = parse(b); + translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q); + rotate(a.rotate, b.rotate, s, q); + skewX(a.skewX, b.skewX, s, q); + scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q); + a = b = null; // gc + return function(t) { + var i = -1, n = q.length, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); }; + }; +} - /** - * Creates an array of the own and inherited enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { - var result = []; - while (object) { - arrayPush(result, getSymbols(object)); - object = getPrototype(object); - } - return result; - }; +var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)"); +var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")"); - /** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - var getTag = baseGetTag; - - // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. - if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = baseGetTag(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : ''; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; - } +var rho = Math.SQRT2; +var rho2 = 2; +var rho4 = 4; +var epsilon2 = 1e-12; - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} transforms The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, - length = transforms.length; +function cosh(x) { + return ((x = Math.exp(x)) + 1 / x) / 2; +} - while (++index < length) { - var data = transforms[index], - size = data.size; +function sinh(x) { + return ((x = Math.exp(x)) - 1 / x) / 2; +} - switch (data.type) { - case 'drop': start += size; break; - case 'dropRight': end -= size; break; - case 'take': end = nativeMin(end, start + size); break; - case 'takeRight': start = nativeMax(start, end - size); break; - } - } - return { 'start': start, 'end': end }; - } +function tanh(x) { + return ((x = Math.exp(2 * x)) - 1) / (x + 1); +} - /** - * Extracts wrapper details from the `source` body comment. - * - * @private - * @param {string} source The source to inspect. - * @returns {Array} Returns the wrapper details. - */ - function getWrapDetails(source) { - var match = source.match(reWrapDetails); - return match ? match[1].split(reSplitDetails) : []; - } +// p0 = [ux0, uy0, w0] +// p1 = [ux1, uy1, w1] +var interpolateZoom = function(p0, p1) { + var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], + ux1 = p1[0], uy1 = p1[1], w1 = p1[2], + dx = ux1 - ux0, + dy = uy1 - uy0, + d2 = dx * dx + dy * dy, + i, + S; - /** - * Checks if `path` exists on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @param {Function} hasFunc The function to check properties. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - */ - function hasPath(object, path, hasFunc) { - path = castPath(path, object); + // Special case for u0 ≅ u1. + if (d2 < epsilon2) { + S = Math.log(w1 / w0) / rho; + i = function(t) { + return [ + ux0 + t * dx, + uy0 + t * dy, + w0 * Math.exp(rho * t * S) + ]; + }; + } - var index = -1, - length = path.length, - result = false; + // General case. + else { + var d1 = Math.sqrt(d2), + b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1), + b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1), + r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), + r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1); + S = (r1 - r0) / rho; + i = function(t) { + var s = t * S, + coshr0 = cosh(r0), + u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0)); + return [ + ux0 + u * dx, + uy0 + u * dy, + w0 * coshr0 / cosh(rho * s + r0) + ]; + }; + } - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; - } - object = object[key]; - } - if (result || ++index != length) { - return result; - } - length = object == null ? 0 : object.length; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); - } + i.duration = S * 1000; - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, - result = array.constructor(length); - - // Add properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } + return i; +}; - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - return (typeof object.constructor == 'function' && !isPrototype(object)) - ? baseCreate(getPrototype(object)) - : {}; - } +function hsl$1(hue$$1) { + return function(start, end) { + var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h), + s = nogamma(start.s, end.s), + l = nogamma(start.l, end.l), + opacity = nogamma(start.opacity, end.opacity); + return function(t) { + start.h = h(t); + start.s = s(t); + start.l = l(t); + start.opacity = opacity(t); + return start + ""; + }; + } +} - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, cloneFunc, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return cloneArrayBuffer(object); +var hsl$2 = hsl$1(hue); +var hslLong = hsl$1(nogamma); - case boolTag: - case dateTag: - return new Ctor(+object); +function lab$1(start, end) { + var l = nogamma((start = lab(start)).l, (end = lab(end)).l), + a = nogamma(start.a, end.a), + b = nogamma(start.b, end.b), + opacity = nogamma(start.opacity, end.opacity); + return function(t) { + start.l = l(t); + start.a = a(t); + start.b = b(t); + start.opacity = opacity(t); + return start + ""; + }; +} - case dataViewTag: - return cloneDataView(object, isDeep); +function hcl$1(hue$$1) { + return function(start, end) { + var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h), + c = nogamma(start.c, end.c), + l = nogamma(start.l, end.l), + opacity = nogamma(start.opacity, end.opacity); + return function(t) { + start.h = h(t); + start.c = c(t); + start.l = l(t); + start.opacity = opacity(t); + return start + ""; + }; + } +} - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - return cloneTypedArray(object, isDeep); +var hcl$2 = hcl$1(hue); +var hclLong = hcl$1(nogamma); - case mapTag: - return cloneMap(object, isDeep, cloneFunc); +function cubehelix$1(hue$$1) { + return (function cubehelixGamma(y) { + y = +y; - case numberTag: - case stringTag: - return new Ctor(object); + function cubehelix$$1(start, end) { + var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h), + s = nogamma(start.s, end.s), + l = nogamma(start.l, end.l), + opacity = nogamma(start.opacity, end.opacity); + return function(t) { + start.h = h(t); + start.s = s(t); + start.l = l(Math.pow(t, y)); + start.opacity = opacity(t); + return start + ""; + }; + } - case regexpTag: - return cloneRegExp(object); + cubehelix$$1.gamma = cubehelixGamma; - case setTag: - return cloneSet(object, isDeep, cloneFunc); + return cubehelix$$1; + })(1); +} - case symbolTag: - return cloneSymbol(object); - } - } +var cubehelix$2 = cubehelix$1(hue); +var cubehelixLong = cubehelix$1(nogamma); - /** - * Inserts wrapper `details` in a comment at the top of the `source` body. - * - * @private - * @param {string} source The source to modify. - * @returns {Array} details The details to insert. - * @returns {string} Returns the modified source. - */ - function insertWrapDetails(source, details) { - var length = details.length; - if (!length) { - return source; - } - var lastIndex = length - 1; - details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; - details = details.join(length > 2 ? ', ' : ' '); - return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); - } +var d3_quantize = function(interpolator, n) { + var samples = new Array(n); + for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1)); + return samples; +}; - /** - * Checks if `value` is a flattenable `arguments` object or array. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ - function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); - } +var frame = 0; +var timeout = 0; +var interval = 0; +var pokeDelay = 1000; +var taskHead; +var taskTail; +var clockLast = 0; +var clockNow = 0; +var clockSkew = 0; +var clock = typeof performance === "object" && performance.now ? performance : Date; +var setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); }; - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - length = length == null ? MAX_SAFE_INTEGER : length; - return !!length && - (typeof value == 'number' || reIsUint.test(value)) && - (value > -1 && value % 1 == 0 && value < length); - } +function now() { + return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew); +} - /** - * Checks if the given arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); - } - return false; - } +function clearNow() { + clockNow = 0; +} - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - if (isArray(value)) { - return false; - } - var type = typeof value; - if (type == 'number' || type == 'symbol' || type == 'boolean' || - value == null || isSymbol(value)) { - return true; - } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); - } +function Timer() { + this._call = + this._time = + this._next = null; +} - /** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ - function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); +Timer.prototype = timer.prototype = { + constructor: Timer, + restart: function(callback, delay, time) { + if (typeof callback !== "function") throw new TypeError("callback is not a function"); + time = (time == null ? now() : +time) + (delay == null ? 0 : +delay); + if (!this._next && taskTail !== this) { + if (taskTail) taskTail._next = this; + else taskHead = this; + taskTail = this; } - - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, - * else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func), - other = lodash[funcName]; - - if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { - return false; - } - if (func === other) { - return true; - } - var data = getData(other); - return !!data && func === data[0]; + this._call = callback; + this._time = time; + sleep(); + }, + stop: function() { + if (this._call) { + this._call = null; + this._time = Infinity; + sleep(); } + } +}; - /** - * Checks if `func` has its source masked. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. - */ - function isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); - } +function timer(callback, delay, time) { + var t = new Timer; + t.restart(callback, delay, time); + return t; +} - /** - * Checks if `func` is capable of being masked. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `func` is maskable, else `false`. - */ - var isMaskable = coreJsData ? isFunction : stubFalse; +function timerFlush() { + now(); // Get the current time, if not already set. + ++frame; // Pretend we’ve set an alarm, if we haven’t already. + var t = taskHead, e; + while (t) { + if ((e = clockNow - t._time) >= 0) t._call.call(null, e); + t = t._next; + } + --frame; +} - /** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ - function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; +function wake() { + clockNow = (clockLast = clock.now()) + clockSkew; + frame = timeout = 0; + try { + timerFlush(); + } finally { + frame = 0; + nap(); + clockNow = 0; + } +} - return value === proto; - } +function poke() { + var now = clock.now(), delay = now - clockLast; + if (delay > pokeDelay) clockSkew -= delay, clockLast = now; +} - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); +function nap() { + var t0, t1 = taskHead, t2, time = Infinity; + while (t1) { + if (t1._call) { + if (time > t1._time) time = t1._time; + t0 = t1, t1 = t1._next; + } else { + t2 = t1._next, t1._next = null; + t1 = t0 ? t0._next = t2 : taskHead = t2; } + } + taskTail = t0; + sleep(time); +} - /** - * A specialized version of `matchesProperty` for source values suitable - * for strict equality comparisons, i.e. `===`. - * - * @private - * @param {string} key The key of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function matchesStrictComparable(key, srcValue) { - return function(object) { - if (object == null) { - return false; - } - return object[key] === srcValue && - (srcValue !== undefined || (key in Object(object))); - }; - } +function sleep(time) { + if (frame) return; // Soonest alarm already set, or will be. + if (timeout) timeout = clearTimeout(timeout); + var delay = time - clockNow; // Strictly less than if we recomputed clockNow. + if (delay > 24) { + if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew); + if (interval) interval = clearInterval(interval); + } else { + if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay); + frame = 1, setFrame(wake); + } +} - /** - * A specialized version of `_.memoize` which clears the memoized function's - * cache when it exceeds `MAX_MEMOIZE_SIZE`. - * - * @private - * @param {Function} func The function to have its output memoized. - * @returns {Function} Returns the new memoized function. - */ - function memoizeCapped(func) { - var result = memoize(func, function(key) { - if (cache.size === MAX_MEMOIZE_SIZE) { - cache.clear(); - } - return key; - }); +var d3_timeout = function(callback, delay, time) { + var t = new Timer; + delay = delay == null ? 0 : +delay; + t.restart(function(elapsed) { + t.stop(); + callback(elapsed + delay); + }, delay, time); + return t; +}; - var cache = result.cache; - return result; - } +var interval$1 = function(callback, delay, time) { + var t = new Timer, total = delay; + if (delay == null) return t.restart(callback, delay, time), t; + delay = +delay, time = time == null ? now() : +time; + t.restart(function tick(elapsed) { + elapsed += total; + t.restart(tick, total += delay, time); + callback(elapsed); + }, delay, time); + return t; +}; - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers used to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and - * `_.rearg` modify function arguments, making the order in which they are - * executed important, preventing the merging of metadata. However, we make - * an exception for a safe combined case where curried functions have `_.ary` - * and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], - srcBitmask = source[1], - newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); - - var isCombo = - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || - ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); - - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & WRAP_BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : value; - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = value; - } - // Use source `ary` if it's smaller. - if (srcBitmask & WRAP_ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; +var emptyOn = dispatch("start", "end", "interrupt"); +var emptyTween = []; - return data; - } +var CREATED = 0; +var SCHEDULED = 1; +var STARTING = 2; +var STARTED = 3; +var RUNNING = 4; +var ENDING = 5; +var ENDED = 6; - /** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; - } +var schedule = function(node, name, id, index, group, timing) { + var schedules = node.__transition; + if (!schedules) node.__transition = {}; + else if (id in schedules) return; + create(node, id, { + name: name, + index: index, // For context during callback. + group: group, // For context during callback. + on: emptyOn, + tween: emptyTween, + time: timing.time, + delay: timing.delay, + duration: timing.duration, + ease: timing.ease, + timer: null, + state: CREATED + }); +}; - /** - * Converts `value` to a string using `Object.prototype.toString`. - * - * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - */ - function objectToString(value) { - return nativeObjectToString.call(value); - } +function init(node, id) { + var schedule = node.__transition; + if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late"); + return schedule; +} - /** - * A specialized version of `baseRest` which transforms the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @param {Function} transform The rest array transform. - * @returns {Function} Returns the new function. - */ - function overRest(func, start, transform) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); +function set$1(node, id) { + var schedule = node.__transition; + if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late"); + return schedule; +} - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = transform(array); - return apply(func, this, otherArgs); - }; - } +function get$1(node, id) { + var schedule = node.__transition; + if (!schedule || !(schedule = schedule[id])) throw new Error("too late"); + return schedule; +} - /** - * Gets the parent value at `path` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path to get the parent value of. - * @returns {*} Returns the parent value. - */ - function parent(object, path) { - return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); - } +function create(node, id, self) { + var schedules = node.__transition, + tween; - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, - length = nativeMin(indexes.length, arrLength), - oldArray = copyArray(array); - - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } + // Initialize the self timer when the transition is created. + // Note the actual delay is not known until the first callback! + schedules[id] = self; + self.timer = timer(schedule, 0, self.time); - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity - * function to avoid garbage collection pauses in V8. See - * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = shortOut(baseSetData); + function schedule(elapsed) { + self.state = SCHEDULED; + self.timer.restart(start, self.delay, self.time); - /** - * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @returns {number|Object} Returns the timer id or timeout object. - */ - var setTimeout = ctxSetTimeout || function(func, wait) { - return root.setTimeout(func, wait); - }; + // If the elapsed delay is less than our first sleep, start immediately. + if (self.delay <= elapsed) start(elapsed - self.delay); + } - /** - * Sets the `toString` method of `func` to return `string`. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var setToString = shortOut(baseSetToString); + function start(elapsed) { + var i, j, n, o; - /** - * Sets the `toString` method of `wrapper` to mimic the source of `reference` - * with wrapper details in a comment at the top of the source body. - * - * @private - * @param {Function} wrapper The function to modify. - * @param {Function} reference The reference function. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Function} Returns `wrapper`. - */ - function setWrapToString(wrapper, reference, bitmask) { - var source = (reference + ''); - return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); - } + // If the state is not SCHEDULED, then we previously errored on start. + if (self.state !== SCHEDULED) return stop(); - /** - * Creates a function that'll short out and invoke `identity` instead - * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` - * milliseconds. - * - * @private - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new shortable function. - */ - function shortOut(func) { - var count = 0, - lastCalled = 0; + for (i in schedules) { + o = schedules[i]; + if (o.name !== self.name) continue; - return function() { - var stamp = nativeNow(), - remaining = HOT_SPAN - (stamp - lastCalled); + // While this element already has a starting transition during this frame, + // defer starting an interrupting transition until that transition has a + // chance to tick (and possibly end); see d3/d3-transition#54! + if (o.state === STARTED) return d3_timeout(start); - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return arguments[0]; - } - } else { - count = 0; - } - return func.apply(undefined, arguments); - }; - } + // Interrupt the active transition, if any. + // Dispatch the interrupt event. + if (o.state === RUNNING) { + o.state = ENDED; + o.timer.stop(); + o.on.call("interrupt", node, node.__data__, o.index, o.group); + delete schedules[i]; + } - /** - * A specialized version of `_.shuffle` which mutates and sets the size of `array`. - * - * @private - * @param {Array} array The array to shuffle. - * @param {number} [size=array.length] The size of `array`. - * @returns {Array} Returns `array`. - */ - function shuffleSelf(array, size) { - var index = -1, - length = array.length, - lastIndex = length - 1; - - size = size === undefined ? length : size; - while (++index < size) { - var rand = baseRandom(index, lastIndex), - value = array[rand]; - - array[rand] = array[index]; - array[index] = value; + // Cancel any pre-empted transitions. No interrupt event is dispatched + // because the cancelled transitions never started. Note that this also + // removes this transition from the pending list! + else if (+i < id) { + o.state = ENDED; + o.timer.stop(); + delete schedules[i]; } - array.length = size; - return array; } - /** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ - var stringToPath = memoizeCapped(function(string) { - var result = []; - if (reLeadingDot.test(string)) { - result.push(''); + // Defer the first tick to end of the current frame; see d3/d3#1576. + // Note the transition may be canceled after start and before the first tick! + // Note this must be scheduled before the start event; see d3/d3-transition#16! + // Assuming this is successful, subsequent callbacks go straight to tick. + d3_timeout(function() { + if (self.state === STARTED) { + self.state = RUNNING; + self.timer.restart(tick, self.delay, self.time); + tick(elapsed); } - string.replace(rePropName, function(match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; }); - /** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ - function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } + // Dispatch the start event. + // Note this must be done before the tween are initialized. + self.state = STARTING; + self.on.call("start", node, node.__data__, self.index, self.group); + if (self.state !== STARTING) return; // interrupted + self.state = STARTED; - /** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. - */ - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} + // Initialize the tween, deleting null tween. + tween = new Array(n = self.tween.length); + for (i = 0, j = -1; i < n; ++i) { + if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) { + tween[++j] = o; } - return ''; } + tween.length = j + 1; + } - /** - * Updates wrapper `details` based on `bitmask` flags. - * - * @private - * @returns {Array} details The details to modify. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Array} Returns `details`. - */ - function updateWrapDetails(details, bitmask) { - arrayEach(wrapFlags, function(pair) { - var value = '_.' + pair[0]; - if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { - details.push(value); - } - }); - return details.sort(); - } + function tick(elapsed) { + var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1), + i = -1, + n = tween.length; - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - if (wrapper instanceof LazyWrapper) { - return wrapper.clone(); - } - var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); - result.__actions__ = copyArray(wrapper.__actions__); - result.__index__ = wrapper.__index__; - result.__values__ = wrapper.__values__; - return result; + while (++i < n) { + tween[i].call(null, t); } - /*------------------------------------------------------------------------*/ + // Dispatch the end event. + if (self.state === ENDING) { + self.on.call("end", node, node.__data__, self.index, self.group); + stop(); + } + } - /** - * Creates an array of elements split into groups the length of `size`. - * If `array` can't be split evenly, the final chunk will be the remaining - * elements. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to process. - * @param {number} [size=1] The length of each chunk - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the new array of chunks. - * @example - * - * _.chunk(['a', 'b', 'c', 'd'], 2); - * // => [['a', 'b'], ['c', 'd']] - * - * _.chunk(['a', 'b', 'c', 'd'], 3); - * // => [['a', 'b', 'c'], ['d']] - */ - function chunk(array, size, guard) { - if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { - size = 1; - } else { - size = nativeMax(toInteger(size), 0); - } - var length = array == null ? 0 : array.length; - if (!length || size < 1) { - return []; - } - var index = 0, - resIndex = 0, - result = Array(nativeCeil(length / size)); + function stop() { + self.state = ENDED; + self.timer.stop(); + delete schedules[id]; + for (var i in schedules) return; // eslint-disable-line no-unused-vars + delete node.__transition; + } +} - while (index < length) { - result[resIndex++] = baseSlice(array, index, (index += size)); - } - return result; - } +var interrupt = function(node, name) { + var schedules = node.__transition, + schedule$$1, + active, + empty = true, + i; - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result[resIndex++] = value; - } - } - return result; - } + if (!schedules) return; - /** - * Creates a new array concatenating `array` with any additional arrays - * and/or values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to concatenate. - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var other = _.concat(array, 2, [3], [[4]]); - * - * console.log(other); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - function concat() { - var length = arguments.length; - if (!length) { - return []; - } - var args = Array(length - 1), - array = arguments[0], - index = length; + name = name == null ? null : name + ""; - while (index--) { - args[index - 1] = arguments[index]; - } - return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); - } + for (i in schedules) { + if ((schedule$$1 = schedules[i]).name !== name) { empty = false; continue; } + active = schedule$$1.state > STARTING && schedule$$1.state < ENDING; + schedule$$1.state = ENDED; + schedule$$1.timer.stop(); + if (active) schedule$$1.on.call("interrupt", node, node.__data__, schedule$$1.index, schedule$$1.group); + delete schedules[i]; + } - /** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.without, _.xor - * @example - * - * _.difference([2, 1], [2, 3]); - * // => [1] - */ - var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; - }); + if (empty) delete node.__transition; +}; - /** - * This method is like `_.difference` except that it accepts `iteratee` which - * is invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The order and references of result values are - * determined by the first array. The iteratee is invoked with one argument: - * (value). - * - * **Note:** Unlike `_.pullAllBy`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [1.2] - * - * // The `_.property` iteratee shorthand. - * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); - * // => [{ 'x': 2 }] - */ - var differenceBy = baseRest(function(array, values) { - var iteratee = last(values); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) - : []; - }); +var selection_interrupt = function(name) { + return this.each(function() { + interrupt(this, name); + }); +}; - /** - * This method is like `_.difference` except that it accepts `comparator` - * which is invoked to compare elements of `array` to `values`. The order and - * references of result values are determined by the first array. The comparator - * is invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.pullAllWith`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * - * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); - * // => [{ 'x': 2, 'y': 1 }] - */ - var differenceWith = baseRest(function(array, values) { - var comparator = last(values); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) - : []; - }); +function tweenRemove(id, name) { + var tween0, tween1; + return function() { + var schedule$$1 = set$1(this, id), + tween = schedule$$1.tween; - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; + // If this node shared tween with the previous node, + // just assign the updated shared tween and we’re done! + // Otherwise, copy-on-write. + if (tween !== tween0) { + tween1 = tween0 = tween; + for (var i = 0, n = tween1.length; i < n; ++i) { + if (tween1[i].name === name) { + tween1 = tween1.slice(); + tween1.splice(i, 1); + break; + } } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, n < 0 ? 0 : n, length); } - /** - * Creates a slice of `array` with `n` elements dropped from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRight([1, 2, 3]); - * // => [1, 2] - * - * _.dropRight([1, 2, 3], 2); - * // => [1] - * - * _.dropRight([1, 2, 3], 5); - * // => [] - * - * _.dropRight([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function dropRight(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; + schedule$$1.tween = tween1; + }; +} + +function tweenFunction(id, name, value) { + var tween0, tween1; + if (typeof value !== "function") throw new Error; + return function() { + var schedule$$1 = set$1(this, id), + tween = schedule$$1.tween; + + // If this node shared tween with the previous node, + // just assign the updated shared tween and we’re done! + // Otherwise, copy-on-write. + if (tween !== tween0) { + tween1 = (tween0 = tween).slice(); + for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) { + if (tween1[i].name === name) { + tween1[i] = t; + break; + } } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, 0, n < 0 ? 0 : n); + if (i === n) tween1.push(t); } - /** - * Creates a slice of `array` excluding elements dropped from the end. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.dropRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney'] - * - * // The `_.matches` iteratee shorthand. - * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropRightWhile(users, ['active', false]); - * // => objects for ['barney'] - * - * // The `_.property` iteratee shorthand. - * _.dropRightWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true, true) - : []; - } + schedule$$1.tween = tween1; + }; +} - /** - * Creates a slice of `array` excluding elements dropped from the beginning. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.dropWhile(users, function(o) { return !o.active; }); - * // => objects for ['pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.dropWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropWhile(users, ['active', false]); - * // => objects for ['pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.dropWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true) - : []; - } +var transition_tween = function(name, value) { + var id = this._id; - /** - * Fills elements of `array` with `value` from `start` up to, but not - * including, `end`. - * - * **Note:** This method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Array - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.fill(array, 'a'); - * console.log(array); - * // => ['a', 'a', 'a'] - * - * _.fill(Array(3), 2); - * // => [2, 2, 2] - * - * _.fill([4, 6, 8, 10], '*', 1, 3); - * // => [4, '*', '*', 10] - */ - function fill(array, value, start, end) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { - start = 0; - end = length; - } - return baseFill(array, value, start, end); - } + name += ""; - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(o) { return o.user == 'barney'; }); - * // => 0 - * - * // The `_.matches` iteratee shorthand. - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findIndex(users, ['active', false]); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.findIndex(users, 'active'); - * // => 2 - */ - function findIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); + if (arguments.length < 2) { + var tween = get$1(this.node(), id).tween; + for (var i = 0, n = tween.length, t; i < n; ++i) { + if ((t = tween[i]).name === name) { + return t.value; } - return baseFindIndex(array, getIteratee(predicate, 3), index); } + return null; + } - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); - * // => 2 - * - * // The `_.matches` iteratee shorthand. - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastIndex(users, ['active', false]); - * // => 2 - * - * // The `_.property` iteratee shorthand. - * _.findLastIndex(users, 'active'); - * // => 0 - */ - function findLastIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = length - 1; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = fromIndex < 0 - ? nativeMax(length + index, 0) - : nativeMin(index, length - 1); - } - return baseFindIndex(array, getIteratee(predicate, 3), index, true); - } + return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value)); +}; - /** - * Flattens `array` a single level deep. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] - */ - function flatten(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, 1) : []; - } +function tweenValue(transition, name, value) { + var id = transition._id; - /** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ - function flattenDeep(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, INFINITY) : []; - } + transition.each(function() { + var schedule$$1 = set$1(this, id); + (schedule$$1.value || (schedule$$1.value = {}))[name] = value.apply(this, arguments); + }); - /** - * Recursively flatten `array` up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Array - * @param {Array} array The array to flatten. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * var array = [1, [2, [3, [4]], 5]]; - * - * _.flattenDepth(array, 1); - * // => [1, 2, [3, [4]], 5] - * - * _.flattenDepth(array, 2); - * // => [1, 2, 3, [4], 5] - */ - function flattenDepth(array, depth) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(array, depth); - } + return function(node) { + return get$1(node, id).value[name]; + }; +} - /** - * The inverse of `_.toPairs`; this method returns an object composed - * from key-value `pairs`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} pairs The key-value pairs. - * @returns {Object} Returns the new object. - * @example - * - * _.fromPairs([['a', 1], ['b', 2]]); - * // => { 'a': 1, 'b': 2 } - */ - function fromPairs(pairs) { - var index = -1, - length = pairs == null ? 0 : pairs.length, - result = {}; - - while (++index < length) { - var pair = pairs[index]; - result[pair[0]] = pair[1]; - } - return result; - } +var interpolate = function(a, b) { + var c; + return (typeof b === "number" ? d3_interpolateNumber + : b instanceof color ? d3_interpolateRgb + : (c = color(b)) ? (b = c, d3_interpolateRgb) + : interpolateString)(a, b); +}; - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias first - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.head([1, 2, 3]); - * // => 1 - * - * _.head([]); - * // => undefined - */ - function head(array) { - return (array && array.length) ? array[0] : undefined; - } +function attrRemove$1(name) { + return function() { + this.removeAttribute(name); + }; +} - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the - * offset from the end of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // Search from the `fromIndex`. - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - */ - function indexOf(array, value, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); - } - return baseIndexOf(array, value, index); - } +function attrRemoveNS$1(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; +} - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - var length = array == null ? 0 : array.length; - return length ? baseSlice(array, 0, -1) : []; - } +function attrConstant$1(name, interpolate$$1, value1) { + var value00, + interpolate0; + return function() { + var value0 = this.getAttribute(name); + return value0 === value1 ? null + : value0 === value00 ? interpolate0 + : interpolate0 = interpolate$$1(value00 = value0, value1); + }; +} - /** - * Creates an array of unique values that are included in all given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersection([2, 1], [2, 3]); - * // => [2] - */ - var intersection = baseRest(function(arrays) { - var mapped = arrayMap(arrays, castArrayLikeObject); - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped) - : []; - }); +function attrConstantNS$1(fullname, interpolate$$1, value1) { + var value00, + interpolate0; + return function() { + var value0 = this.getAttributeNS(fullname.space, fullname.local); + return value0 === value1 ? null + : value0 === value00 ? interpolate0 + : interpolate0 = interpolate$$1(value00 = value0, value1); + }; +} - /** - * This method is like `_.intersection` except that it accepts `iteratee` - * which is invoked for each element of each `arrays` to generate the criterion - * by which they're compared. The order and references of result values are - * determined by the first array. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [2.1] - * - * // The `_.property` iteratee shorthand. - * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }] - */ - var intersectionBy = baseRest(function(arrays) { - var iteratee = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); +function attrFunction$1(name, interpolate$$1, value) { + var value00, + value10, + interpolate0; + return function() { + var value0, value1 = value(this); + if (value1 == null) return void this.removeAttribute(name); + value0 = this.getAttribute(name); + return value0 === value1 ? null + : value0 === value00 && value1 === value10 ? interpolate0 + : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + }; +} - if (iteratee === last(mapped)) { - iteratee = undefined; - } else { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, getIteratee(iteratee, 2)) - : []; - }); +function attrFunctionNS$1(fullname, interpolate$$1, value) { + var value00, + value10, + interpolate0; + return function() { + var value0, value1 = value(this); + if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local); + value0 = this.getAttributeNS(fullname.space, fullname.local); + return value0 === value1 ? null + : value0 === value00 && value1 === value10 ? interpolate0 + : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + }; +} - /** - * This method is like `_.intersection` except that it accepts `comparator` - * which is invoked to compare elements of `arrays`. The order and references - * of result values are determined by the first array. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.intersectionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }] - */ - var intersectionWith = baseRest(function(arrays) { - var comparator = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); +var transition_attr = function(name, value) { + var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate; + return this.attrTween(name, typeof value === "function" + ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value)) + : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname) + : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + "")); +}; - comparator = typeof comparator == 'function' ? comparator : undefined; - if (comparator) { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, undefined, comparator) - : []; - }); +function attrTweenNS(fullname, value) { + function tween() { + var node = this, i = value.apply(node, arguments); + return i && function(t) { + node.setAttributeNS(fullname.space, fullname.local, i(t)); + }; + } + tween._value = value; + return tween; +} - /** - * Converts all elements in `array` into a string separated by `separator`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to convert. - * @param {string} [separator=','] The element separator. - * @returns {string} Returns the joined string. - * @example - * - * _.join(['a', 'b', 'c'], '~'); - * // => 'a~b~c' - */ - function join(array, separator) { - return array == null ? '' : nativeJoin.call(array, separator); - } +function attrTween(name, value) { + function tween() { + var node = this, i = value.apply(node, arguments); + return i && function(t) { + node.setAttribute(name, i(t)); + }; + } + tween._value = value; + return tween; +} - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array == null ? 0 : array.length; - return length ? array[length - 1] : undefined; - } +var transition_attrTween = function(name, value) { + var key = "attr." + name; + if (arguments.length < 2) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + var fullname = namespace(name); + return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value)); +}; - /** - * This method is like `_.indexOf` except that it iterates over elements of - * `array` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.lastIndexOf([1, 2, 1, 2], 2); - * // => 3 - * - * // Search from the `fromIndex`. - * _.lastIndexOf([1, 2, 1, 2], 2, 2); - * // => 1 - */ - function lastIndexOf(array, value, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = length; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); - } - return value === value - ? strictLastIndexOf(array, value, index) - : baseFindIndex(array, baseIsNaN, index, true); - } +function delayFunction(id, value) { + return function() { + init(this, id).delay = +value.apply(this, arguments); + }; +} - /** - * Gets the element at index `n` of `array`. If `n` is negative, the nth - * element from the end is returned. - * - * @static - * @memberOf _ - * @since 4.11.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=0] The index of the element to return. - * @returns {*} Returns the nth element of `array`. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * - * _.nth(array, 1); - * // => 'b' - * - * _.nth(array, -2); - * // => 'c'; - */ - function nth(array, n) { - return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; - } +function delayConstant(id, value) { + return value = +value, function() { + init(this, id).delay = value; + }; +} - /** - * Removes all given values from `array` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` - * to remove elements from an array by predicate. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...*} [values] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pull(array, 'a', 'c'); - * console.log(array); - * // => ['b', 'b'] - */ - var pull = baseRest(pullAll); +var transition_delay = function(value) { + var id = this._id; - /** - * This method is like `_.pull` except that it accepts an array of values to remove. - * - * **Note:** Unlike `_.difference`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pullAll(array, ['a', 'c']); - * console.log(array); - * // => ['b', 'b'] - */ - function pullAll(array, values) { - return (array && array.length && values && values.length) - ? basePullAll(array, values) - : array; - } + return arguments.length + ? this.each((typeof value === "function" + ? delayFunction + : delayConstant)(id, value)) + : get$1(this.node(), id).delay; +}; - /** - * This method is like `_.pullAll` except that it accepts `iteratee` which is - * invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The iteratee is invoked with one argument: (value). - * - * **Note:** Unlike `_.differenceBy`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; - * - * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); - * console.log(array); - * // => [{ 'x': 2 }] - */ - function pullAllBy(array, values, iteratee) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, getIteratee(iteratee, 2)) - : array; - } +function durationFunction(id, value) { + return function() { + set$1(this, id).duration = +value.apply(this, arguments); + }; +} - /** - * This method is like `_.pullAll` except that it accepts `comparator` which - * is invoked to compare elements of `array` to `values`. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.differenceWith`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; - * - * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); - * console.log(array); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] - */ - function pullAllWith(array, values, comparator) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, undefined, comparator) - : array; - } +function durationConstant(id, value) { + return value = +value, function() { + set$1(this, id).duration = value; + }; +} - /** - * Removes elements from `array` corresponding to `indexes` and returns an - * array of removed elements. - * - * **Note:** Unlike `_.at`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * var pulled = _.pullAt(array, [1, 3]); - * - * console.log(array); - * // => ['a', 'c'] - * - * console.log(pulled); - * // => ['b', 'd'] - */ - var pullAt = flatRest(function(array, indexes) { - var length = array == null ? 0 : array.length, - result = baseAt(array, indexes); +var transition_duration = function(value) { + var id = this._id; - basePullAt(array, arrayMap(indexes, function(index) { - return isIndex(index, length) ? +index : index; - }).sort(compareAscending)); + return arguments.length + ? this.each((typeof value === "function" + ? durationFunction + : durationConstant)(id, value)) + : get$1(this.node(), id).duration; +}; - return result; - }); +function easeConstant(id, value) { + if (typeof value !== "function") throw new Error; + return function() { + set$1(this, id).ease = value; + }; +} - /** - * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is invoked - * with three arguments: (value, index, array). - * - * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` - * to pull elements from an array by value. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4]; - * var evens = _.remove(array, function(n) { - * return n % 2 == 0; - * }); - * - * console.log(array); - * // => [1, 3] - * - * console.log(evens); - * // => [2, 4] - */ - function remove(array, predicate) { - var result = []; - if (!(array && array.length)) { - return result; - } - var index = -1, - indexes = [], - length = array.length; +var transition_ease = function(value) { + var id = this._id; - predicate = getIteratee(predicate, 3); - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result.push(value); - indexes.push(index); - } - } - basePullAt(array, indexes); - return result; - } + return arguments.length + ? this.each(easeConstant(id, value)) + : get$1(this.node(), id).ease; +}; - /** - * Reverses `array` so that the first element becomes the last, the second - * element becomes the second to last, and so on. - * - * **Note:** This method mutates `array` and is based on - * [`Array#reverse`](https://mdn.io/Array/reverse). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.reverse(array); - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function reverse(array) { - return array == null ? array : nativeReverse.call(array); - } +var transition_filter = function(match) { + if (typeof match !== "function") match = matcher$1(match); - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of - * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are - * returned. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - else { - start = start == null ? 0 : toInteger(start); - end = end === undefined ? length : toInteger(end); + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { + if ((node = group[i]) && match.call(node, node.__data__, i, group)) { + subgroup.push(node); } - return baseSlice(array, start, end); } + } - /** - * Uses a binary search to determine the lowest index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([30, 50], 40); - * // => 1 - */ - function sortedIndex(array, value) { - return baseSortedIndex(array, value); - } + return new Transition(subgroups, this._parents, this._name, this._id); +}; - /** - * This method is like `_.sortedIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); - * // => 0 - */ - function sortedIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); - } +var transition_merge = function(transition$$1) { + if (transition$$1._id !== this._id) throw new Error; - /** - * This method is like `_.indexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedIndexOf([4, 5, 5, 5, 6], 5); - * // => 1 - */ - function sortedIndexOf(array, value) { - var length = array == null ? 0 : array.length; - if (length) { - var index = baseSortedIndex(array, value); - if (index < length && eq(array[index], value)) { - return index; - } + for (var groups0 = this._groups, groups1 = transition$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group0[i] || group1[i]) { + merge[i] = node; } - return -1; } + } - /** - * This method is like `_.sortedIndex` except that it returns the highest - * index at which `value` should be inserted into `array` in order to - * maintain its sort order. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedLastIndex([4, 5, 5, 5, 6], 5); - * // => 4 - */ - function sortedLastIndex(array, value) { - return baseSortedIndex(array, value, true); - } + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } - /** - * This method is like `_.sortedLastIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 1 - * - * // The `_.property` iteratee shorthand. - * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); - * // => 1 - */ - function sortedLastIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); - } + return new Transition(merges, this._parents, this._name, this._id); +}; - /** - * This method is like `_.lastIndexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); - * // => 3 - */ - function sortedLastIndexOf(array, value) { - var length = array == null ? 0 : array.length; - if (length) { - var index = baseSortedIndex(array, value, true) - 1; - if (eq(array[index], value)) { - return index; - } - } - return -1; - } +function start(name) { + return (name + "").trim().split(/^|\s+/).every(function(t) { + var i = t.indexOf("."); + if (i >= 0) t = t.slice(0, i); + return !t || t === "start"; + }); +} - /** - * This method is like `_.uniq` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniq([1, 1, 2]); - * // => [1, 2] - */ - function sortedUniq(array) { - return (array && array.length) - ? baseSortedUniq(array) - : []; - } +function onFunction(id, name, listener) { + var on0, on1, sit = start(name) ? init : set$1; + return function() { + var schedule$$1 = sit(this, id), + on = schedule$$1.on; - /** - * This method is like `_.uniqBy` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); - * // => [1.1, 2.3] - */ - function sortedUniqBy(array, iteratee) { - return (array && array.length) - ? baseSortedUniq(array, getIteratee(iteratee, 2)) - : []; - } + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener); - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.tail([1, 2, 3]); - * // => [2, 3] - */ - function tail(array) { - var length = array == null ? 0 : array.length; - return length ? baseSlice(array, 1, length) : []; - } + schedule$$1.on = on1; + }; +} - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - if (!(array && array.length)) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, 0, n < 0 ? 0 : n); - } +var transition_on = function(name, listener) { + var id = this._id; - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, n < 0 ? 0 : n, length); - } + return arguments.length < 2 + ? get$1(this.node(), id).on.on(name) + : this.each(onFunction(id, name, listener)); +}; - /** - * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.takeRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeRightWhile(users, ['active', false]); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.takeRightWhile(users, 'active'); - * // => [] - */ - function takeRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), false, true) - : []; - } +function removeFunction(id) { + return function() { + var parent = this.parentNode; + for (var i in this.__transition) if (+i !== id) return; + if (parent) parent.removeChild(this); + }; +} - /** - * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.takeWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matches` iteratee shorthand. - * _.takeWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeWhile(users, ['active', false]); - * // => objects for ['barney', 'fred'] - * - * // The `_.property` iteratee shorthand. - * _.takeWhile(users, 'active'); - * // => [] - */ - function takeWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3)) - : []; - } +var transition_remove = function() { + return this.on("end.remove", removeFunction(this._id)); +}; - /** - * Creates an array of unique values, in order, from all given arrays using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([2], [1, 2]); - * // => [2, 1] - */ - var union = baseRest(function(arrays) { - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); - }); +var transition_select = function(select) { + var name = this._name, + id = this._id; - /** - * This method is like `_.union` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which uniqueness is computed. Result values are chosen from the first - * array in which the value occurs. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.unionBy([2.1], [1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - var unionBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; + if (typeof select !== "function") select = selector(select); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { + if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + subgroup[i] = subnode; + schedule(subgroup[i], name, id, i, subgroup, get$1(node, id)); } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); - }); + } + } - /** - * This method is like `_.union` except that it accepts `comparator` which - * is invoked to compare elements of `arrays`. Result values are chosen from - * the first array in which the value occurs. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.unionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var unionWith = baseRest(function(arrays) { - var comparator = last(arrays); - comparator = typeof comparator == 'function' ? comparator : undefined; - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); - }); + return new Transition(subgroups, this._parents, name, id); +}; - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurrence of each element - * is kept. The order of result values is determined by the order they occur - * in the array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - */ - function uniq(array) { - return (array && array.length) ? baseUniq(array) : []; - } +var transition_selectAll = function(select) { + var name = this._name, + id = this._id; - /** - * This method is like `_.uniq` except that it accepts `iteratee` which is - * invoked for each element in `array` to generate the criterion by which - * uniqueness is computed. The order of result values is determined by the - * order they occur in the array. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniqBy([2.1, 1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniqBy(array, iteratee) { - return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; - } + if (typeof select !== "function") select = selectorAll(select); - /** - * This method is like `_.uniq` except that it accepts `comparator` which - * is invoked to compare elements of `array`. The order of result values is - * determined by the order they occur in the array.The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.uniqWith(objects, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] - */ - function uniqWith(array, comparator) { - comparator = typeof comparator == 'function' ? comparator : undefined; - return (array && array.length) ? baseUniq(array, undefined, comparator) : []; + for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) { + if (child = children[k]) { + schedule(child, name, id, k, children, inherit); + } + } + subgroups.push(children); + parents.push(node); + } } + } - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @since 1.2.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - * - * _.unzip(zipped); - * // => [['a', 'b'], [1, 2], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var length = 0; - array = arrayFilter(array, function(group) { - if (isArrayLikeObject(group)) { - length = nativeMax(group.length, length); - return true; - } - }); - return baseTimes(length, function(index) { - return arrayMap(array, baseProperty(index)); - }); - } + return new Transition(subgroups, parents, name, id); +}; - /** - * This method is like `_.unzip` except that it accepts `iteratee` to specify - * how regrouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee=_.identity] The function to combine - * regrouped values. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip([1, 2], [10, 20], [100, 200]); - * // => [[1, 10, 100], [2, 20, 200]] - * - * _.unzipWith(zipped, _.add); - * // => [3, 30, 300] - */ - function unzipWith(array, iteratee) { - if (!(array && array.length)) { - return []; - } - var result = unzip(array); - if (iteratee == null) { - return result; - } - return arrayMap(result, function(group) { - return apply(iteratee, undefined, group); - }); - } +var Selection$1 = selection.prototype.constructor; - /** - * Creates an array excluding all given values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.pull`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...*} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.xor - * @example - * - * _.without([2, 1, 2, 3], 1, 2); - * // => [3] - */ - var without = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, values) - : []; - }); +var transition_selection = function() { + return new Selection$1(this._groups, this._parents); +}; - /** - * Creates an array of unique values that is the - * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the given arrays. The order of result values is determined by the order - * they occur in the arrays. - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.without - * @example - * - * _.xor([2, 1], [2, 3]); - * // => [1, 3] - */ - var xor = baseRest(function(arrays) { - return baseXor(arrayFilter(arrays, isArrayLikeObject)); - }); +function styleRemove$1(name, interpolate$$1) { + var value00, + value10, + interpolate0; + return function() { + var value0 = styleValue(this, name), + value1 = (this.style.removeProperty(name), styleValue(this, name)); + return value0 === value1 ? null + : value0 === value00 && value1 === value10 ? interpolate0 + : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + }; +} - /** - * This method is like `_.xor` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which by which they're compared. The order of result values is determined - * by the order they occur in the arrays. The iteratee is invoked with one - * argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [1.2, 3.4] - * - * // The `_.property` iteratee shorthand. - * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 2 }] - */ - var xorBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); - }); +function styleRemoveEnd(name) { + return function() { + this.style.removeProperty(name); + }; +} - /** - * This method is like `_.xor` except that it accepts `comparator` which is - * invoked to compare elements of `arrays`. The order of result values is - * determined by the order they occur in the arrays. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.xorWith(objects, others, _.isEqual); - * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var xorWith = baseRest(function(arrays) { - var comparator = last(arrays); - comparator = typeof comparator == 'function' ? comparator : undefined; - return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); - }); +function styleConstant$1(name, interpolate$$1, value1) { + var value00, + interpolate0; + return function() { + var value0 = styleValue(this, name); + return value0 === value1 ? null + : value0 === value00 ? interpolate0 + : interpolate0 = interpolate$$1(value00 = value0, value1); + }; +} - /** - * Creates an array of grouped elements, the first of which contains the - * first elements of the given arrays, the second of which contains the - * second elements of the given arrays, and so on. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - */ - var zip = baseRest(unzip); +function styleFunction$1(name, interpolate$$1, value) { + var value00, + value10, + interpolate0; + return function() { + var value0 = styleValue(this, name), + value1 = value(this); + if (value1 == null) value1 = (this.style.removeProperty(name), styleValue(this, name)); + return value0 === value1 ? null + : value0 === value00 && value1 === value10 ? interpolate0 + : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + }; +} - /** - * This method is like `_.fromPairs` except that it accepts two arrays, - * one of property identifiers and one of corresponding values. - * - * @static - * @memberOf _ - * @since 0.4.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject(['a', 'b'], [1, 2]); - * // => { 'a': 1, 'b': 2 } - */ - function zipObject(props, values) { - return baseZipObject(props || [], values || [], assignValue); - } +var transition_style = function(name, value, priority) { + var i = (name += "") === "transform" ? interpolateTransformCss : interpolate; + return value == null ? this + .styleTween(name, styleRemove$1(name, i)) + .on("end.style." + name, styleRemoveEnd(name)) + : this.styleTween(name, typeof value === "function" + ? styleFunction$1(name, i, tweenValue(this, "style." + name, value)) + : styleConstant$1(name, i, value + ""), priority); +}; - /** - * This method is like `_.zipObject` except that it supports property paths. - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); - * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } - */ - function zipObjectDeep(props, values) { - return baseZipObject(props || [], values || [], baseSet); - } +function styleTween(name, value, priority) { + function tween() { + var node = this, i = value.apply(node, arguments); + return i && function(t) { + node.style.setProperty(name, i(t), priority); + }; + } + tween._value = value; + return tween; +} - /** - * This method is like `_.zip` except that it accepts `iteratee` to specify - * how grouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee=_.identity] The function to combine - * grouped values. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { - * return a + b + c; - * }); - * // => [111, 222] - */ - var zipWith = baseRest(function(arrays) { - var length = arrays.length, - iteratee = length > 1 ? arrays[length - 1] : undefined; +var transition_styleTween = function(name, value, priority) { + var key = "style." + (name += ""); + if (arguments.length < 2) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + return this.tween(key, styleTween(name, value, priority == null ? "" : priority)); +}; - iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; - return unzipWith(arrays, iteratee); - }); +function textConstant$1(value) { + return function() { + this.textContent = value; + }; +} - /*------------------------------------------------------------------------*/ +function textFunction$1(value) { + return function() { + var value1 = value(this); + this.textContent = value1 == null ? "" : value1; + }; +} - /** - * Creates a `lodash` wrapper instance that wraps `value` with explicit method - * chain sequences enabled. The result of such sequences must be unwrapped - * with `_#value`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Seq - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _ - * .chain(users) - * .sortBy('age') - * .map(function(o) { - * return o.user + ' is ' + o.age; - * }) - * .head() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } +var transition_text = function(value) { + return this.tween("text", typeof value === "function" + ? textFunction$1(tweenValue(this, "text", value)) + : textConstant$1(value == null ? "" : value + "")); +}; - /** - * This method invokes `interceptor` and returns `value`. The interceptor - * is invoked with one argument; (value). The purpose of this method is to - * "tap into" a method chain sequence in order to modify intermediate results. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * // Mutate input array. - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor) { - interceptor(value); - return value; - } +var transition_transition = function() { + var name = this._name, + id0 = this._id, + id1 = newId(); - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * The purpose of this method is to "pass thru" values replacing intermediate - * results in a method chain sequence. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor) { - return interceptor(value); + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + var inherit = get$1(node, id0); + schedule(node, name, id1, i, group, { + time: inherit.time + inherit.delay + inherit.duration, + delay: 0, + duration: inherit.duration, + ease: inherit.ease + }); + } } + } - /** - * This method is the wrapper version of `_.at`. - * - * @name at - * @memberOf _ - * @since 1.0.0 - * @category Seq - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _(object).at(['a[0].b.c', 'a[1]']).value(); - * // => [3, 4] - */ - var wrapperAt = flatRest(function(paths) { - var length = paths.length, - start = length ? paths[0] : 0, - value = this.__wrapped__, - interceptor = function(object) { return baseAt(object, paths); }; - - if (length > 1 || this.__actions__.length || - !(value instanceof LazyWrapper) || !isIndex(start)) { - return this.thru(interceptor); - } - value = value.slice(start, +start + (length ? 1 : 0)); - value.__actions__.push({ - 'func': thru, - 'args': [interceptor], - 'thisArg': undefined - }); - return new LodashWrapper(value, this.__chain__).thru(function(array) { - if (length && !array.length) { - array.push(undefined); - } - return array; - }); - }); + return new Transition(groups, this._parents, name, id1); +}; - /** - * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. - * - * @name chain - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // A sequence without explicit chaining. - * _(users).head(); - * // => { 'user': 'barney', 'age': 36 } - * - * // A sequence with explicit chaining. - * _(users) - * .chain() - * .head() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } +var id = 0; - /** - * Executes the chain sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapped = wrapped.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapped.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } +function Transition(groups, parents, name, id) { + this._groups = groups; + this._parents = parents; + this._name = name; + this._id = id; +} - /** - * Gets the next value on a wrapped object following the - * [iterator protocol](https://mdn.io/iteration_protocols#iterator). - * - * @name next - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the next iterator value. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped.next(); - * // => { 'done': false, 'value': 1 } - * - * wrapped.next(); - * // => { 'done': false, 'value': 2 } - * - * wrapped.next(); - * // => { 'done': true, 'value': undefined } - */ - function wrapperNext() { - if (this.__values__ === undefined) { - this.__values__ = toArray(this.value()); - } - var done = this.__index__ >= this.__values__.length, - value = done ? undefined : this.__values__[this.__index__++]; +function transition(name) { + return selection().transition(name); +} - return { 'done': done, 'value': value }; - } +function newId() { + return ++id; +} - /** - * Enables the wrapper to be iterable. - * - * @name Symbol.iterator - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the wrapper object. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped[Symbol.iterator]() === wrapped; - * // => true - * - * Array.from(wrapped); - * // => [1, 2] - */ - function wrapperToIterator() { - return this; - } +var selection_prototype = selection.prototype; - /** - * Creates a clone of the chain sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @param {*} value The value to plant. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2]).map(square); - * var other = wrapped.plant([3, 4]); - * - * other.value(); - * // => [9, 16] - * - * wrapped.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, - parent = this; - - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - clone.__index__ = 0; - clone.__values__ = undefined; - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } +Transition.prototype = transition.prototype = { + constructor: Transition, + select: transition_select, + selectAll: transition_selectAll, + filter: transition_filter, + merge: transition_merge, + selection: transition_selection, + transition: transition_transition, + call: selection_prototype.call, + nodes: selection_prototype.nodes, + node: selection_prototype.node, + size: selection_prototype.size, + empty: selection_prototype.empty, + each: selection_prototype.each, + on: transition_on, + attr: transition_attr, + attrTween: transition_attrTween, + style: transition_style, + styleTween: transition_styleTween, + text: transition_text, + remove: transition_remove, + tween: transition_tween, + delay: transition_delay, + duration: transition_duration, + ease: transition_ease +}; - /** - * This method is the wrapper version of `_.reverse`. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - if (value instanceof LazyWrapper) { - var wrapped = value; - if (this.__actions__.length) { - wrapped = new LazyWrapper(this); - } - wrapped = wrapped.reverse(); - wrapped.__actions__.push({ - 'func': thru, - 'args': [reverse], - 'thisArg': undefined - }); - return new LodashWrapper(wrapped, this.__chain__); - } - return this.thru(reverse); - } +function linear$1(t) { + return +t; +} - /** - * Executes the chain sequence to resolve the unwrapped value. - * - * @name value - * @memberOf _ - * @since 0.1.0 - * @alias toJSON, valueOf - * @category Seq - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } +function quadIn(t) { + return t * t; +} - /*------------------------------------------------------------------------*/ +function quadOut(t) { + return t * (2 - t); +} - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the number of times the key was returned by `iteratee`. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': 1, '6': 2 } - * - * // The `_.property` iteratee shorthand. - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - ++result[key]; - } else { - baseAssignValue(result, key, 1); - } - }); +function quadInOut(t) { + return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2; +} - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * Iteration is stopped once `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * **Note:** This method returns `true` for - * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because - * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of - * elements of empty collections. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.every(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, guard) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } +function cubicIn(t) { + return t * t * t; +} - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * **Note:** Unlike `_.remove`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.reject - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.filter(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, { 'age': 36, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.filter(users, 'active'); - * // => objects for ['barney'] - */ - function filter(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, getIteratee(predicate, 3)); - } +function cubicOut(t) { + return --t * t * t + 1; +} - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.find(users, function(o) { return o.age < 40; }); - * // => object for 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.find(users, { 'age': 1, 'active': true }); - * // => object for 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.find(users, ['active', false]); - * // => object for 'fred' - * - * // The `_.property` iteratee shorthand. - * _.find(users, 'active'); - * // => object for 'barney' - */ - var find = createFind(findIndex); +function cubicInOut(t) { + return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2; +} - /** - * This method is like `_.find` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=collection.length-1] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * _.findLast([1, 2, 3, 4], function(n) { - * return n % 2 == 1; - * }); - * // => 3 - */ - var findLast = createFind(findLastIndex); +var exponent = 3; - /** - * Creates a flattened array of values by running each element in `collection` - * thru `iteratee` and flattening the mapped results. The iteratee is invoked - * with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [n, n]; - * } - * - * _.flatMap([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMap(collection, iteratee) { - return baseFlatten(map(collection, iteratee), 1); - } +var polyIn = (function custom(e) { + e = +e; - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDeep([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMapDeep(collection, iteratee) { - return baseFlatten(map(collection, iteratee), INFINITY); - } + function polyIn(t) { + return Math.pow(t, e); + } - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDepth([1, 2], duplicate, 2); - * // => [[1, 1], [2, 2]] - */ - function flatMapDepth(collection, iteratee, depth) { - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(map(collection, iteratee), depth); - } + polyIn.exponent = custom; - /** - * Iterates over elements of `collection` and invokes `iteratee` for each element. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" - * property are iterated like arrays. To avoid this behavior use `_.forIn` - * or `_.forOwn` for object iteration. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias each - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEachRight - * @example - * - * _.forEach([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `1` then `2`. - * - * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forEach(collection, iteratee) { - var func = isArray(collection) ? arrayEach : baseEach; - return func(collection, getIteratee(iteratee, 3)); - } + return polyIn; +})(exponent); - /** - * This method is like `_.forEach` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @alias eachRight - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEach - * @example - * - * _.forEachRight([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `2` then `1`. - */ - function forEachRight(collection, iteratee) { - var func = isArray(collection) ? arrayEachRight : baseEachRight; - return func(collection, getIteratee(iteratee, 3)); - } +var polyOut = (function custom(e) { + e = +e; - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The order of grouped values - * is determined by the order they occur in `collection`. The corresponding - * value of each key is an array of elements responsible for generating the - * key. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': [4.2], '6': [6.1, 6.3] } - * - * // The `_.property` iteratee shorthand. - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - baseAssignValue(result, key, [value]); - } - }); + function polyOut(t) { + return 1 - Math.pow(1 - t, e); + } - /** - * Checks if `value` is in `collection`. If `collection` is a string, it's - * checked for a substring of `value`, otherwise - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * is used for equality comparisons. If `fromIndex` is negative, it's used as - * the offset from the end of `collection`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {boolean} Returns `true` if `value` is found, else `false`. - * @example - * - * _.includes([1, 2, 3], 1); - * // => true - * - * _.includes([1, 2, 3], 1, 2); - * // => false - * - * _.includes({ 'a': 1, 'b': 2 }, 1); - * // => true - * - * _.includes('abcd', 'bc'); - * // => true - */ - function includes(collection, value, fromIndex, guard) { - collection = isArrayLike(collection) ? collection : values(collection); - fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; + polyOut.exponent = custom; - var length = collection.length; - if (fromIndex < 0) { - fromIndex = nativeMax(length + fromIndex, 0); - } - return isString(collection) - ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) - : (!!length && baseIndexOf(collection, value, fromIndex) > -1); - } + return polyOut; +})(exponent); - /** - * Invokes the method at `path` of each element in `collection`, returning - * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `path` is a function, it's invoked - * for, and `this` bound to, each element in `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke each method with. - * @returns {Array} Returns the array of results. - * @example - * - * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invokeMap([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - var invokeMap = baseRest(function(collection, path, args) { - var index = -1, - isFunc = typeof path == 'function', - result = isArrayLike(collection) ? Array(collection.length) : []; +var polyInOut = (function custom(e) { + e = +e; - baseEach(collection, function(value) { - result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); - }); - return result; - }); + function polyInOut(t) { + return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2; + } - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the last element responsible for generating the key. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var array = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.keyBy(array, function(o) { - * return String.fromCharCode(o.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.keyBy(array, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - */ - var keyBy = createAggregator(function(result, value, key) { - baseAssignValue(result, key, value); - }); + polyInOut.exponent = custom; - /** - * Creates an array of values by running each element in `collection` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, - * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, - * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, - * `template`, `trim`, `trimEnd`, `trimStart`, and `words` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - * @example - * - * function square(n) { - * return n * n; - * } - * - * _.map([4, 8], square); - * // => [16, 64] - * - * _.map({ 'a': 4, 'b': 8 }, square); - * // => [16, 64] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // The `_.property` iteratee shorthand. - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee) { - var func = isArray(collection) ? arrayMap : baseMap; - return func(collection, getIteratee(iteratee, 3)); - } + return polyInOut; +})(exponent); - /** - * This method is like `_.sortBy` except that it allows specifying the sort - * orders of the iteratees to sort by. If `orders` is unspecified, all values - * are sorted in ascending order. Otherwise, specify an order of "desc" for - * descending or "asc" for ascending sort order of corresponding values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] - * The iteratees to sort by. - * @param {string[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // Sort by `user` in ascending order and by `age` in descending order. - * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - */ - function orderBy(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - orders = guard ? undefined : orders; - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseOrderBy(collection, iteratees, orders); - } +var pi = Math.PI; +var halfPi = pi / 2; - /** - * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, the second of which - * contains elements `predicate` returns falsey for. The predicate is - * invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the array of grouped elements. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true }, - * { 'user': 'pebbles', 'age': 1, 'active': false } - * ]; - * - * _.partition(users, function(o) { return o.active; }); - * // => objects for [['fred'], ['barney', 'pebbles']] - * - * // The `_.matches` iteratee shorthand. - * _.partition(users, { 'age': 1, 'active': false }); - * // => objects for [['pebbles'], ['barney', 'fred']] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.partition(users, ['active', false]); - * // => objects for [['barney', 'pebbles'], ['fred']] - * - * // The `_.property` iteratee shorthand. - * _.partition(users, 'active'); - * // => objects for [['fred'], ['barney', 'pebbles']] - */ - var partition = createAggregator(function(result, value, key) { - result[key ? 0 : 1].push(value); - }, function() { return [[], []]; }); +function sinIn(t) { + return 1 - Math.cos(t * halfPi); +} - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` thru `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not given, the first element of `collection` is used as the initial - * value. The iteratee is invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, - * and `sortBy` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduceRight - * @example - * - * _.reduce([1, 2], function(sum, n) { - * return sum + n; - * }, 0); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * return result; - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) - */ - function reduce(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduce : baseReduce, - initAccum = arguments.length < 3; +function sinOut(t) { + return Math.sin(t * halfPi); +} - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); - } +function sinInOut(t) { + return (1 - Math.cos(pi * t)) / 2; +} - /** - * This method is like `_.reduce` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduce - * @example - * - * var array = [[0, 1], [2, 3], [4, 5]]; - * - * _.reduceRight(array, function(flattened, other) { - * return flattened.concat(other); - * }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - function reduceRight(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduceRight : baseReduce, - initAccum = arguments.length < 3; +function expIn(t) { + return Math.pow(2, 10 * t - 10); +} - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); - } +function expOut(t) { + return 1 - Math.pow(2, -10 * t); +} - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.filter - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * _.reject(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.reject(users, { 'age': 40, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.reject(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.reject(users, 'active'); - * // => objects for ['barney'] - */ - function reject(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, negate(getIteratee(predicate, 3))); - } +function expInOut(t) { + return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2; +} - /** - * Gets a random element from `collection`. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - */ - function sample(collection) { - var func = isArray(collection) ? arraySample : baseSample; - return func(collection); - } +function circleIn(t) { + return 1 - Math.sqrt(1 - t * t); +} - /** - * Gets `n` random elements at unique keys from `collection` up to the - * size of `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @param {number} [n=1] The number of elements to sample. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the random elements. - * @example - * - * _.sampleSize([1, 2, 3], 2); - * // => [3, 1] - * - * _.sampleSize([1, 2, 3], 4); - * // => [2, 3, 1] - */ - function sampleSize(collection, n, guard) { - if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); - } - var func = isArray(collection) ? arraySampleSize : baseSampleSize; - return func(collection, n); - } +function circleOut(t) { + return Math.sqrt(1 - --t * t); +} - /** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * _.shuffle([1, 2, 3, 4]); - * // => [4, 1, 3, 2] - */ - function shuffle(collection) { - var func = isArray(collection) ? arrayShuffle : baseShuffle; - return func(collection); - } +function circleInOut(t) { + return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2; +} - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - if (collection == null) { - return 0; - } - if (isArrayLike(collection)) { - return isString(collection) ? stringSize(collection) : collection.length; - } - var tag = getTag(collection); - if (tag == mapTag || tag == setTag) { - return collection.size; - } - return baseKeys(collection).length; - } +var b1 = 4 / 11; +var b2 = 6 / 11; +var b3 = 8 / 11; +var b4 = 3 / 4; +var b5 = 9 / 11; +var b6 = 10 / 11; +var b7 = 15 / 16; +var b8 = 21 / 22; +var b9 = 63 / 64; +var b0 = 1 / b1 / b1; - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * Iteration is stopped once `predicate` returns truthy. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.some(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, guard) { - var func = isArray(collection) ? arraySome : baseSome; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } +function bounceIn(t) { + return 1 - bounceOut(1 - t); +} - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection thru each iteratee. This method - * performs a stable sort, that is, it preserves the original sort order of - * equal elements. The iteratees are invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {...(Function|Function[])} [iteratees=[_.identity]] - * The iteratees to sort by. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.sortBy(users, [function(o) { return o.user; }]); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - * - * _.sortBy(users, ['user', 'age']); - * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] - */ - var sortBy = baseRest(function(collection, iteratees) { - if (collection == null) { - return []; - } - var length = iteratees.length; - if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { - iteratees = []; - } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { - iteratees = [iteratees[0]]; - } - return baseOrderBy(collection, baseFlatten(iteratees, 1), []); - }); +function bounceOut(t) { + return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9; +} - /*------------------------------------------------------------------------*/ +function bounceInOut(t) { + return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2; +} - /** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ - var now = ctxNow || function() { - return root.Date.now(); - }; +var overshoot = 1.70158; - /*------------------------------------------------------------------------*/ +var backIn = (function custom(s) { + s = +s; - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it's called `n` or more times. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => Logs 'done saving!' after the two async saves have completed. - */ - function after(n, func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } + function backIn(t) { + return t * t * ((s + 1) * t - s); + } - /** - * Creates a function that invokes `func`, with up to `n` arguments, - * ignoring any additional arguments. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @param {number} [n=func.length] The arity cap. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.ary(parseInt, 1)); - * // => [6, 8, 10] - */ - function ary(func, n, guard) { - n = guard ? undefined : n; - n = (func && n == null) ? func.length : n; - return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); - } + backIn.overshoot = custom; - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it's called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery(element).on('click', _.before(5, addContactToList)); - * // => Allows adding up to 4 contacts to the list. - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } + return backIn; +})(overshoot); - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and `partials` prepended to the arguments it receives. - * - * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for partially applied arguments. - * - * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" - * property of bound functions. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * function greet(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // Bound with placeholders. - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = baseRest(function(func, thisArg, partials) { - var bitmask = WRAP_BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bind)); - bitmask |= WRAP_PARTIAL_FLAG; - } - return createWrap(func, bitmask, thisArg, partials, holders); - }); +var backOut = (function custom(s) { + s = +s; - /** - * Creates a function that invokes the method at `object[key]` with `partials` - * prepended to the arguments it receives. - * - * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. See - * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) - * for more details. - * - * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Function - * @param {Object} object The object to invoke the method on. - * @param {string} key The key of the method. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'user': 'fred', - * 'greet': function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * }; - * - * var bound = _.bindKey(object, 'greet', 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * object.greet = function(greeting, punctuation) { - * return greeting + 'ya ' + this.user + punctuation; - * }; - * - * bound('!'); - * // => 'hiya fred!' - * - * // Bound with placeholders. - * var bound = _.bindKey(object, 'greet', _, '!'); - * bound('hi'); - * // => 'hiya fred!' - */ - var bindKey = baseRest(function(object, key, partials) { - var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bindKey)); - bitmask |= WRAP_PARTIAL_FLAG; - } - return createWrap(key, bitmask, object, partials, holders); - }); + function backOut(t) { + return --t * t * ((s + 1) * t + s) + 1; + } - /** - * Creates a function that accepts arguments of `func` and either invokes - * `func` returning its result, if at least `arity` number of arguments have - * been provided, or returns a function that accepts the remaining `func` - * arguments, and so on. The arity of `func` may be specified if `func.length` - * is not sufficient. - * - * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curry(abc); - * - * curried(1)(2)(3); - * // => [1, 2, 3] - * - * curried(1, 2)(3); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(1)(_, 3)(2); - * // => [1, 2, 3] - */ - function curry(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curry.placeholder; - return result; - } + backOut.overshoot = custom; - /** - * This method is like `_.curry` except that arguments are applied to `func` - * in the manner of `_.partialRight` instead of `_.partial`. - * - * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curryRight(abc); - * - * curried(3)(2)(1); - * // => [1, 2, 3] - * - * curried(2, 3)(1); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(3)(1, _)(2); - * // => [1, 2, 3] - */ - function curryRight(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryRight.placeholder; - return result; - } + return backOut; +})(overshoot); - /** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ - function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } +var backInOut = (function custom(s) { + s = +s; - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; + function backInOut(t) { + return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2; + } - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } + backInOut.overshoot = custom; - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } + return backInOut; +})(overshoot); - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - result = wait - timeSinceLastCall; +var tau = 2 * Math.PI; +var amplitude = 1; +var period = 0.3; - return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; - } +var elasticIn = (function custom(a, p) { + var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau); - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; + function elasticIn(t) { + return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p); + } - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } + elasticIn.amplitude = function(a) { return custom(a, p * tau); }; + elasticIn.period = function(p) { return custom(a, p); }; - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } + return elasticIn; +})(amplitude, period); - function trailingEdge(time) { - timerId = undefined; +var elasticOut = (function custom(a, p) { + var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau); - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } + function elasticOut(t) { + return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p); + } - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } + elasticOut.amplitude = function(a) { return custom(a, p * tau); }; + elasticOut.period = function(p) { return custom(a, p); }; - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } + return elasticOut; +})(amplitude, period); - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); +var elasticInOut = (function custom(a, p) { + var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau); - lastArgs = arguments; - lastThis = this; - lastCallTime = time; + function elasticInOut(t) { + return ((t = t * 2 - 1) < 0 + ? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p) + : 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2; + } - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; - } + elasticInOut.amplitude = function(a) { return custom(a, p * tau); }; + elasticInOut.period = function(p) { return custom(a, p); }; - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // => Logs 'deferred' after one millisecond. - */ - var defer = baseRest(function(func, args) { - return baseDelay(func, 1, args); - }); + return elasticInOut; +})(amplitude, period); - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => Logs 'later' after one second. - */ - var delay = baseRest(function(func, wait, args) { - return baseDelay(func, toNumber(wait) || 0, args); - }); +var defaultTiming = { + time: null, // Set on use. + delay: 0, + duration: 250, + ease: cubicInOut +}; - /** - * Creates a function that invokes `func` with arguments reversed. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to flip arguments for. - * @returns {Function} Returns the new flipped function. - * @example - * - * var flipped = _.flip(function() { - * return _.toArray(arguments); - * }); - * - * flipped('a', 'b', 'c', 'd'); - * // => ['d', 'c', 'b', 'a'] - */ - function flip(func) { - return createWrap(func, WRAP_FLIP_FLAG); +function inherit(node, id) { + var timing; + while (!(timing = node.__transition) || !(timing = timing[id])) { + if (!(node = node.parentNode)) { + return defaultTiming.time = now(), defaultTiming; } + } + return timing; +} - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided, it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is used as the map cache key. The `func` - * is invoked with the `this` binding of the memoized function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the - * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `clear`, `delete`, `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoized function. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] - * - * object.a = 2; - * values(object); - * // => [1, 2] - * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] - * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result) || cache; - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; - } +var selection_transition = function(name) { + var id, + timing; - // Expose `MapCache`. - memoize.Cache = MapCache; + if (name instanceof Transition) { + id = name._id, name = name._name; + } else { + id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + ""; + } - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new negated function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + schedule(node, name, id, i, group, timing || inherit(node, id)); } - return function() { - var args = arguments; - switch (args.length) { - case 0: return !predicate.call(this); - case 1: return !predicate.call(this, args[0]); - case 2: return !predicate.call(this, args[0], args[1]); - case 3: return !predicate.call(this, args[0], args[1], args[2]); - } - return !predicate.apply(this, args); - }; - } - - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first invocation. The `func` is - * invoked with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // => `createApplication` is invoked once - */ - function once(func) { - return before(2, func); } + } - /** - * Creates a function that invokes `func` with its arguments transformed. - * - * @static - * @since 4.0.0 - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms=[_.identity]] - * The argument transforms. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var func = _.overArgs(function(x, y) { - * return [x, y]; - * }, [square, doubled]); - * - * func(9, 3); - * // => [81, 6] - * - * func(10, 5); - * // => [100, 10] - */ - var overArgs = castRest(function(func, transforms) { - transforms = (transforms.length == 1 && isArray(transforms[0])) - ? arrayMap(transforms[0], baseUnary(getIteratee())) - : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); - - var funcsLength = transforms.length; - return baseRest(function(args) { - var index = -1, - length = nativeMin(args.length, funcsLength); - - while (++index < length) { - args[index] = transforms[index].call(this, args[index]); - } - return apply(func, this, args); - }); - }); + return new Transition(groups, this._parents, name, id); +}; - /** - * Creates a function that invokes `func` with `partials` prepended to the - * arguments it receives. This method is like `_.bind` except it does **not** - * alter the `this` binding. - * - * The `_.partial.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 0.2.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var sayHelloTo = _.partial(greet, 'hello'); - * sayHelloTo('fred'); - * // => 'hello fred' - * - * // Partially applied with placeholders. - * var greetFred = _.partial(greet, _, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - */ - var partial = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partial)); - return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); - }); +selection.prototype.interrupt = selection_interrupt; +selection.prototype.transition = selection_transition; - /** - * This method is like `_.partial` except that partially applied arguments - * are appended to the arguments it receives. - * - * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var greetFred = _.partialRight(greet, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - * - * // Partially applied with placeholders. - * var sayHelloTo = _.partialRight(greet, 'hello', _); - * sayHelloTo('fred'); - * // => 'hello fred' - */ - var partialRight = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partialRight)); - return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); - }); +var root$1 = [null]; - /** - * Creates a function that invokes `func` with arguments arranged according - * to the specified `indexes` where the argument value at the first index is - * provided as the first argument, the argument value at the second index is - * provided as the second argument, and so on. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes. - * @returns {Function} Returns the new function. - * @example - * - * var rearged = _.rearg(function(a, b, c) { - * return [a, b, c]; - * }, [2, 0, 1]); - * - * rearged('b', 'c', 'a') - * // => ['a', 'b', 'c'] - */ - var rearg = flatRest(function(func, indexes) { - return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); - }); +var active = function(node, name) { + var schedules = node.__transition, + schedule$$1, + i; - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as - * an array. - * - * **Note:** This method is based on the - * [rest parameter](https://mdn.io/rest_parameters). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.rest(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function rest(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); + if (schedules) { + name = name == null ? null : name + ""; + for (i in schedules) { + if ((schedule$$1 = schedules[i]).state > SCHEDULED && schedule$$1.name === name) { + return new Transition([[node]], root$1, name, +i); } - start = start === undefined ? start : toInteger(start); - return baseRest(func, start); } + } - /** - * Creates a function that invokes `func` with the `this` binding of the - * create function and an array of arguments much like - * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). - * - * **Note:** This method is based on the - * [spread operator](https://mdn.io/spread_operator). - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Function - * @param {Function} func The function to spread arguments over. - * @param {number} [start=0] The start position of the spread. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.spread(function(who, what) { - * return who + ' says ' + what; - * }); - * - * say(['fred', 'hello']); - * // => 'fred says hello' - * - * var numbers = Promise.all([ - * Promise.resolve(40), - * Promise.resolve(36) - * ]); - * - * numbers.then(_.spread(function(x, y) { - * return x + y; - * })); - * // => a Promise of 76 - */ - function spread(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start == null ? 0 : nativeMax(toInteger(start), 0); - return baseRest(function(args) { - var array = args[start], - otherArgs = castSlice(args, 0, start); + return null; +}; - if (array) { - arrayPush(otherArgs, array); - } - return apply(func, this, otherArgs); - }); - } +var constant$4 = function(x) { + return function() { + return x; + }; +}; - /** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed `func` invocations and a `flush` method to - * immediately invoke them. Provide `options` to indicate whether `func` - * should be invoked on the leading and/or trailing edge of the `wait` - * timeout. The `func` is invoked with the last arguments provided to the - * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the throttled function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=true] - * Specify invoking on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // Avoid excessively updating the position while scrolling. - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. - * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); - * jQuery(element).on('click', throttled); - * - * // Cancel the trailing throttled invocation. - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; +var BrushEvent = function(target, type, selection) { + this.target = target; + this.type = type; + this.selection = selection; +}; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { - 'leading': leading, - 'maxWait': wait, - 'trailing': trailing - }); - } +function nopropagation$1() { + event.stopImmediatePropagation(); +} - /** - * Creates a function that accepts up to one argument, ignoring any - * additional arguments. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.unary(parseInt)); - * // => [6, 8, 10] - */ - function unary(func) { - return ary(func, 1); - } +var noevent$1 = function() { + event.preventDefault(); + event.stopImmediatePropagation(); +}; - /** - * Creates a function that provides `value` to `wrapper` as its first - * argument. Any additional arguments provided to the function are appended - * to those provided to the `wrapper`. The wrapper is invoked with the `this` - * binding of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {*} value The value to wrap. - * @param {Function} [wrapper=identity] The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

      ' + func(text) + '

      '; - * }); - * - * p('fred, barney, & pebbles'); - * // => '

      fred, barney, & pebbles

      ' - */ - function wrap(value, wrapper) { - return partial(castFunction(wrapper), value); - } +var MODE_DRAG = {name: "drag"}; +var MODE_SPACE = {name: "space"}; +var MODE_HANDLE = {name: "handle"}; +var MODE_CENTER = {name: "center"}; - /*------------------------------------------------------------------------*/ +var X = { + name: "x", + handles: ["e", "w"].map(type), + input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; }, + output: function(xy) { return xy && [xy[0][0], xy[1][0]]; } +}; - /** - * Casts `value` as an array if it's not one. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Lang - * @param {*} value The value to inspect. - * @returns {Array} Returns the cast array. - * @example - * - * _.castArray(1); - * // => [1] - * - * _.castArray({ 'a': 1 }); - * // => [{ 'a': 1 }] - * - * _.castArray('abc'); - * // => ['abc'] - * - * _.castArray(null); - * // => [null] - * - * _.castArray(undefined); - * // => [undefined] - * - * _.castArray(); - * // => [] - * - * var array = [1, 2, 3]; - * console.log(_.castArray(array) === array); - * // => true - */ - function castArray() { - if (!arguments.length) { - return []; - } - var value = arguments[0]; - return isArray(value) ? value : [value]; - } +var Y = { + name: "y", + handles: ["n", "s"].map(type), + input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; }, + output: function(xy) { return xy && [xy[0][1], xy[1][1]]; } +}; - /** - * Creates a shallow clone of `value`. - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) - * and supports cloning arrays, array buffers, booleans, date objects, maps, - * numbers, `Object` objects, regexes, sets, strings, symbols, and typed - * arrays. The own enumerable properties of `arguments` objects are cloned - * as plain objects. An empty object is returned for uncloneable values such - * as error objects, functions, DOM nodes, and WeakMaps. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to clone. - * @returns {*} Returns the cloned value. - * @see _.cloneDeep - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var shallow = _.clone(objects); - * console.log(shallow[0] === objects[0]); - * // => true - */ - function clone(value) { - return baseClone(value, CLONE_SYMBOLS_FLAG); - } +var XY = { + name: "xy", + handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type), + input: function(xy) { return xy; }, + output: function(xy) { return xy; } +}; - /** - * This method is like `_.clone` except that it accepts `customizer` which - * is invoked to produce the cloned value. If `customizer` returns `undefined`, - * cloning is handled by the method instead. The `customizer` is invoked with - * up to four arguments; (value [, index|key, object, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the cloned value. - * @see _.cloneDeepWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(false); - * } - * } - * - * var el = _.cloneWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 0 - */ - function cloneWith(value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); - } +var cursors = { + overlay: "crosshair", + selection: "move", + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" +}; - /** - * This method is like `_.clone` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @returns {*} Returns the deep cloned value. - * @see _.clone - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var deep = _.cloneDeep(objects); - * console.log(deep[0] === objects[0]); - * // => false - */ - function cloneDeep(value) { - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); - } +var flipX = { + e: "w", + w: "e", + nw: "ne", + ne: "nw", + se: "sw", + sw: "se" +}; - /** - * This method is like `_.cloneWith` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the deep cloned value. - * @see _.cloneWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(true); - * } - * } - * - * var el = _.cloneDeepWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 20 - */ - function cloneDeepWith(value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); - } +var flipY = { + n: "s", + s: "n", + nw: "sw", + ne: "se", + se: "ne", + sw: "nw" +}; - /** - * Checks if `object` conforms to `source` by invoking the predicate - * properties of `source` with the corresponding property values of `object`. - * - * **Note:** This method is equivalent to `_.conforms` when `source` is - * partially applied. - * - * @static - * @memberOf _ - * @since 4.14.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); - * // => true - * - * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); - * // => false - */ - function conformsTo(object, source) { - return source == null || baseConformsTo(object, source, keys(source)); - } +var signsX = { + overlay: +1, + selection: +1, + n: null, + e: +1, + s: null, + w: -1, + nw: -1, + ne: +1, + se: +1, + sw: -1 +}; - /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ - function eq(value, other) { - return value === other || (value !== value && other !== other); - } +var signsY = { + overlay: +1, + selection: +1, + n: -1, + e: null, + s: +1, + w: null, + nw: -1, + ne: -1, + se: +1, + sw: +1 +}; - /** - * Checks if `value` is greater than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - * @see _.lt - * @example - * - * _.gt(3, 1); - * // => true - * - * _.gt(3, 3); - * // => false - * - * _.gt(1, 3); - * // => false - */ - var gt = createRelationalOperation(baseGt); +function type(t) { + return {type: t}; +} - /** - * Checks if `value` is greater than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than or equal to - * `other`, else `false`. - * @see _.lte - * @example - * - * _.gte(3, 1); - * // => true - * - * _.gte(3, 3); - * // => true - * - * _.gte(1, 3); - * // => false - */ - var gte = createRelationalOperation(function(value, other) { - return value >= other; - }); +// Ignore right-click, since that should open the context menu. +function defaultFilter() { + return !event.button; +} - /** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && - !propertyIsEnumerable.call(value, 'callee'); - }; +function defaultExtent() { + var svg = this.ownerSVGElement || this; + return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]]; +} - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ - var isArray = Array.isArray; +// Like d3.local, but with the name “__brush” rather than auto-generated. +function local$$1(node) { + while (!node.__brush) if (!(node = node.parentNode)) return; + return node.__brush; +} - /** - * Checks if `value` is classified as an `ArrayBuffer` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - * @example - * - * _.isArrayBuffer(new ArrayBuffer(2)); - * // => true - * - * _.isArrayBuffer(new Array(2)); - * // => false - */ - var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; +function empty(extent) { + return extent[0][0] === extent[1][0] + || extent[0][1] === extent[1][1]; +} - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } +function brushSelection(node) { + var state = node.__brush; + return state ? state.dim.output(state.selection) : null; +} - /** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ - function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); - } +function brushX() { + return brush$1(X); +} - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && baseGetTag(value) == boolTag); - } +function brushY() { + return brush$1(Y); +} - /** - * Checks if `value` is a buffer. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * _.isBuffer(new Buffer(2)); - * // => true - * - * _.isBuffer(new Uint8Array(2)); - * // => false - */ - var isBuffer = nativeIsBuffer || stubFalse; +var brush = function() { + return brush$1(XY); +}; - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; +function brush$1(dim) { + var extent = defaultExtent, + filter = defaultFilter, + listeners = dispatch(brush, "start", "brush", "end"), + handleSize = 6, + touchending; - /** - * Checks if `value` is likely a DOM element. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - * - * _.isElement(''); - * // => false - */ - function isElement(value) { - return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); - } + function brush(group) { + var overlay = group + .property("__brush", initialize) + .selectAll(".overlay") + .data([type("overlay")]); - /** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (value == null) { - return true; - } - if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || - isBuffer(value) || isTypedArray(value) || isArguments(value))) { - return !value.length; - } - var tag = getTag(value); - if (tag == mapTag || tag == setTag) { - return !value.size; - } - if (isPrototype(value)) { - return !baseKeys(value).length; - } - for (var key in value) { - if (hasOwnProperty.call(value, key)) { - return false; - } - } - return true; - } + overlay.enter().append("rect") + .attr("class", "overlay") + .attr("pointer-events", "all") + .attr("cursor", cursors.overlay) + .merge(overlay) + .each(function() { + var extent = local$$1(this).extent; + d3_select(this) + .attr("x", extent[0][0]) + .attr("y", extent[0][1]) + .attr("width", extent[1][0] - extent[0][0]) + .attr("height", extent[1][1] - extent[0][1]); + }); - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are compared by strict equality, i.e. `===`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ - function isEqual(value, other) { - return baseIsEqual(value, other); - } + group.selectAll(".selection") + .data([type("selection")]) + .enter().append("rect") + .attr("class", "selection") + .attr("cursor", cursors.selection) + .attr("fill", "#777") + .attr("fill-opacity", 0.3) + .attr("stroke", "#fff") + .attr("shape-rendering", "crispEdges"); - /** - * This method is like `_.isEqual` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with up to - * six arguments: (objValue, othValue [, index|key, object, other, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, othValue) { - * if (isGreeting(objValue) && isGreeting(othValue)) { - * return true; - * } - * } - * - * var array = ['hello', 'goodbye']; - * var other = ['hi', 'goodbye']; - * - * _.isEqualWith(array, other, customizer); - * // => true - */ - function isEqualWith(value, other, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; - } + var handle = group.selectAll(".handle") + .data(dim.handles, function(d) { return d.type; }); - /** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ - function isError(value) { - if (!isObjectLike(value)) { - return false; - } - var tag = baseGetTag(value); - return tag == errorTag || tag == domExcTag || - (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); - } + handle.exit().remove(); - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on - * [`Number.isFinite`](https://mdn.io/Number/isFinite). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(3); - * // => true - * - * _.isFinite(Number.MIN_VALUE); - * // => true - * - * _.isFinite(Infinity); - * // => false - * - * _.isFinite('3'); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } + handle.enter().append("rect") + .attr("class", function(d) { return "handle handle--" + d.type; }) + .attr("cursor", function(d) { return cursors[d.type]; }); - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - if (!isObject(value)) { - return false; - } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; - } + group + .each(redraw) + .attr("fill", "none") + .attr("pointer-events", "all") + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)") + .on("mousedown.brush touchstart.brush", started); + } - /** - * Checks if `value` is an integer. - * - * **Note:** This method is based on - * [`Number.isInteger`](https://mdn.io/Number/isInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an integer, else `false`. - * @example - * - * _.isInteger(3); - * // => true - * - * _.isInteger(Number.MIN_VALUE); - * // => false - * - * _.isInteger(Infinity); - * // => false - * - * _.isInteger('3'); - * // => false - */ - function isInteger(value) { - return typeof value == 'number' && value == toInteger(value); - } + brush.move = function(group, selection) { + if (group.selection) { + group + .on("start.brush", function() { emitter(this, arguments).beforestart().start(); }) + .on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); }) + .tween("brush", function() { + var that = this, + state = that.__brush, + emit = emitter(that, arguments), + selection0 = state.selection, + selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent), + i = d3_interpolate(selection0, selection1); - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } + function tween(t) { + state.selection = t === 1 && empty(selection1) ? null : i(t); + redraw.call(that); + emit.brush(); + } - /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ - function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); - } + return selection0 && selection1 ? tween : tween(1); + }); + } else { + group + .each(function() { + var that = this, + args = arguments, + state = that.__brush, + selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent), + emit = emitter(that, args).beforestart(); - /** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ - function isObjectLike(value) { - return value != null && typeof value == 'object'; + interrupt(that); + state.selection = selection1 == null || empty(selection1) ? null : selection1; + redraw.call(that); + emit.start().brush().end(); + }); } + }; - /** - * Checks if `value` is classified as a `Map` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - * @example - * - * _.isMap(new Map); - * // => true - * - * _.isMap(new WeakMap); - * // => false - */ - var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; - - /** - * Performs a partial deep comparison between `object` and `source` to - * determine if `object` contains equivalent property values. - * - * **Note:** This method is equivalent to `_.matches` when `source` is - * partially applied. - * - * Partial comparisons will match empty array and empty object `source` - * values against any array or object value, respectively. See `_.isEqual` - * for a list of supported value comparisons. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.isMatch(object, { 'b': 2 }); - * // => true - * - * _.isMatch(object, { 'b': 1 }); - * // => false - */ - function isMatch(object, source) { - return object === source || baseIsMatch(object, source, getMatchData(source)); - } + function redraw() { + var group = d3_select(this), + selection = local$$1(this).selection; - /** - * This method is like `_.isMatch` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with five - * arguments: (objValue, srcValue, index|key, object, source). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, srcValue) { - * if (isGreeting(objValue) && isGreeting(srcValue)) { - * return true; - * } - * } - * - * var object = { 'greeting': 'hello' }; - * var source = { 'greeting': 'hi' }; - * - * _.isMatchWith(object, source, customizer); - * // => true - */ - function isMatchWith(object, source, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseIsMatch(object, source, getMatchData(source), customizer); - } + if (selection) { + group.selectAll(".selection") + .style("display", null) + .attr("x", selection[0][0]) + .attr("y", selection[0][1]) + .attr("width", selection[1][0] - selection[0][0]) + .attr("height", selection[1][1] - selection[0][1]); - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is based on - * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as - * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for - * `undefined` and other non-number values. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some - // ActiveX objects in IE. - return isNumber(value) && value != +value; + group.selectAll(".handle") + .style("display", null) + .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; }) + .attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; }) + .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; }) + .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; }); } - /** - * Checks if `value` is a pristine native function. - * - * **Note:** This method can't reliably detect native functions in the presence - * of the core-js package because core-js circumvents this kind of detection. - * Despite multiple requests, the core-js maintainer has made it clear: any - * attempt to fix the detection will be obstructed. As a result, we're left - * with little choice but to throw an error. Unfortunately, this also affects - * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), - * which rely on core-js. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ - function isNative(value) { - if (isMaskable(value)) { - throw new Error(CORE_ERROR_TEXT); - } - return baseIsNative(value); + else { + group.selectAll(".selection,.handle") + .style("display", "none") + .attr("x", null) + .attr("y", null) + .attr("width", null) + .attr("height", null); } + } - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } + function emitter(that, args) { + return that.__brush.emitter || new Emitter(that, args); + } - /** - * Checks if `value` is `null` or `undefined`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is nullish, else `false`. - * @example - * - * _.isNil(null); - * // => true - * - * _.isNil(void 0); - * // => true - * - * _.isNil(NaN); - * // => false - */ - function isNil(value) { - return value == null; - } + function Emitter(that, args) { + this.that = that; + this.args = args; + this.state = that.__brush; + this.active = 0; + } - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are - * classified as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a number, else `false`. - * @example - * - * _.isNumber(3); - * // => true - * - * _.isNumber(Number.MIN_VALUE); - * // => true - * - * _.isNumber(Infinity); - * // => true - * - * _.isNumber('3'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || - (isObjectLike(value) && baseGetTag(value) == numberTag); + Emitter.prototype = { + beforestart: function() { + if (++this.active === 1) this.state.emitter = this, this.starting = true; + return this; + }, + start: function() { + if (this.starting) this.starting = false, this.emit("start"); + return this; + }, + brush: function() { + this.emit("brush"); + return this; + }, + end: function() { + if (--this.active === 0) delete this.state.emitter, this.emit("end"); + return this; + }, + emit: function(type) { + customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]); } + }; - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * @static - * @memberOf _ - * @since 0.8.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - function isPlainObject(value) { - if (!isObjectLike(value) || baseGetTag(value) != objectTag) { - return false; - } - var proto = getPrototype(value); - if (proto === null) { - return true; - } - var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return typeof Ctor == 'function' && Ctor instanceof Ctor && - funcToString.call(Ctor) == objectCtorString; - } + function started() { + if (event.touches) { if (event.changedTouches.length < event.touches.length) return noevent$1(); } + else if (touchending) return; + if (!filter.apply(this, arguments)) return; - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + var that = this, + type = event.target.__data__.type, + mode = (event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (event.altKey ? MODE_CENTER : MODE_HANDLE), + signX = dim === Y ? null : signsX[type], + signY = dim === X ? null : signsY[type], + state = local$$1(that), + extent = state.extent, + selection = state.selection, + W = extent[0][0], w0, w1, + N = extent[0][1], n0, n1, + E = extent[1][0], e0, e1, + S = extent[1][1], s0, s1, + dx, + dy, + moving, + shifting = signX && signY && event.shiftKey, + lockX, + lockY, + point0 = d3_mouse(that), + point = point0, + emit = emitter(that, arguments).beforestart(); - /** - * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 - * double precision number which isn't the result of a rounded unsafe integer. - * - * **Note:** This method is based on - * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. - * @example - * - * _.isSafeInteger(3); - * // => true - * - * _.isSafeInteger(Number.MIN_VALUE); - * // => false - * - * _.isSafeInteger(Infinity); - * // => false - * - * _.isSafeInteger('3'); - * // => false - */ - function isSafeInteger(value) { - return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; + if (type === "overlay") { + state.selection = selection = [ + [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]], + [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0] + ]; + } else { + w0 = selection[0][0]; + n0 = selection[0][1]; + e0 = selection[1][0]; + s0 = selection[1][1]; } - /** - * Checks if `value` is classified as a `Set` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - * @example - * - * _.isSet(new Set); - * // => true - * - * _.isSet(new WeakSet); - * // => false - */ - var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + w1 = w0; + n1 = n0; + e1 = e0; + s1 = s0; - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); - } + var group = d3_select(that) + .attr("pointer-events", "none"); - /** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ - function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && baseGetTag(value) == symbolTag); - } + var overlay = group.selectAll(".overlay") + .attr("cursor", cursors[type]); - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + if (event.touches) { + group + .on("touchmove.brush", moved, true) + .on("touchend.brush touchcancel.brush", ended, true); + } else { + var view = d3_select(event.view) + .on("keydown.brush", keydowned, true) + .on("keyup.brush", keyupped, true) + .on("mousemove.brush", moved, true) + .on("mouseup.brush", ended, true); - /** - * Checks if `value` is `undefined`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; + dragDisable(event.view); } - /** - * Checks if `value` is classified as a `WeakMap` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. - * @example - * - * _.isWeakMap(new WeakMap); - * // => true - * - * _.isWeakMap(new Map); - * // => false - */ - function isWeakMap(value) { - return isObjectLike(value) && getTag(value) == weakMapTag; - } + nopropagation$1(); + interrupt(that); + redraw.call(that); + emit.start(); - /** - * Checks if `value` is classified as a `WeakSet` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. - * @example - * - * _.isWeakSet(new WeakSet); - * // => true - * - * _.isWeakSet(new Set); - * // => false - */ - function isWeakSet(value) { - return isObjectLike(value) && baseGetTag(value) == weakSetTag; + function moved() { + var point1 = d3_mouse(that); + if (shifting && !lockX && !lockY) { + if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true; + else lockX = true; + } + point = point1; + moving = true; + noevent$1(); + move(); } - /** - * Checks if `value` is less than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - * @see _.gt - * @example - * - * _.lt(1, 3); - * // => true - * - * _.lt(3, 3); - * // => false - * - * _.lt(3, 1); - * // => false - */ - var lt = createRelationalOperation(baseLt); + function move() { + var t; - /** - * Checks if `value` is less than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than or equal to - * `other`, else `false`. - * @see _.gte - * @example - * - * _.lte(1, 3); - * // => true - * - * _.lte(3, 3); - * // => true - * - * _.lte(3, 1); - * // => false - */ - var lte = createRelationalOperation(function(value, other) { - return value <= other; - }); + dx = point[0] - point0[0]; + dy = point[1] - point0[1]; - /** - * Converts `value` to an array. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * _.toArray({ 'a': 1, 'b': 2 }); - * // => [1, 2] - * - * _.toArray('abc'); - * // => ['a', 'b', 'c'] - * - * _.toArray(1); - * // => [] - * - * _.toArray(null); - * // => [] - */ - function toArray(value) { - if (!value) { - return []; + switch (mode) { + case MODE_SPACE: + case MODE_DRAG: { + if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx; + if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy; + break; + } + case MODE_HANDLE: { + if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0; + else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx; + if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0; + else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy; + break; + } + case MODE_CENTER: { + if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX)); + if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY)); + break; + } } - if (isArrayLike(value)) { - return isString(value) ? stringToArray(value) : copyArray(value); + + if (e1 < w1) { + signX *= -1; + t = w0, w0 = e0, e0 = t; + t = w1, w1 = e1, e1 = t; + if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]); } - if (symIterator && value[symIterator]) { - return iteratorToArray(value[symIterator]()); + + if (s1 < n1) { + signY *= -1; + t = n0, n0 = s0, s0 = t; + t = n1, n1 = s1, s1 = t; + if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]); } - var tag = getTag(value), - func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); - return func(value); - } + if (state.selection) selection = state.selection; // May be set by brush.move! + if (lockX) w1 = selection[0][0], e1 = selection[1][0]; + if (lockY) n1 = selection[0][1], s1 = selection[1][1]; - /** - * Converts `value` to a finite number. - * - * @static - * @memberOf _ - * @since 4.12.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted number. - * @example - * - * _.toFinite(3.2); - * // => 3.2 - * - * _.toFinite(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toFinite(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toFinite('3.2'); - * // => 3.2 - */ - function toFinite(value) { - if (!value) { - return value === 0 ? value : 0; - } - value = toNumber(value); - if (value === INFINITY || value === -INFINITY) { - var sign = (value < 0 ? -1 : 1); - return sign * MAX_INTEGER; + if (selection[0][0] !== w1 + || selection[0][1] !== n1 + || selection[1][0] !== e1 + || selection[1][1] !== s1) { + state.selection = [[w1, n1], [e1, s1]]; + redraw.call(that); + emit.brush(); } - return value === value ? value : 0; } - /** - * Converts `value` to an integer. - * - * **Note:** This method is loosely based on - * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toInteger(3.2); - * // => 3 - * - * _.toInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toInteger(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toInteger('3.2'); - * // => 3 - */ - function toInteger(value) { - var result = toFinite(value), - remainder = result % 1; - - return result === result ? (remainder ? result - remainder : result) : 0; + function ended() { + nopropagation$1(); + if (event.touches) { + if (event.touches.length) return; + if (touchending) clearTimeout(touchending); + touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! + group.on("touchmove.brush touchend.brush touchcancel.brush", null); + } else { + yesdrag(event.view, moving); + view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null); + } + group.attr("pointer-events", "all"); + overlay.attr("cursor", cursors.overlay); + if (state.selection) selection = state.selection; // May be set by brush.move (on start)! + if (empty(selection)) state.selection = null, redraw.call(that); + emit.end(); } - /** - * Converts `value` to an integer suitable for use as the length of an - * array-like object. - * - * **Note:** This method is based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toLength(3.2); - * // => 3 - * - * _.toLength(Number.MIN_VALUE); - * // => 0 - * - * _.toLength(Infinity); - * // => 4294967295 - * - * _.toLength('3.2'); - * // => 3 - */ - function toLength(value) { - return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; + function keydowned() { + switch (event.keyCode) { + case 16: { // SHIFT + shifting = signX && signY; + break; + } + case 18: { // ALT + if (mode === MODE_HANDLE) { + if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX; + if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY; + mode = MODE_CENTER; + move(); + } + break; + } + case 32: { // SPACE; takes priority over ALT + if (mode === MODE_HANDLE || mode === MODE_CENTER) { + if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx; + if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy; + mode = MODE_SPACE; + overlay.attr("cursor", cursors.selection); + move(); + } + break; + } + default: return; + } + noevent$1(); } - /** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ - function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; + function keyupped() { + switch (event.keyCode) { + case 16: { // SHIFT + if (shifting) { + lockX = lockY = shifting = false; + move(); + } + break; + } + case 18: { // ALT + if (mode === MODE_CENTER) { + if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1; + if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1; + mode = MODE_HANDLE; + move(); + } + break; + } + case 32: { // SPACE + if (mode === MODE_SPACE) { + if (event.altKey) { + if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX; + if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY; + mode = MODE_CENTER; + } else { + if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1; + if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1; + mode = MODE_HANDLE; + } + overlay.attr("cursor", cursors[type]); + move(); + } + break; + } + default: return; } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); + noevent$1(); } + } - /** - * Converts `value` to a plain object flattening inherited enumerable string - * keyed properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return copyObject(value, keysIn(value)); - } + function initialize() { + var state = this.__brush || {selection: null}; + state.extent = extent.apply(this, arguments); + state.dim = dim; + return state; + } - /** - * Converts `value` to a safe integer. A safe integer can be compared and - * represented correctly. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toSafeInteger(3.2); - * // => 3 - * - * _.toSafeInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toSafeInteger(Infinity); - * // => 9007199254740991 - * - * _.toSafeInteger('3.2'); - * // => 3 - */ - function toSafeInteger(value) { - return value - ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) - : (value === 0 ? value : 0); - } + brush.extent = function(_) { + return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent; + }; - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - return value == null ? '' : baseToString(value); - } + brush.filter = function(_) { + return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter; + }; - /*------------------------------------------------------------------------*/ + brush.handleSize = function(_) { + return arguments.length ? (handleSize = +_, brush) : handleSize; + }; - /** - * Assigns own enumerable string keyed properties of source objects to the - * destination object. Source objects are applied from left to right. - * Subsequent sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object` and is loosely based on - * [`Object.assign`](https://mdn.io/Object/assign). - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assignIn - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assign({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'c': 3 } - */ - var assign = createAssigner(function(object, source) { - if (isPrototype(source) || isArrayLike(source)) { - copyObject(source, keys(source), object); - return; - } - for (var key in source) { - if (hasOwnProperty.call(source, key)) { - assignValue(object, key, source[key]); - } - } - }); + brush.on = function() { + var value = listeners.on.apply(listeners, arguments); + return value === listeners ? brush : value; + }; - /** - * This method is like `_.assign` except that it iterates over own and - * inherited source properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assign - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assignIn({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } - */ - var assignIn = createAssigner(function(object, source) { - copyObject(source, keysIn(source), object); - }); + return brush; +} - /** - * This method is like `_.assignIn` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extendWith - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignInWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keysIn(source), object, customizer); - }); +var cos = Math.cos; +var sin = Math.sin; +var pi$1 = Math.PI; +var halfPi$1 = pi$1 / 2; +var tau$1 = pi$1 * 2; +var max$1 = Math.max; - /** - * This method is like `_.assign` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignInWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keys(source), object, customizer); - }); +function compareValue(compare) { + return function(a, b) { + return compare( + a.source.value + a.target.value, + b.source.value + b.target.value + ); + }; +} - /** - * Creates an array of values corresponding to `paths` of `object`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Array} Returns the picked values. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _.at(object, ['a[0].b.c', 'a[1]']); - * // => [3, 4] - */ - var at = flatRest(baseAt); +var chord = function() { + var padAngle = 0, + sortGroups = null, + sortSubgroups = null, + sortChords = null; - /** - * Creates an object that inherits from the `prototype` object. If a - * `properties` object is given, its own enumerable string keyed properties - * are assigned to the created object. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties) { - var result = baseCreate(prototype); - return properties == null ? result : baseAssign(result, properties); - } + function chord(matrix) { + var n = matrix.length, + groupSums = [], + groupIndex = d3_range(n), + subgroupIndex = [], + chords = [], + groups = chords.groups = new Array(n), + subgroups = new Array(n * n), + k, + x, + x0, + dx, + i, + j; - /** - * Assigns own and inherited enumerable string keyed properties of source - * objects to the destination object for all destination properties that - * resolve to `undefined`. Source objects are applied from left to right. - * Once a property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaultsDeep - * @example - * - * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var defaults = baseRest(function(args) { - args.push(undefined, customDefaultsAssignIn); - return apply(assignInWith, undefined, args); - }); + // Compute the sum. + k = 0, i = -1; while (++i < n) { + x = 0, j = -1; while (++j < n) { + x += matrix[i][j]; + } + groupSums.push(x); + subgroupIndex.push(d3_range(n)); + k += x; + } - /** - * This method is like `_.defaults` except that it recursively assigns - * default properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaults - * @example - * - * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); - * // => { 'a': { 'b': 2, 'c': 3 } } - */ - var defaultsDeep = baseRest(function(args) { - args.push(undefined, customDefaultsMerge); - return apply(mergeWith, undefined, args); + // Sort groups… + if (sortGroups) groupIndex.sort(function(a, b) { + return sortGroups(groupSums[a], groupSums[b]); }); - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(o) { return o.age < 40; }); - * // => 'barney' (iteration order is not guaranteed) - * - * // The `_.matches` iteratee shorthand. - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findKey(users, 'active'); - * // => 'barney' - */ - function findKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); - } + // Sort subgroups… + if (sortSubgroups) subgroupIndex.forEach(function(d, i) { + d.sort(function(a, b) { + return sortSubgroups(matrix[i][a], matrix[i][b]); + }); + }); - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(o) { return o.age < 40; }); - * // => returns 'pebbles' assuming `_.findKey` returns 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - function findLastKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); - } + // Convert the sum to scaling factor for [0, 2pi]. + // TODO Allow start and end angle to be specified? + // TODO Allow padding to be specified as percentage? + k = max$1(0, tau$1 - padAngle * n) / k; + dx = k ? padAngle : tau$1 / n; - /** - * Iterates over own and inherited enumerable string keyed properties of an - * object and invokes `iteratee` for each property. The iteratee is invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forInRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forIn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). - */ - function forIn(object, iteratee) { - return object == null - ? object - : baseFor(object, getIteratee(iteratee, 3), keysIn); + // Compute the start and end angle for each group and subgroup. + // Note: Opera has a bug reordering object literal properties! + x = 0, i = -1; while (++i < n) { + x0 = x, j = -1; while (++j < n) { + var di = groupIndex[i], + dj = subgroupIndex[di][j], + v = matrix[di][dj], + a0 = x, + a1 = x += v * k; + subgroups[dj * n + di] = { + index: di, + subindex: dj, + startAngle: a0, + endAngle: a1, + value: v + }; + } + groups[di] = { + index: di, + startAngle: x0, + endAngle: x, + value: groupSums[di] + }; + x += dx; } - /** - * This method is like `_.forIn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forIn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forInRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. - */ - function forInRight(object, iteratee) { - return object == null - ? object - : baseForRight(object, getIteratee(iteratee, 3), keysIn); + // Generate chords for each (non-empty) subgroup-subgroup link. + i = -1; while (++i < n) { + j = i - 1; while (++j < n) { + var source = subgroups[j * n + i], + target = subgroups[i * n + j]; + if (source.value || target.value) { + chords.push(source.value < target.value + ? {source: target, target: source} + : {source: source, target: target}); + } + } } - /** - * Iterates over own enumerable string keyed properties of an object and - * invokes `iteratee` for each property. The iteratee is invoked with three - * arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwnRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forOwn(object, iteratee) { - return object && baseForOwn(object, getIteratee(iteratee, 3)); - } + return sortChords ? chords.sort(sortChords) : chords; + } - /** - * This method is like `_.forOwn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwnRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. - */ - function forOwnRight(object, iteratee) { - return object && baseForOwnRight(object, getIteratee(iteratee, 3)); - } + chord.padAngle = function(_) { + return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle; + }; - /** - * Creates an array of function property names from own enumerable properties - * of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functionsIn - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functions(new Foo); - * // => ['a', 'b'] - */ - function functions(object) { - return object == null ? [] : baseFunctions(object, keys(object)); - } + chord.sortGroups = function(_) { + return arguments.length ? (sortGroups = _, chord) : sortGroups; + }; - /** - * Creates an array of function property names from own and inherited - * enumerable properties of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functions - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functionsIn(new Foo); - * // => ['a', 'b', 'c'] - */ - function functionsIn(object) { - return object == null ? [] : baseFunctions(object, keysIn(object)); - } + chord.sortSubgroups = function(_) { + return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups; + }; - /** - * Gets the value at `path` of `object`. If the resolved value is - * `undefined`, the `defaultValue` is returned in its place. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, path); - return result === undefined ? defaultValue : result; - } + chord.sortChords = function(_) { + return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._; + }; - /** - * Checks if `path` is a direct property of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = { 'a': { 'b': 2 } }; - * var other = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b'); - * // => true - * - * _.has(object, ['a', 'b']); - * // => true - * - * _.has(other, 'a'); - * // => false - */ - function has(object, path) { - return object != null && hasPath(object, path, baseHas); - } + return chord; +}; - /** - * Checks if `path` is a direct or inherited property of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.hasIn(object, 'a'); - * // => true - * - * _.hasIn(object, 'a.b'); - * // => true - * - * _.hasIn(object, ['a', 'b']); - * // => true - * - * _.hasIn(object, 'b'); - * // => false - */ - function hasIn(object, path) { - return object != null && hasPath(object, path, baseHasIn); - } +var slice$2 = Array.prototype.slice; - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite - * property assignments of previous values. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Object - * @param {Object} object The object to invert. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - */ - var invert = createInverter(function(result, value, key) { - result[value] = key; - }, constant(identity)); +var constant$5 = function(x) { + return function() { + return x; + }; +}; - /** - * This method is like `_.invert` except that the inverted object is generated - * from the results of running each element of `object` thru `iteratee`. The - * corresponding inverted value of each inverted key is an array of keys - * responsible for generating the inverted value. The iteratee is invoked - * with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Object - * @param {Object} object The object to invert. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invertBy(object); - * // => { '1': ['a', 'c'], '2': ['b'] } - * - * _.invertBy(object, function(value) { - * return 'group' + value; - * }); - * // => { 'group1': ['a', 'c'], 'group2': ['b'] } - */ - var invertBy = createInverter(function(result, value, key) { - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - }, getIteratee); +var pi$2 = Math.PI; +var tau$2 = 2 * pi$2; +var epsilon$1 = 1e-6; +var tauEpsilon = tau$2 - epsilon$1; - /** - * Invokes the method at `path` of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - * @example - * - * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; - * - * _.invoke(object, 'a[0].b.c.slice', 1, 3); - * // => [2, 3] - */ - var invoke = baseRest(baseInvoke); +function Path() { + this._x0 = this._y0 = // start of current subpath + this._x1 = this._y1 = null; // end of current subpath + this._ = ""; +} - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); - } +function path() { + return new Path; +} - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); +Path.prototype = path.prototype = { + constructor: Path, + moveTo: function(x, y) { + this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y); + }, + closePath: function() { + if (this._x1 !== null) { + this._x1 = this._x0, this._y1 = this._y0; + this._ += "Z"; } + }, + lineTo: function(x, y) { + this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y); + }, + quadraticCurveTo: function(x1, y1, x, y) { + this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y); + }, + bezierCurveTo: function(x1, y1, x2, y2, x, y) { + this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y); + }, + arcTo: function(x1, y1, x2, y2, r) { + x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r; + var x0 = this._x1, + y0 = this._y1, + x21 = x2 - x1, + y21 = y2 - y1, + x01 = x0 - x1, + y01 = y0 - y1, + l01_2 = x01 * x01 + y01 * y01; - /** - * The opposite of `_.mapValues`; this method creates an object with the - * same values as `object` and keys generated by running each own enumerable - * string keyed property of `object` thru `iteratee`. The iteratee is invoked - * with three arguments: (value, key, object). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapValues - * @example - * - * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { - * return key + value; - * }); - * // => { 'a1': 1, 'b2': 2 } - */ - function mapKeys(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); + // Is the radius negative? Error. + if (r < 0) throw new Error("negative radius: " + r); - baseForOwn(object, function(value, key, object) { - baseAssignValue(result, iteratee(value, key, object), value); - }); - return result; + // Is this path empty? Move to (x1,y1). + if (this._x1 === null) { + this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1); } - /** - * Creates an object with the same keys as `object` and values generated - * by running each own enumerable string keyed property of `object` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, key, object). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapKeys - * @example - * - * var users = { - * 'fred': { 'user': 'fred', 'age': 40 }, - * 'pebbles': { 'user': 'pebbles', 'age': 1 } - * }; - * - * _.mapValues(users, function(o) { return o.age; }); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - * - * // The `_.property` iteratee shorthand. - * _.mapValues(users, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - */ - function mapValues(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); + // Or, is (x1,y1) coincident with (x0,y0)? Do nothing. + else if (!(l01_2 > epsilon$1)) {} - baseForOwn(object, function(value, key, object) { - baseAssignValue(result, key, iteratee(value, key, object)); - }); - return result; + // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear? + // Equivalently, is (x1,y1) coincident with (x2,y2)? + // Or, is the radius zero? Line to (x1,y1). + else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) { + this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1); } - /** - * This method is like `_.assign` except that it recursively merges own and - * inherited enumerable string keyed properties of source objects into the - * destination object. Source properties that resolve to `undefined` are - * skipped if a destination value exists. Array and plain object properties - * are merged recursively. Other objects and value types are overridden by - * assignment. Source objects are applied from left to right. Subsequent - * sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * var object = { - * 'a': [{ 'b': 2 }, { 'd': 4 }] - * }; - * - * var other = { - * 'a': [{ 'c': 3 }, { 'e': 5 }] - * }; - * - * _.merge(object, other); - * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } - */ - var merge = createAssigner(function(object, source, srcIndex) { - baseMerge(object, source, srcIndex); - }); - - /** - * This method is like `_.merge` except that it accepts `customizer` which - * is invoked to produce the merged values of the destination and source - * properties. If `customizer` returns `undefined`, merging is handled by the - * method instead. The `customizer` is invoked with six arguments: - * (objValue, srcValue, key, object, source, stack). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * function customizer(objValue, srcValue) { - * if (_.isArray(objValue)) { - * return objValue.concat(srcValue); - * } - * } - * - * var object = { 'a': [1], 'b': [2] }; - * var other = { 'a': [3], 'b': [4] }; - * - * _.mergeWith(object, other, customizer); - * // => { 'a': [1, 3], 'b': [2, 4] } - */ - var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { - baseMerge(object, source, srcIndex, customizer); - }); + // Otherwise, draw an arc! + else { + var x20 = x2 - x0, + y20 = y2 - y0, + l21_2 = x21 * x21 + y21 * y21, + l20_2 = x20 * x20 + y20 * y20, + l21 = Math.sqrt(l21_2), + l01 = Math.sqrt(l01_2), + l = r * Math.tan((pi$2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2), + t01 = l / l01, + t21 = l / l21; - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable property paths of `object` that are not omitted. - * - * **Note:** This method is considerably slower than `_.pick`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to omit. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omit(object, ['a', 'c']); - * // => { 'b': '2' } - */ - var omit = flatRest(function(object, paths) { - var result = {}; - if (object == null) { - return result; - } - var isDeep = false; - paths = arrayMap(paths, function(path) { - path = castPath(path, object); - isDeep || (isDeep = path.length > 1); - return path; - }); - copyObject(object, getAllKeysIn(object), result); - if (isDeep) { - result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); - } - var length = paths.length; - while (length--) { - baseUnset(result, paths[length]); + // If the start tangent is not coincident with (x0,y0), line to. + if (Math.abs(t01 - 1) > epsilon$1) { + this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01); } - return result; - }); - /** - * The opposite of `_.pickBy`; this method creates an object composed of - * the own and inherited enumerable string keyed properties of `object` that - * `predicate` doesn't return truthy for. The predicate is invoked with two - * arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omitBy(object, _.isNumber); - * // => { 'b': '2' } - */ - function omitBy(object, predicate) { - return pickBy(object, negate(getIteratee(predicate))); + this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21); } + }, + arc: function(x, y, r, a0, a1, ccw) { + x = +x, y = +y, r = +r; + var dx = r * Math.cos(a0), + dy = r * Math.sin(a0), + x0 = x + dx, + y0 = y + dy, + cw = 1 ^ ccw, + da = ccw ? a0 - a1 : a1 - a0; - /** - * Creates an object composed of the picked `object` properties. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pick(object, ['a', 'c']); - * // => { 'a': 1, 'c': 3 } - */ - var pick = flatRest(function(object, paths) { - return object == null ? {} : basePick(object, paths); - }); + // Is the radius negative? Error. + if (r < 0) throw new Error("negative radius: " + r); - /** - * Creates an object composed of the `object` properties `predicate` returns - * truthy for. The predicate is invoked with two arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pickBy(object, _.isNumber); - * // => { 'a': 1, 'c': 3 } - */ - function pickBy(object, predicate) { - if (object == null) { - return {}; - } - var props = arrayMap(getAllKeysIn(object), function(prop) { - return [prop]; - }); - predicate = getIteratee(predicate); - return basePickBy(object, props, function(value, path) { - return predicate(value, path[0]); - }); + // Is this path empty? Move to (x0,y0). + if (this._x1 === null) { + this._ += "M" + x0 + "," + y0; } - /** - * This method is like `_.get` except that if the resolved value is a - * function it's invoked with the `this` binding of its parent object and - * its result is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a[0].b.c3', 'default'); - * // => 'default' - * - * _.result(object, 'a[0].b.c3', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - path = castPath(path, object); + // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0). + else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) { + this._ += "L" + x0 + "," + y0; + } - var index = -1, - length = path.length; + // Is this arc empty? We’re done. + if (!r) return; - // Ensure the loop is entered when path is empty. - if (!length) { - length = 1; - object = undefined; - } - while (++index < length) { - var value = object == null ? undefined : object[toKey(path[index])]; - if (value === undefined) { - index = length; - value = defaultValue; - } - object = isFunction(value) ? value.call(object) : value; - } - return object; - } + // Does the angle go the wrong way? Flip the direction. + if (da < 0) da = da % tau$2 + tau$2; - /** - * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, - * it's created. Arrays are created for missing index properties while objects - * are created for all other missing properties. Use `_.setWith` to customize - * `path` creation. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, ['x', '0', 'y', 'z'], 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - return object == null ? object : baseSet(object, path, value); + // Is this a complete circle? Draw two arcs to complete the circle. + if (da > tauEpsilon) { + this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0); } - /** - * This method is like `_.set` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.setWith(object, '[0][1]', 'a', Object); - * // => { '0': { '1': 'a' } } - */ - function setWith(object, path, value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseSet(object, path, value, customizer); + // Is this arc non-empty? Draw an arc! + else if (da > epsilon$1) { + this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1)); } + }, + rect: function(x, y, w, h) { + this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z"; + }, + toString: function() { + return this._; + } +}; - /** - * Creates an array of own enumerable string keyed-value pairs for `object` - * which can be consumed by `_.fromPairs`. If `object` is a map or set, its - * entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entries - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairs(new Foo); - * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) - */ - var toPairs = createToPairs(keys); +function defaultSource(d) { + return d.source; +} - /** - * Creates an array of own and inherited enumerable string keyed-value pairs - * for `object` which can be consumed by `_.fromPairs`. If `object` is a map - * or set, its entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entriesIn - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairsIn(new Foo); - * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) - */ - var toPairsIn = createToPairs(keysIn); +function defaultTarget(d) { + return d.target; +} - /** - * An alternative to `_.reduce`; this method transforms `object` to a new - * `accumulator` object which is the result of running each of its own - * enumerable string keyed properties thru `iteratee`, with each invocation - * potentially mutating the `accumulator` object. If `accumulator` is not - * provided, a new object with the same `[[Prototype]]` will be used. The - * iteratee is invoked with four arguments: (accumulator, value, key, object). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The custom accumulator value. - * @returns {*} Returns the accumulated value. - * @example - * - * _.transform([2, 3, 4], function(result, n) { - * result.push(n *= n); - * return n % 2 == 0; - * }, []); - * // => [4, 9] - * - * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } - */ - function transform(object, iteratee, accumulator) { - var isArr = isArray(object), - isArrLike = isArr || isBuffer(object) || isTypedArray(object); +function defaultRadius(d) { + return d.radius; +} - iteratee = getIteratee(iteratee, 4); - if (accumulator == null) { - var Ctor = object && object.constructor; - if (isArrLike) { - accumulator = isArr ? new Ctor : []; - } - else if (isObject(object)) { - accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; - } - else { - accumulator = {}; - } - } - (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { - return iteratee(accumulator, value, index, object); - }); - return accumulator; - } +function defaultStartAngle(d) { + return d.startAngle; +} - /** - * Removes the property at `path` of `object`. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 7 } }] }; - * _.unset(object, 'a[0].b.c'); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - * - * _.unset(object, ['a', '0', 'b', 'c']); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - */ - function unset(object, path) { - return object == null ? true : baseUnset(object, path); - } +function defaultEndAngle(d) { + return d.endAngle; +} - /** - * This method is like `_.set` except that accepts `updater` to produce the - * value to set. Use `_.updateWith` to customize `path` creation. The `updater` - * is invoked with one argument: (value). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.update(object, 'a[0].b.c', function(n) { return n * n; }); - * console.log(object.a[0].b.c); - * // => 9 - * - * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); - * console.log(object.x[0].y.z); - * // => 0 - */ - function update(object, path, updater) { - return object == null ? object : baseUpdate(object, path, castFunction(updater)); - } +var ribbon = function() { + var source = defaultSource, + target = defaultTarget, + radius = defaultRadius, + startAngle = defaultStartAngle, + endAngle = defaultEndAngle, + context = null; - /** - * This method is like `_.update` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.updateWith(object, '[0][1]', _.constant('a'), Object); - * // => { '0': { '1': 'a' } } - */ - function updateWith(object, path, updater, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); - } + function ribbon() { + var buffer, + argv = slice$2.call(arguments), + s = source.apply(this, argv), + t = target.apply(this, argv), + sr = +radius.apply(this, (argv[0] = s, argv)), + sa0 = startAngle.apply(this, argv) - halfPi$1, + sa1 = endAngle.apply(this, argv) - halfPi$1, + sx0 = sr * cos(sa0), + sy0 = sr * sin(sa0), + tr = +radius.apply(this, (argv[0] = t, argv)), + ta0 = startAngle.apply(this, argv) - halfPi$1, + ta1 = endAngle.apply(this, argv) - halfPi$1; - /** - * Creates an array of the own enumerable string keyed property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return object == null ? [] : baseValues(object, keys(object)); + if (!context) context = buffer = path(); + + context.moveTo(sx0, sy0); + context.arc(0, 0, sr, sa0, sa1); + if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr? + context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0)); + context.arc(0, 0, tr, ta0, ta1); } + context.quadraticCurveTo(0, 0, sx0, sy0); + context.closePath(); - /** - * Creates an array of the own and inherited enumerable string keyed property - * values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.valuesIn(new Foo); - * // => [1, 2, 3] (iteration order is not guaranteed) - */ - function valuesIn(object) { - return object == null ? [] : baseValues(object, keysIn(object)); - } + if (buffer) return context = null, buffer + "" || null; + } - /*------------------------------------------------------------------------*/ + ribbon.radius = function(_) { + return arguments.length ? (radius = typeof _ === "function" ? _ : constant$5(+_), ribbon) : radius; + }; - /** - * Clamps `number` within the inclusive `lower` and `upper` bounds. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Number - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - * @example - * - * _.clamp(-10, -5, 5); - * // => -5 - * - * _.clamp(10, -5, 5); - * // => 5 - */ - function clamp(number, lower, upper) { - if (upper === undefined) { - upper = lower; - lower = undefined; - } - if (upper !== undefined) { - upper = toNumber(upper); - upper = upper === upper ? upper : 0; - } - if (lower !== undefined) { - lower = toNumber(lower); - lower = lower === lower ? lower : 0; - } - return baseClamp(toNumber(number), lower, upper); - } + ribbon.startAngle = function(_) { + return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : startAngle; + }; - /** - * Checks if `n` is between `start` and up to, but not including, `end`. If - * `end` is not specified, it's set to `start` with `start` then set to `0`. - * If `start` is greater than `end` the params are swapped to support - * negative ranges. - * - * @static - * @memberOf _ - * @since 3.3.0 - * @category Number - * @param {number} number The number to check. - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - * @see _.range, _.rangeRight - * @example - * - * _.inRange(3, 2, 4); - * // => true - * - * _.inRange(4, 8); - * // => true - * - * _.inRange(4, 2); - * // => false - * - * _.inRange(2, 2); - * // => false - * - * _.inRange(1.2, 2); - * // => true - * - * _.inRange(5.2, 4); - * // => false - * - * _.inRange(-3, -2, -6); - * // => true - */ - function inRange(number, start, end) { - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - number = toNumber(number); - return baseInRange(number, start, end); - } + ribbon.endAngle = function(_) { + return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : endAngle; + }; - /** - * Produces a random number between the inclusive `lower` and `upper` bounds. - * If only one argument is provided a number between `0` and the given number - * is returned. If `floating` is `true`, or either `lower` or `upper` are - * floats, a floating-point number is returned instead of an integer. - * - * **Note:** JavaScript follows the IEEE-754 standard for resolving - * floating-point values which can produce unexpected results. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Number - * @param {number} [lower=0] The lower bound. - * @param {number} [upper=1] The upper bound. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(lower, upper, floating) { - if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { - upper = floating = undefined; - } - if (floating === undefined) { - if (typeof upper == 'boolean') { - floating = upper; - upper = undefined; - } - else if (typeof lower == 'boolean') { - floating = lower; - lower = undefined; - } - } - if (lower === undefined && upper === undefined) { - lower = 0; - upper = 1; - } - else { - lower = toFinite(lower); - if (upper === undefined) { - upper = lower; - lower = 0; - } else { - upper = toFinite(upper); - } - } - if (lower > upper) { - var temp = lower; - lower = upper; - upper = temp; - } - if (floating || lower % 1 || upper % 1) { - var rand = nativeRandom(); - return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); - } - return baseRandom(lower, upper); - } + ribbon.source = function(_) { + return arguments.length ? (source = _, ribbon) : source; + }; - /*------------------------------------------------------------------------*/ + ribbon.target = function(_) { + return arguments.length ? (target = _, ribbon) : target; + }; - /** - * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the camel cased string. - * @example - * - * _.camelCase('Foo Bar'); - * // => 'fooBar' - * - * _.camelCase('--foo-bar--'); - * // => 'fooBar' - * - * _.camelCase('__FOO_BAR__'); - * // => 'fooBar' - */ - var camelCase = createCompounder(function(result, word, index) { - word = word.toLowerCase(); - return result + (index ? capitalize(word) : word); - }); + ribbon.context = function(_) { + return arguments.length ? ((context = _ == null ? null : _), ribbon) : context; + }; - /** - * Converts the first character of `string` to upper case and the remaining - * to lower case. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to capitalize. - * @returns {string} Returns the capitalized string. - * @example - * - * _.capitalize('FRED'); - * // => 'Fred' - */ - function capitalize(string) { - return upperFirst(toString(string).toLowerCase()); - } + return ribbon; +}; - /** - * Deburrs `string` by converting - * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) - * letters to basic Latin letters and removing - * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to deburr. - * @returns {string} Returns the deburred string. - * @example - * - * _.deburr('déjà vu'); - * // => 'deja vu' - */ - function deburr(string) { - string = toString(string); - return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); - } +var prefix = "$"; - /** - * Checks if `string` ends with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search up to. - * @returns {boolean} Returns `true` if `string` ends with `target`, - * else `false`. - * @example - * - * _.endsWith('abc', 'c'); - * // => true - * - * _.endsWith('abc', 'b'); - * // => false - * - * _.endsWith('abc', 'b', 2); - * // => true - */ - function endsWith(string, target, position) { - string = toString(string); - target = baseToString(target); +function Map() {} + +Map.prototype = map$1.prototype = { + constructor: Map, + has: function(key) { + return (prefix + key) in this; + }, + get: function(key) { + return this[prefix + key]; + }, + set: function(key, value) { + this[prefix + key] = value; + return this; + }, + remove: function(key) { + var property = prefix + key; + return property in this && delete this[property]; + }, + clear: function() { + for (var property in this) if (property[0] === prefix) delete this[property]; + }, + keys: function() { + var keys = []; + for (var property in this) if (property[0] === prefix) keys.push(property.slice(1)); + return keys; + }, + values: function() { + var values = []; + for (var property in this) if (property[0] === prefix) values.push(this[property]); + return values; + }, + entries: function() { + var entries = []; + for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]}); + return entries; + }, + size: function() { + var size = 0; + for (var property in this) if (property[0] === prefix) ++size; + return size; + }, + empty: function() { + for (var property in this) if (property[0] === prefix) return false; + return true; + }, + each: function(f) { + for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this); + } +}; - var length = string.length; - position = position === undefined - ? length - : baseClamp(toInteger(position), 0, length); +function map$1(object, f) { + var map = new Map; - var end = position; - position -= target.length; - return position >= 0 && string.slice(position, end) == target; - } + // Copy constructor. + if (object instanceof Map) object.each(function(value, key) { map.set(key, value); }); - /** - * Converts the characters "&", "<", ">", '"', and "'" in `string` to their - * corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional - * characters use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. See - * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * When working with HTML you should always - * [quote attribute values](http://wonko.com/post/html-escaping) to reduce - * XSS vectors. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - string = toString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; + // Index array by numeric index or specified key function. + else if (Array.isArray(object)) { + var i = -1, + n = object.length, + o; + + if (f == null) while (++i < n) map.set(i, object[i]); + else while (++i < n) map.set(f(o = object[i], i, object), o); + } + + // Convert object to map. + else if (object) for (var key in object) map.set(key, object[key]); + + return map; +} + +var nest = function() { + var keys = [], + sortKeys = [], + sortValues, + rollup, + nest; + + function apply(array, depth, createResult, setResult) { + if (depth >= keys.length) { + if (sortValues != null) array.sort(sortValues); + return rollup != null ? rollup(array) : array; } - /** - * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", - * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https://lodash\.com/\)' - */ - function escapeRegExp(string) { - string = toString(string); - return (string && reHasRegExpChar.test(string)) - ? string.replace(reRegExpChar, '\\$&') - : string; + var i = -1, + n = array.length, + key = keys[depth++], + keyValue, + value, + valuesByKey = map$1(), + values, + result = createResult(); + + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) { + values.push(value); + } else { + valuesByKey.set(keyValue, [value]); + } } - /** - * Converts `string` to - * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the kebab cased string. - * @example - * - * _.kebabCase('Foo Bar'); - * // => 'foo-bar' - * - * _.kebabCase('fooBar'); - * // => 'foo-bar' - * - * _.kebabCase('__FOO_BAR__'); - * // => 'foo-bar' - */ - var kebabCase = createCompounder(function(result, word, index) { - return result + (index ? '-' : '') + word.toLowerCase(); + valuesByKey.each(function(values, key) { + setResult(result, key, apply(values, depth, createResult, setResult)); }); - /** - * Converts `string`, as space separated words, to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the lower cased string. - * @example - * - * _.lowerCase('--Foo-Bar--'); - * // => 'foo bar' - * - * _.lowerCase('fooBar'); - * // => 'foo bar' - * - * _.lowerCase('__FOO_BAR__'); - * // => 'foo bar' - */ - var lowerCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + word.toLowerCase(); - }); + return result; + } - /** - * Converts the first character of `string` to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.lowerFirst('Fred'); - * // => 'fred' - * - * _.lowerFirst('FRED'); - * // => 'fRED' - */ - var lowerFirst = createCaseFirst('toLowerCase'); + function entries(map, depth) { + if (++depth > keys.length) return map; + var array, sortKey = sortKeys[depth - 1]; + if (rollup != null && depth >= keys.length) array = map.entries(); + else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); }); + return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array; + } - /** - * Pads `string` on the left and right sides if it's shorter than `length`. - * Padding characters are truncated if they can't be evenly divided by `length`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.pad('abc', 8); - * // => ' abc ' - * - * _.pad('abc', 8, '_-'); - * // => '_-abc_-_' - * - * _.pad('abc', 3); - * // => 'abc' - */ - function pad(string, length, chars) { - string = toString(string); - length = toInteger(length); + return nest = { + object: function(array) { return apply(array, 0, createObject, setObject); }, + map: function(array) { return apply(array, 0, createMap, setMap); }, + entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); }, + key: function(d) { keys.push(d); return nest; }, + sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; }, + sortValues: function(order) { sortValues = order; return nest; }, + rollup: function(f) { rollup = f; return nest; } + }; +}; - var strLength = length ? stringSize(string) : 0; - if (!length || strLength >= length) { - return string; - } - var mid = (length - strLength) / 2; - return ( - createPadding(nativeFloor(mid), chars) + - string + - createPadding(nativeCeil(mid), chars) - ); - } +function createObject() { + return {}; +} - /** - * Pads `string` on the right side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padEnd('abc', 6); - * // => 'abc ' - * - * _.padEnd('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padEnd('abc', 3); - * // => 'abc' - */ - function padEnd(string, length, chars) { - string = toString(string); - length = toInteger(length); +function setObject(object, key, value) { + object[key] = value; +} - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (string + createPadding(length - strLength, chars)) - : string; - } +function createMap() { + return map$1(); +} - /** - * Pads `string` on the left side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padStart('abc', 6); - * // => ' abc' - * - * _.padStart('abc', 6, '_-'); - * // => '_-_abc' - * - * _.padStart('abc', 3); - * // => 'abc' - */ - function padStart(string, length, chars) { - string = toString(string); - length = toInteger(length); +function setMap(map, key, value) { + map.set(key, value); +} - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (createPadding(length - strLength, chars) + string) - : string; - } +function Set() {} - /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a - * hexadecimal, in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the - * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category String - * @param {string} string The string to convert. - * @param {number} [radix=10] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {number} Returns the converted integer. - * @example - * - * _.parseInt('08'); - * // => 8 - * - * _.map(['6', '08', '10'], _.parseInt); - * // => [6, 8, 10] - */ - function parseInt(string, radix, guard) { - if (guard || radix == null) { - radix = 0; - } else if (radix) { - radix = +radix; - } - return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); - } +var proto = map$1.prototype; - /** - * Repeats the given string `n` times. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=1] The number of times to repeat the string. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {string} Returns the repeated string. - * @example - * - * _.repeat('*', 3); - * // => '***' - * - * _.repeat('abc', 2); - * // => 'abcabc' - * - * _.repeat('abc', 0); - * // => '' - */ - function repeat(string, n, guard) { - if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); - } - return baseRepeat(toString(string), n); - } +Set.prototype = set$2.prototype = { + constructor: Set, + has: proto.has, + add: function(value) { + value += ""; + this[prefix + value] = value; + return this; + }, + remove: proto.remove, + clear: proto.clear, + values: proto.keys, + size: proto.size, + empty: proto.empty, + each: proto.each +}; - /** - * Replaces matches for `pattern` in `string` with `replacement`. - * - * **Note:** This method is based on - * [`String#replace`](https://mdn.io/String/replace). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to modify. - * @param {RegExp|string} pattern The pattern to replace. - * @param {Function|string} replacement The match replacement. - * @returns {string} Returns the modified string. - * @example - * - * _.replace('Hi Fred', 'Fred', 'Barney'); - * // => 'Hi Barney' - */ - function replace() { - var args = arguments, - string = toString(args[0]); +function set$2(object, f) { + var set = new Set; - return args.length < 3 ? string : string.replace(args[1], args[2]); - } + // Copy constructor. + if (object instanceof Set) object.each(function(value) { set.add(value); }); - /** - * Converts `string` to - * [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the snake cased string. - * @example - * - * _.snakeCase('Foo Bar'); - * // => 'foo_bar' - * - * _.snakeCase('fooBar'); - * // => 'foo_bar' - * - * _.snakeCase('--FOO-BAR--'); - * // => 'foo_bar' - */ - var snakeCase = createCompounder(function(result, word, index) { - return result + (index ? '_' : '') + word.toLowerCase(); - }); + // Otherwise, assume it’s an array. + else if (object) { + var i = -1, n = object.length; + if (f == null) while (++i < n) set.add(object[i]); + else while (++i < n) set.add(f(object[i], i, object)); + } - /** - * Splits `string` by `separator`. - * - * **Note:** This method is based on - * [`String#split`](https://mdn.io/String/split). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to split. - * @param {RegExp|string} separator The separator pattern to split by. - * @param {number} [limit] The length to truncate results to. - * @returns {Array} Returns the string segments. - * @example - * - * _.split('a-b-c', '-', 2); - * // => ['a', 'b'] - */ - function split(string, separator, limit) { - if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { - separator = limit = undefined; - } - limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; - if (!limit) { - return []; - } - string = toString(string); - if (string && ( - typeof separator == 'string' || - (separator != null && !isRegExp(separator)) - )) { - separator = baseToString(separator); - if (!separator && hasUnicode(string)) { - return castSlice(stringToArray(string), 0, limit); - } - } - return string.split(separator, limit); - } + return set; +} - /** - * Converts `string` to - * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @since 3.1.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the start cased string. - * @example - * - * _.startCase('--foo-bar--'); - * // => 'Foo Bar' - * - * _.startCase('fooBar'); - * // => 'Foo Bar' - * - * _.startCase('__FOO_BAR__'); - * // => 'FOO BAR' - */ - var startCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + upperFirst(word); - }); +var keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; +}; - /** - * Checks if `string` starts with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, - * else `false`. - * @example - * - * _.startsWith('abc', 'a'); - * // => true - * - * _.startsWith('abc', 'b'); - * // => false - * - * _.startsWith('abc', 'b', 1); - * // => true - */ - function startsWith(string, target, position) { - string = toString(string); - position = position == null - ? 0 - : baseClamp(toInteger(position), 0, string.length); +var values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; +}; - target = baseToString(target); - return string.slice(position, position + target.length) == target; - } +var entries = function(map) { + var entries = []; + for (var key in map) entries.push({key: key, value: map[key]}); + return entries; +}; - /** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is given, it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options={}] The options object. - * @param {RegExp} [options.escape=_.templateSettings.escape] - * The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] - * The "evaluate" delimiter. - * @param {Object} [options.imports=_.templateSettings.imports] - * An object to import into the template as free variables. - * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] - * The "interpolate" delimiter. - * @param {string} [options.sourceURL='lodash.templateSources[n]'] - * The sourceURL of the compiled template. - * @param {string} [options.variable='obj'] - * The data object variable name. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the compiled template function. - * @example - * - * // Use the "interpolate" delimiter to create a compiled template. - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // Use the HTML "escape" delimiter to escape data property values. - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': '