Index: .classpath
===================================================================
--- .classpath	(revision 15755)
+++ .classpath	(working copy)
@@ -33,6 +33,11 @@
 			<attribute name="test" value="true"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5">
+		<attributes>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
 	<classpathentry kind="lib" path="test/lib/jfcunit.jar">
 		<attributes>
 			<attribute name="test" value="true"/>
Index: .settings/org.eclipse.jdt.core.prefs
===================================================================
--- .settings/org.eclipse.jdt.core.prefs	(revision 15755)
+++ .settings/org.eclipse.jdt.core.prefs	(working copy)
@@ -24,6 +24,7 @@
 org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
@@ -80,6 +81,7 @@
 org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
 org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
 org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
 org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
 org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
 org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
@@ -112,8 +114,14 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=enabled
 org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
@@ -121,22 +129,34 @@
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
 org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
 org.eclipse.jdt.core.formatter.blank_lines_after_package=1
@@ -161,21 +181,25 @@
 org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
 org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
 org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
 org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
 org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
 org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
-org.eclipse.jdt.core.formatter.comment.format_block_comments=false
+org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
 org.eclipse.jdt.core.formatter.comment.format_comments=true
 org.eclipse.jdt.core.formatter.comment.format_header=false
-org.eclipse.jdt.core.formatter.comment.format_html=false
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
-org.eclipse.jdt.core.formatter.comment.format_line_comments=false
-org.eclipse.jdt.core.formatter.comment.format_source_code=false
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
 org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
 org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
-org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.line_length=80
 org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
 org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
 org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
@@ -185,7 +209,7 @@
 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
 org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
 org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
-org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
@@ -196,7 +220,8 @@
 org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
 org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
 org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
-org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.indentation.size=8
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
@@ -219,12 +244,13 @@
 org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=do not insert
 org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
 org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
 org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
 org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
 org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
@@ -254,6 +280,8 @@
 org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
 org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
 org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
@@ -278,13 +306,17 @@
 org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
 org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
 org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
 org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
 org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
@@ -332,6 +364,8 @@
 org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
@@ -368,9 +402,12 @@
 org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
 org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
 org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
@@ -382,20 +419,53 @@
 org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
 org.eclipse.jdt.core.formatter.join_lines_in_comments=true
 org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
 org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
 org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
 org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
 org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
 org.eclipse.jdt.core.formatter.lineSplit=120
 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
 org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
 org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
 org.eclipse.jdt.core.formatter.tabulation.char=space
 org.eclipse.jdt.core.formatter.tabulation.size=4
-org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
 org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
 org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
 org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
Index: .settings/org.eclipse.jdt.ui.prefs
===================================================================
--- .settings/org.eclipse.jdt.ui.prefs	(revision 15755)
+++ .settings/org.eclipse.jdt.ui.prefs	(working copy)
@@ -1,10 +1,71 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=true
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_modifiers=true
+cleanup.remove_redundant_semicolons=true
+cleanup.remove_redundant_type_arguments=false
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_autoboxing=false
+cleanup.use_blocks=false
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_unboxing=false
+cleanup_profile=_JOSM
 cleanup_settings_version=2
 eclipse.preferences.version=1
 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
-formatter_profile=_josm
-formatter_settings_version=12
+formatter_profile=_JOSM
+formatter_settings_version=16
 org.eclipse.jdt.ui.javadoc=false
-org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return the ${bare_field_name}\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} the ${bare_field_name} to set\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">// License\: GPL. \r\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\r\n * ${see_to_overridden}\r\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\r\n * ${tags}\r\n * ${see_to_target}\r\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">// License\: GPL. For details, see LICENSE file.\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\r\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\r\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\r\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\r\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter function" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return the ${bare_field_name}\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter function" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} the ${bare_field_name} to set\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="filecomment_context" deleted\="false" description\="Comment for created JavaScript files" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for vars" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding function" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding functions" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Jsdoc)\r\n * ${see_to_overridden}\r\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate functions" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\r\n * ${tags}\r\n * ${see_to_target}\r\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.classbody" name\="classbody">\r\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created function stubs" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated function stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">// License\: GPL. \n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">// License\: GPL. For details, see LICENSE file.\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter function" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter function" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="filecomment_context" deleted\="false" description\="Comment for created JavaScript files" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\n * \n */</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for vars" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding function" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding functions" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Jsdoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate functions" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created function stubs" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated function stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.wst.jsdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
 sp_cleanup.add_default_serial_version_id=true
 sp_cleanup.add_generated_serial_version_id=false
 sp_cleanup.add_missing_annotations=true
@@ -21,7 +82,7 @@
 sp_cleanup.convert_functional_interfaces=false
 sp_cleanup.convert_to_enhanced_for_loop=false
 sp_cleanup.correct_indentation=false
-sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code=true
 sp_cleanup.format_source_code_changes_only=true
 sp_cleanup.insert_inferred_type_arguments=false
 sp_cleanup.make_local_variable_final=false
@@ -39,6 +100,8 @@
 sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
 sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
 sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_modifiers=false
+sp_cleanup.remove_redundant_semicolons=false
 sp_cleanup.remove_redundant_type_arguments=false
 sp_cleanup.remove_trailing_whitespaces=true
 sp_cleanup.remove_trailing_whitespaces_all=true
Index: .settings/org.sonarlint.eclipse.core.prefs
===================================================================
--- .settings/org.sonarlint.eclipse.core.prefs	(revision 15755)
+++ .settings/org.sonarlint.eclipse.core.prefs	(working copy)
@@ -1,5 +1,4 @@
 autoEnabled=true
 eclipse.preferences.version=1
 extraProperties=
-moduleKey=josm
 serverId=josm
Index: build.xml
===================================================================
--- build.xml	(revision 15755)
+++ build.xml	(working copy)
@@ -503,51 +503,52 @@
         <attribute name="excludes" default="${default-junit@{testITsuffix}-excludes}"/>
         <sequential>
             <echo message="Running @{testfamily}@{testITsuffix} tests with JUnit"/>
-            <jacoco:coverage destfile="${test.dir}/jacoco@{testITsuffix}.exec" enabled="@{coverage}" includes="${jacoco.includes}"
-                inclbootstrapclasses="${jacoco.inclbootstrapclasses}" inclnolocationclasses="${jacoco.inclnolocationclasses}">
-                <junit printsummary="${junit.printsummary}" fork="true" forkmode="once" failureproperty="test.@{testfamily}@{testITsuffix}.failed">
-                    <jvmarg value="-Dfile.encoding=UTF-8"/>
-                    <jvmarg value="-javaagent:${test.dir}/lib/jmockit.jar"/>
-                    <jvmarg value="--add-modules" if:set="isJava9" unless:set="isJava11" />
-                    <jvmarg value="java.activation,java.se.ee" if:set="isJava9" unless:set="isJava11" />
-                    <jvmarg value="--add-exports" if:set="isJava9" unless:set="noJavaFX" />
-                    <jvmarg value="javafx.graphics/com.sun.javafx.application=ALL-UNNAMED" if:set="isJava9" unless:set="noJavaFX" />
-                    <jvmarg value="--add-exports" if:set="isJava9" unless:set="isJava11" />
-                    <jvmarg value="jdk.deploy/com.sun.deploy.config=ALL-UNNAMED" if:set="isJava9" unless:set="isJava11" />
-                    <jvmarg value="--add-opens" if:set="isJava9" />
-                    <jvmarg value="java.base/java.io=ALL-UNNAMED" if:set="isJava9" />
-                    <jvmarg value="--add-opens" if:set="isJava9" />
-                    <jvmarg value="java.base/java.lang=ALL-UNNAMED" if:set="isJava9" />
-                    <jvmarg value="--add-opens" if:set="isJava9" />
-                    <jvmarg value="java.base/java.nio=ALL-UNNAMED" if:set="isJava9" />
-                    <jvmarg value="--add-opens" if:set="isJava9" />
-                    <jvmarg value="java.base/java.text=ALL-UNNAMED" if:set="isJava9" />
-                    <jvmarg value="--add-opens" if:set="isJava9" />
-                    <jvmarg value="java.base/java.util=ALL-UNNAMED" if:set="isJava9" />
-                    <jvmarg value="--add-opens" if:set="isJava9" />
-                    <jvmarg value="java.base/jdk.internal.loader=ALL-UNNAMED" if:set="isJava9" />
-                    <jvmarg value="--add-opens" if:set="isJava9" />
-                    <jvmarg value="java.desktop/java.awt=ALL-UNNAMED" if:set="isJava9" />
-                    <sysproperty key="josm.home" value="${test.dir}/config/@{testfamily}-josm.home"/>
-                    <sysproperty key="josm.test.data" value="${test.dir}/data"/>
-                    <sysproperty key="java.awt.headless" value="${test.headless}"/>
-                    <sysproperty key="glass.platform" value="Monocle"/>
-                    <sysproperty key="monocle.platform" value="Headless"/>
-                    <sysproperty key="prism.order" value="sw"/>
-                    <sysproperty key="suppressPermanentFailure" value="${suppressPermanentFailure}"/>
-                    <classpath>
-                        <path refid="test.classpath"/>
-                        <pathelement path="${test.dir}/build/unit"/>
-                        <pathelement path="${test.dir}/build/@{testfamily}"/>
-                        <pathelement path="${test.dir}/config"/>
-                    </classpath>
-                    <formatter type="plain"/>
-                    <formatter type="xml"/>
-                    <batchtest fork="yes" todir="${test.dir}/report">
-                        <fileset dir="${test.dir}/build/@{testfamily}" includes="@{includes}" excludes="@{excludes}"/>
-                    </batchtest>
-                </junit>
-            </jacoco:coverage>
+            <jacoco:agent destfile="${test.dir}/jacoco@{testITsuffix}.exec" enabled="@{coverage}" includes="${jacoco.includes}" dumponexit="true"
+		    inclbootstrapclasses="${jacoco.inclbootstrapclasses}" inclnolocationclasses="${jacoco.inclnolocationclasses}" property="jacocoagent@{testfamily}@{testITsuffix}" />
+            <junitlauncher printsummary="${junit.printsummary}" failureproperty="test.@{testfamily}@{testITsuffix}.failed">
+                <classpath>
+                    <path refid="test.classpath"/>
+                    <pathelement path="${test.dir}/build/unit"/> <!-- required for functional/etc to have JOSMTestRules -->
+                    <pathelement path="${test.dir}/build/@{testfamily}"/>
+                </classpath>
+                <testclasses outputDir="${test.dir}/report">
+                    <fileset dir="${test.dir}/build/@{testfamily}" includes="@{includes}" excludes="@{excludes}"/>
+	                <fork>
+	                    <jvmarg value="${jacocoagent@{testfamily}@{testITsuffix}}" if:set="jacocoagent@{testfamily}@{testITsuffix}" />
+	                    <jvmarg value="-Dfile.encoding=UTF-8"/>
+	                    <jvmarg value="-javaagent:${test.dir}/lib/jmockit.jar"/>
+	                    <jvmarg value="--add-modules" if:set="isJava9" unless:set="isJava11" />
+	                    <jvmarg value="java.activation,java.se.ee" if:set="isJava9" unless:set="isJava11" />
+	                    <jvmarg value="--add-exports" if:set="isJava9" unless:set="noJavaFX" />
+	                    <jvmarg value="javafx.graphics/com.sun.javafx.application=ALL-UNNAMED" if:set="isJava9" unless:set="noJavaFX" />
+	                    <jvmarg value="--add-exports" if:set="isJava9" unless:set="isJava11" />
+	                    <jvmarg value="jdk.deploy/com.sun.deploy.config=ALL-UNNAMED" if:set="isJava9" unless:set="isJava11" />
+	                    <jvmarg value="--add-opens" if:set="isJava9" />
+	                    <jvmarg value="java.base/java.io=ALL-UNNAMED" if:set="isJava9" />
+	                    <jvmarg value="--add-opens" if:set="isJava9" />
+	                    <jvmarg value="java.base/java.lang=ALL-UNNAMED" if:set="isJava9" />
+	                    <jvmarg value="--add-opens" if:set="isJava9" />
+	                    <jvmarg value="java.base/java.nio=ALL-UNNAMED" if:set="isJava9" />
+	                    <jvmarg value="--add-opens" if:set="isJava9" />
+	                    <jvmarg value="java.base/java.text=ALL-UNNAMED" if:set="isJava9" />
+	                    <jvmarg value="--add-opens" if:set="isJava9" />
+	                    <jvmarg value="java.base/java.util=ALL-UNNAMED" if:set="isJava9" />
+	                    <jvmarg value="--add-opens" if:set="isJava9" />
+	                    <jvmarg value="java.base/jdk.internal.loader=ALL-UNNAMED" if:set="isJava9" />
+	                    <jvmarg value="--add-opens" if:set="isJava9" />
+	                    <jvmarg value="java.desktop/java.awt=ALL-UNNAMED" if:set="isJava9" />
+	                    <sysproperty key="josm.home" value="${test.dir}/config/@{testfamily}-josm.home"/>
+	                    <sysproperty key="josm.test.data" value="${test.dir}/data"/>
+	                    <sysproperty key="java.awt.headless" value="${test.headless}"/>
+	                    <sysproperty key="glass.platform" value="Monocle"/>
+	                    <sysproperty key="monocle.platform" value="Headless"/>
+	                    <sysproperty key="prism.order" value="sw"/>
+	                    <sysproperty key="suppressPermanentFailure" value="${suppressPermanentFailure}"/>
+	                </fork>
+                    <listener type="legacy-plain" />
+                    <listener type="legacy-xml" />
+                </testclasses>
+            </junitlauncher>
         </sequential>
     </macrodef>
     <target name="test" depends="test-compile" unless="test.notRequired"
@@ -658,11 +659,11 @@
 
         # Keep serialization code
         -keepclassmembers class * implements java.io.Serializable {
-            static final long serialVersionUID; 
+            static final long serialVersionUID;
             private static final java.io.ObjectStreamField[] serialPersistentFields;
             private void writeObject(java.io.ObjectOutputStream);
             private void readObject(java.io.ObjectInputStream);
-            java.lang.Object writeReplace(); 
+            java.lang.Object writeReplace();
             java.lang.Object readResolve();
         }
 
Index: data/validator/potentially_fixed.mapcss
===================================================================
--- data/validator/potentially_fixed.mapcss	(nonexistent)
+++ data/validator/potentially_fixed.mapcss	(working copy)
@@ -0,0 +1,16 @@
+/* Check for fixme's that have tag-value pairs */
+*[fixme][count(split(" ", tag("fixme"))) == 1][tag(tag("fixme")) != "none"]:modified {
+  throwWarning: tr("fixme is a tag which exists on the object, is the fixme fixed?");
+  assertNoMatch: "way fixme=name";
+  assertMatch: "way name=TODO fixme=name";
+  assertNoMatch: "way name=TODO fixme=\"name me\"";
+  assertNoMatch: "way name=TODO";
+}
+*[fixme][count(split(" ", tag("fixme"))) == 1][tag(tag("fixme")) != "none"]!:modified {
+  throwOther: tr("fixme is a tag which exists on the object, is the fixme fixed?");
+  assertNoMatch: "way fixme=name";
+  assertMatch: "way name=TODO fixme=name";
+  assertNoMatch: "way name=TODO fixme=\"name me\"";
+  assertNoMatch: "way name=TODO";
+}
+
Index: eclipse/JOSM (Java 8).launch
===================================================================
--- eclipse/JOSM (Java 8).launch	(revision 15755)
+++ eclipse/JOSM (Java 8).launch	(working copy)
@@ -1,16 +1,17 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/JOSM/src/org/openstreetmap/josm/gui/MainApplication.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
-<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;sourceLookupDirector&gt;&#13;&#10;&lt;sourceContainers duplicates=&quot;false&quot;&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;josm-atlas&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-DXFImport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM/test\/lib\/equalsverifier-2.4.4.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-apache-commons&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;classpathContainer path=&amp;quot;GROOVY_SUPPORT&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.classpathContainer&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-addrinterpolation&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-alignways&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-areaselector&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-buildings_tools&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-cadastre-fr&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-GeoTools&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/commons-beanutils-1.7.0.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/commons-pool-1.5.4.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/vecmath-1.3.2.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jsr-275-1.0-beta-2.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/hsqldb-2.2.8.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/imageio-ext-tiff-1.1.10.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/imageio-ext-utilities-1.1.10.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jai_codec-1.1.3.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jai_core-1.1.3.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jai_imageio-1.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jdom-1.1.3.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-contour-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-rangelookup-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-utils-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-vectorbinarize-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-vectorize-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-zonalstats-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-jts&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-jts/lib\/jts-1.13.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-canvec_helper&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-colorscheme&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-commandline&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-conflation&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-utilsplugin2&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-create_grid_of_ways&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-czechaddress&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-dataimport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-dataimport/lib\/jsr173-1.0_api.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-dataimport/lib\/jaxb-api.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-DirectDownload&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-DirectUpload&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-download_along&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-editgpx&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-ElevationProfile&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-EPCI-fr&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-ext_tools&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-FastDraw&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-FixAddresses&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-geochat&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-globalsat&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-gpsblam&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-gpxfilter&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-graphview&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-HouseNumberTaggingTool&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imagery_offset_db&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Imagery-XML-Bounds&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imageryadjust&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imagerycache&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imagewaypoint&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-ImportImage&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-log4j&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-log4j/lib\/log4j-1.2.17.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-importvec&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-InfoMode&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-irsrectify&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-junctionchecking&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-lakewalker&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-livegps&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-mapdust&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Measurement&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-merge-overlap&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-michigan_left&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-mirrored_download&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-namemanager&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-NanoLog&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-native-password-manager&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-OpenData&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-OpeningHoursEditor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-openvisible&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-osmarender&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-OsmInspectorPlugin&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-PBF&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-pdfimport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-photo_geotaging&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-photoadjust&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-piclayer&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-plastic_laf&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Poly&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-print&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-proj4j&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-public_transport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-reltoolbox&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Reverter&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-roadsigns&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-routes&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-routing&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-sds&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-SeaMapEditor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-SimplifyArea&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-surveyor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-tageditor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;josm-tagging-preset-tester&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-terracer&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-tracer&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-tracer2&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-trustosm&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-turnlanes&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-turnrestrictions&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;classpathContainer path=&amp;quot;GROOVY_DSL_SUPPORT&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.classpathContainer&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-undelete&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-videomapping&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-walkingpapers&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-waydownloader&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-waypoint_search&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-wayselector&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-wikipedia&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-wms-turbo-challenge2&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;default/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.debug.core.containerType.default&quot;/&gt;&#13;&#10;&lt;/sourceContainers&gt;&#13;&#10;&lt;/sourceLookupDirector&gt;&#13;&#10;"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.openstreetmap.josm.gui.MainApplication"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="--debug"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="JOSM"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xverify:none"/>
-</launchConfiguration>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+        <listEntry value="/JOSM/src/org/openstreetmap/josm/gui/MainApplication.java"/>
+    </listAttribute>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+        <listEntry value="1"/>
+    </listAttribute>
+    <stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
+    <stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;sourceLookupDirector&gt;&#13;&#10;&lt;sourceContainers duplicates=&quot;false&quot;&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;josm-atlas&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-DXFImport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM/test\/lib\/equalsverifier-2.4.4.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-apache-commons&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;classpathContainer path=&amp;quot;GROOVY_SUPPORT&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.classpathContainer&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-addrinterpolation&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-alignways&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-areaselector&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-buildings_tools&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-cadastre-fr&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-GeoTools&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/commons-beanutils-1.7.0.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/commons-pool-1.5.4.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/vecmath-1.3.2.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jsr-275-1.0-beta-2.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/hsqldb-2.2.8.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/imageio-ext-tiff-1.1.10.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/imageio-ext-utilities-1.1.10.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jai_codec-1.1.3.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jai_core-1.1.3.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jai_imageio-1.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jdom-1.1.3.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-contour-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-rangelookup-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-utils-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-vectorbinarize-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-vectorize-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-GeoTools/lib\/jt-zonalstats-1.3.1.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-jts&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-jts/lib\/jts-1.13.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-canvec_helper&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-colorscheme&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-commandline&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-conflation&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-utilsplugin2&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-create_grid_of_ways&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-czechaddress&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-dataimport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-dataimport/lib\/jsr173-1.0_api.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-dataimport/lib\/jaxb-api.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-DirectDownload&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-DirectUpload&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-download_along&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-editgpx&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-ElevationProfile&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-EPCI-fr&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-ext_tools&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-FastDraw&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-FixAddresses&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-geochat&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-globalsat&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-gpsblam&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-gpxfilter&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-graphview&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-HouseNumberTaggingTool&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imagery_offset_db&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Imagery-XML-Bounds&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imageryadjust&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imagerycache&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-imagewaypoint&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-ImportImage&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-log4j&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;packageFragmentRoot handle=&amp;quot;=JOSM-log4j/lib\/log4j-1.2.17.jar&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.packageFragmentRoot&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-importvec&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-InfoMode&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-irsrectify&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-junctionchecking&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-lakewalker&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-livegps&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-mapdust&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Measurement&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-merge-overlap&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-michigan_left&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-mirrored_download&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-namemanager&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-NanoLog&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-native-password-manager&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-OpenData&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-OpeningHoursEditor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-openvisible&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-osmarender&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-OsmInspectorPlugin&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-PBF&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-pdfimport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-photo_geotaging&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-photoadjust&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-piclayer&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-plastic_laf&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Poly&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-print&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-proj4j&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-public_transport&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-reltoolbox&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-Reverter&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-roadsigns&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-routes&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-routing&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-sds&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-SeaMapEditor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-SimplifyArea&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-surveyor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-tageditor&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;josm-tagging-preset-tester&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-terracer&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-tracer&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-tracer2&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-trustosm&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-turnlanes&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-turnrestrictions&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;classpathContainer path=&amp;quot;GROOVY_DSL_SUPPORT&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.classpathContainer&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-undelete&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-videomapping&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-walkingpapers&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-waydownloader&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-waypoint_search&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-wayselector&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-wikipedia&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;JOSM-wms-turbo-challenge2&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;default/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.debug.core.containerType.default&quot;/&gt;&#13;&#10;&lt;/sourceContainers&gt;&#13;&#10;&lt;/sourceLookupDirector&gt;&#13;&#10;"/>
+    <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+    <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+    <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.openstreetmap.josm.gui.MainApplication"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="--debug"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="JOSM"/>
+    <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xverify:none -Xmx4096M"/>
+</launchConfiguration>
Index: josm-latest.jnlp
===================================================================
--- josm-latest.jnlp	(revision 15755)
+++ josm-latest.jnlp	(working copy)
@@ -3,8 +3,8 @@
 <jnlp spec="6.0+" codebase="https://josm.openstreetmap.de/download/" href="josm-latest.jnlp">
     <information>
         <title>JOSM (development version)</title>
-        <vendor>OpenStreetMap</vendor> 
-        <homepage href="https://josm.openstreetmap.de"/> 
+        <vendor>OpenStreetMap</vendor>
+        <homepage href="https://josm.openstreetmap.de"/>
         <description>Java OpenStreetMap editor</description>
         <description kind="one-line">JOSM</description>
         <description kind="tooltip">JOSM</description>
@@ -15,6 +15,8 @@
             <desktop/>
             <menu/>
         </shortcut>
+        <association mime-type="text/xml" extensions="osm osc"/>
+        <association mime-type="text/plain" extensions="geojson"/>
     </information>
     <security>
         <all-permissions/>
Index: josm.jnlp
===================================================================
--- josm.jnlp	(revision 15755)
+++ josm.jnlp	(working copy)
@@ -3,18 +3,20 @@
 <jnlp spec="6.0+" codebase="https://josm.openstreetmap.de/download/" href="josm.jnlp">
     <information>
         <title>JOSM</title>
-        <vendor>OpenStreetMap</vendor> 
-        <homepage href="https://josm.openstreetmap.de"/> 
+        <vendor>OpenStreetMap</vendor>
+        <homepage href="https://josm.openstreetmap.de"/>
         <description>Java OpenStreetMap editor</description>
         <description kind="one-line">JOSM</description>
         <description kind="tooltip">JOSM</description>
         <icon href="https://josm.openstreetmap.de/logo.png" width="256" height="256"/>
-        <icon href="https://josm.openstreetmap.de/logo64.png" width="64" height="64" kind="shortcut"/> 
+        <icon href="https://josm.openstreetmap.de/logo64.png" width="64" height="64" kind="shortcut"/>
         <offline-allowed/>
         <shortcut>
             <desktop/>
             <menu/>
         </shortcut>
+        <association mime-type="text/xml" extensions="osm osc"/>
+        <association mime-type="text/plain" extensions="geojson"/>
     </information>
     <security>
         <all-permissions/>
Index: src/org/openstreetmap/josm/actions/ValidateAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ValidateAction.java	(revision 15755)
+++ src/org/openstreetmap/josm/actions/ValidateAction.java	(working copy)
@@ -114,6 +114,8 @@
         private boolean canceled;
         private List<TestError> errors;
 
+        private List<Class<? extends Test>> runTests;
+
         /**
          * Constructs a new {@code ValidationTask}
          * @param tests  the tests to run
@@ -151,32 +153,47 @@
         @Override
         protected void realRun() throws SAXException, IOException,
         OsmTransferException {
+            runTests = new ArrayList<>();
             if (tests == null || tests.isEmpty())
                 return;
             errors = new ArrayList<>(200);
             getProgressMonitor().setTicksCount(tests.size() * validatedPrimitives.size());
-            int testCounter = 0;
+            runTests(tests, 0);
+            tests = null;
+            if (Boolean.TRUE.equals(ValidatorPrefHelper.PREF_USE_IGNORE.get())) {
+                getProgressMonitor().setCustomText("");
+                getProgressMonitor().subTask(tr("Updating ignored errors ..."));
+                for (TestError error : errors) {
+                    if (canceled) return;
+                    error.updateIgnored();
+                }
+            }
+        }
+
+        protected int runTests(Collection<Test> tests, int testCounter) {
+            ArrayList<Test> remaining = new ArrayList<>();
             for (Test test : tests) {
                 if (canceled)
-                    return;
+                    return testCounter;
+                if (test.getAfterClass() != null && !runTests.contains(test.getAfterClass())) {
+                    remaining.add(test);
+                    continue;
+                }
                 testCounter++;
-                getProgressMonitor().setCustomText(tr("Test {0}/{1}: Starting {2}", testCounter, tests.size(), test.getName()));
+                getProgressMonitor().setCustomText(tr("Test {0}/{1}: Starting {2}", testCounter, this.tests.size(), test.getName()));
                 test.setPartialSelection(formerValidatedPrimitives != null);
+                test.setPreviousErrors(errors);
                 test.startTest(getProgressMonitor().createSubTaskMonitor(validatedPrimitives.size(), false));
                 test.visit(validatedPrimitives);
                 test.endTest();
                 errors.addAll(test.getErrors());
                 test.clear();
+                runTests.add(test.getClass());
             }
-            tests = null;
-            if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
-                getProgressMonitor().setCustomText("");
-                getProgressMonitor().subTask(tr("Updating ignored errors ..."));
-                for (TestError error : errors) {
-                    if (canceled) return;
-                    error.updateIgnored();
-                }
+            if (!remaining.isEmpty()) {
+                testCounter = runTests(remaining, testCounter);
             }
+            return testCounter;
         }
     }
 }
Index: src/org/openstreetmap/josm/command/AddPrimitivesCommand.java
===================================================================
--- src/org/openstreetmap/josm/command/AddPrimitivesCommand.java	(revision 15755)
+++ src/org/openstreetmap/josm/command/AddPrimitivesCommand.java	(working copy)
@@ -12,6 +12,7 @@
 import java.util.stream.Collectors;
 
 import javax.swing.Icon;
+import javax.swing.SwingUtilities;
 
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
@@ -112,7 +113,9 @@
             }
         }
         if (toSelect != null) {
-            ds.setSelected(toSelect.stream().map(ds::getPrimitiveById).collect(Collectors.toList()));
+            SwingUtilities.invokeLater(
+                    () -> ds.setSelected(toSelect.stream().map(ds::getPrimitiveById).filter(Objects::nonNull)
+                            .collect(Collectors.toList())));
         }
         return true;
     }
Index: src/org/openstreetmap/josm/data/gpx/GpxData.java
===================================================================
--- src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/gpx/GpxData.java	(working copy)
@@ -18,6 +18,7 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -78,7 +79,7 @@
      */
     private final ArrayList<GpxRoute> privateRoutes = new ArrayList<>();
     /**
-     * Addidionaly waypoints for this file.
+     * Additionally waypoints for this file.
      */
     private final ArrayList<WayPoint> privateWaypoints = new ArrayList<>();
     /**
@@ -96,6 +97,11 @@
     private boolean suppressedInvalidate;
 
     /**
+     * A list of tracks with an arbitrary max area
+     */
+    private final Map<Double, List<GpxTrack>> maxAreaTracks = new HashMap<>();
+
+    /**
      * Tracks. Access is discouraged, use {@link #getTracks()} to read.
      * @see #getTracks()
      */
@@ -1278,4 +1284,28 @@
             return true;
         }
     }
+
+    /**
+     * Get a list of tracks with a maximum number of points
+     * @param maxPoints the maximum number of points for each subtrack
+     * @return A list of tracks with a maximum number of points of maxPoints
+     */
+    public List<GpxTrack> getMaxAreaTracks(double maxPoints) {
+        if (!maxAreaTracks.containsKey(maxPoints)) {
+            List<GpxTrack> ttracks = new ArrayList<>();
+            Collection<WayPoint> tWayPoints = new TreeSet<>();
+
+            for (WayPoint point : getTrackPoints().collect(Collectors.toList())) {
+                tWayPoints.add(point);
+                if (tWayPoints.size() >= maxPoints) {
+                    Map<String, Object> emptyMap = Collections.emptyMap();
+                    Collection<Collection<WayPoint>> tCollection = new TreeSet<>();
+                    tCollection.add(tWayPoints);
+                    ttracks.add(new GpxTrack(tCollection, emptyMap));
+                }
+            }
+            maxAreaTracks.put(maxPoints, ttracks);
+        }
+        return maxAreaTracks.get(maxPoints);
+    }
 }
Index: src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
===================================================================
--- src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(working copy)
@@ -239,6 +239,8 @@
     private String origName;
     /** (original) language of the translated name entry */
     private String langName;
+    /** preferred source tag value (for changeset source) */
+    private String source;
     /** whether this is a entry activated by default or not */
     private boolean defaultEntry;
     /** Whether this service requires a explicit EULA acceptance before it can be activated */
@@ -363,6 +365,8 @@
         @StructEntry boolean transparent;
         @StructEntry int minimumTileExpire;
         @StructEntry String category;
+        @StructEntry
+        String source;
 
         /**
          * Constructs a new empty WMS {@code ImageryPreferenceEntry}.
@@ -399,6 +403,7 @@
             icon = i.icon;
             description = i.description;
             category = i.category != null ? i.category.getCategoryString() : null;
+            source = i.source;
             if (i.bounds != null) {
                 bounds = i.bounds.encodeAsString(",");
                 StringBuilder shapesString = new StringBuilder();
@@ -591,6 +596,7 @@
         transparent = e.transparent;
         minimumTileExpire = e.minimumTileExpire;
         category = ImageryCategory.fromString(e.category);
+        source = e.source;
     }
 
     /**
@@ -640,6 +646,7 @@
         this.minimumTileExpire = i.minimumTileExpire;
         this.categoryOriginalString = i.categoryOriginalString;
         this.category = i.category;
+        this.source = i.source;
     }
 
     @Override
@@ -695,7 +702,7 @@
                 Objects.equals(this.customHttpHeaders, other.customHttpHeaders) &&
                 Objects.equals(this.transparent, other.transparent) &&
                 Objects.equals(this.minimumTileExpire, other.minimumTileExpire) &&
-                Objects.equals(this.category, other.category);
+                Objects.equals(this.category, other.category) && Objects.equals(this.source, other.source);
         // CHECKSTYLE.ON: BooleanExpressionComplexity
     }
 
@@ -991,6 +998,26 @@
     }
 
     /**
+     * Returns the entry preferred source tag
+     *
+     * @return The preferred source tag. May be null or an empty string.
+     * @since xxx
+     */
+    public String getSource() {
+        return source;
+    }
+
+    /**
+     * Returns the entry preferred source tag
+     *
+     * @param source The preferred source tag for the source
+     * @since xxx
+     */
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    /**
      * Store the id of this info to the preferences and clear it afterwards.
      */
     public void clearId() {
@@ -1638,7 +1665,9 @@
                 // Retrieve english name, unfortunately not saved in preferences
                 Optional<ImageryInfo> infoEn = ImageryLayerInfo.allDefaultLayers.stream().filter(x -> id.equals(x.getId())).findAny();
                 if (infoEn.isPresent()) {
-                    return infoEn.get().getOriginalName();
+                    ImageryInfo info = infoEn.get();
+                    String sourceTag = info.getSource();
+                    return sourceTag == null || sourceTag.trim().isEmpty() ? info.getOriginalName() : sourceTag;
                 }
             }
             return getOriginalName();
Index: src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Node.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/osm/Node.java	(working copy)
@@ -385,7 +385,22 @@
 
     @Override
     public boolean isOutsideDownloadArea() {
-        if (isNewOrUndeleted() || getDataSet() == null)
+        return isOutsideDownloadArea(false);
+    }
+
+    /**
+     * Tests if this primitive lies outside of the downloaded area of its
+     * {@link DataSet}, possibly ignoring if the node is new or undeleted.
+     * 
+     * @param ignoreNewOrUndeleted if true, don't use
+     *                             {@link OsmPrimitive#isNewOrUndeleted} (if
+     *                             {@code true}, {@link Node#isOutsideDownloadArea}
+     *                             returns {@code false})
+     * @return {@code true} if this primitive lies outside of the downloaded area
+     * @see Node#isOutsideDownloadArea
+     */
+    public boolean isOutsideDownloadArea(boolean ignoreNewOrUndeleted) {
+        if ((!ignoreNewOrUndeleted && isNewOrUndeleted()) || getDataSet() == null)
             return false;
         Area area = getDataSet().getDataSourceArea();
         if (area == null)
Index: src/org/openstreetmap/josm/data/osm/SimplePrimitiveId.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/SimplePrimitiveId.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/osm/SimplePrimitiveId.java	(working copy)
@@ -148,4 +148,22 @@
     private static OsmPrimitiveType getOsmPrimitiveType(char firstChar) {
         return firstChar == 'n' ? OsmPrimitiveType.NODE : firstChar == 'w' ? OsmPrimitiveType.WAY : OsmPrimitiveType.RELATION;
     }
+
+    /**
+     * Convert a primitive to a simple id
+     *
+     * @param primitive The primitive to convert
+     * @return The type (may be n, w, or r, or something else) + the id (e.g., w42)
+     * @since xxx
+     */
+    public static String toSimpleId(IPrimitive primitive) {
+        if (primitive instanceof Relation) {
+            return "r" + primitive.getOsmId();
+        } else if (primitive instanceof Way) {
+            return "w" + primitive.getOsmId();
+        } else if (primitive instanceof Node) {
+            return "n" + primitive.getOsmId();
+        }
+        return primitive.getType().toString() + primitive.getOsmId();
+    }
 }
Index: src/org/openstreetmap/josm/data/validation/OsmValidator.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/validation/OsmValidator.java	(working copy)
@@ -60,6 +60,7 @@
 import org.openstreetmap.josm.data.validation.tests.PublicTransportRouteTest;
 import org.openstreetmap.josm.data.validation.tests.RelationChecker;
 import org.openstreetmap.josm.data.validation.tests.RightAngleBuildingTest;
+import org.openstreetmap.josm.data.validation.tests.RoutingIslandsTest;
 import org.openstreetmap.josm.data.validation.tests.SelfIntersectingWay;
 import org.openstreetmap.josm.data.validation.tests.SharpAngles;
 import org.openstreetmap.josm.data.validation.tests.SimilarNamedWays;
@@ -149,6 +150,7 @@
         PublicTransportRouteTest.class, // 3600 .. 3699
         RightAngleBuildingTest.class, // 3700 .. 3799
         SharpAngles.class, // 3800 .. 3899
+        RoutingIslandsTest.class, // 3900 .. 3999
     };
 
     /**
Index: src/org/openstreetmap/josm/data/validation/Test.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/Test.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/validation/Test.java	(working copy)
@@ -46,6 +46,9 @@
     /** Name of the test */
     protected final String name;
 
+    /** Test to run after */
+    protected Class<? extends Test> afterTest;
+
     /** Description of the test */
     protected final String description;
 
@@ -67,6 +70,9 @@
     /** The list of errors */
     protected List<TestError> errors = new ArrayList<>(30);
 
+    /** The list of previously found errors */
+    protected List<TestError> previousErrors;
+
     /** Whether the test is run on a partial selection data */
     protected boolean partialSelection;
 
@@ -84,8 +90,21 @@
      * @param description Description of the test
      */
     public Test(String name, String description) {
+        this(name, description, null);
+    }
+
+    /**
+     * Constructor
+     * @param name Name of the test
+     * @param description Description of the test
+     * @param afterTest Ensure the test is run after a test with this name
+     *
+     * @since xxx
+     */
+    public Test(String name, String description, Class<? extends Test> afterTest) {
         this.name = name;
         this.description = description;
+        this.afterTest = afterTest;
     }
 
     /**
@@ -187,6 +206,15 @@
     }
 
     /**
+     * Set the validation errors accumulated by other tests until this moment
+     * For validation errors accumulated by this test, use {@code getErrors()}
+     * @param errors The errors from previous tests
+     */
+    public void setPreviousErrors(List<TestError> errors) {
+        previousErrors = errors;
+    }
+
+    /**
      * Notification of the end of the test. The tester may perform additional
      * actions and destroy the used structures.
      * <p>
@@ -326,6 +354,16 @@
     }
 
     /**
+     * Get the class that the test must run after
+     * @return A class that extends {@code Test}
+     *
+     * @since xxx
+     */
+    public Class<? extends Test> getAfterClass() {
+        return afterTest;
+    }
+
+    /**
      * Determines if the test has been canceled.
      * @return {@code true} if the test has been canceled, {@code false} otherwise
      */
Index: src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java	(working copy)
@@ -16,6 +16,7 @@
 import org.openstreetmap.josm.data.validation.Severity;
 import org.openstreetmap.josm.data.validation.Test;
 import org.openstreetmap.josm.data.validation.TestError;
+import org.openstreetmap.josm.tools.Access;
 import org.openstreetmap.josm.tools.LanguageInfo;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.SubclassFilteredCollection;
@@ -30,13 +31,8 @@
     private static final Set<String> RESTRICTION_TYPES = new HashSet<>(Arrays.asList("oneway", "toll", "noexit", "maxspeed", "minspeed",
             "maxstay", "maxweight", "maxaxleload", "maxheight", "maxwidth", "maxlength", "overtaking", "maxgcweight", "maxgcweightrating",
             "fee", "restriction", "interval", "duration"));
-    private static final Set<String> RESTRICTION_VALUES = new HashSet<>(Arrays.asList("yes", "official", "designated", "destination",
-            "delivery", "customers", "permissive", "private", "agricultural", "forestry", "no"));
-    private static final Set<String> TRANSPORT_MODES = new HashSet<>(Arrays.asList("access", "foot", "ski", "inline_skates", "ice_skates",
-            "horse", "vehicle", "bicycle", "carriage", "trailer", "caravan", "motor_vehicle", "motorcycle", "moped", "mofa",
-            "motorcar", "motorhome", "psv", "bus", "taxi", "tourist_bus", "goods", "hgv", "agricultural", "atv", "snowmobile",
-            "hgv_articulated", "ski:nordic", "ski:alpine", "ski:telemark", "coach", "golf_cart"
-            /*,"minibus","share_taxi","hov","car_sharing","emergency","hazmat","disabled"*/));
+    private static final Set<String> RESTRICTION_VALUES = Access.getRestrictionValues();
+    private static final Set<String> TRANSPORT_MODES = Access.getTransportModes();
 
     private static final Pattern CONDITIONAL_PATTERN;
     static {
Index: src/org/openstreetmap/josm/data/validation/tests/ConnectivityRelationCheck.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/ConnectivityRelationCheck.java	(nonexistent)
+++ src/org/openstreetmap/josm/data/validation/tests/ConnectivityRelationCheck.java	(working copy)
@@ -0,0 +1,178 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.validation.tests;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.validation.Severity;
+import org.openstreetmap.josm.data.validation.Test;
+import org.openstreetmap.josm.data.validation.TestError;
+
+/**
+ * Check for inconsistencies in lane information between relation and members.
+ */
+public class ConnectivityRelationCheck extends Test {
+
+    protected static final int INCONSISTENT_LANE_COUNT = 3900;
+
+    protected static final int UNKNOWN_CONNECTIVITY_ROLE = INCONSISTENT_LANE_COUNT + 1;
+
+    protected static final int NO_CONNECTIVITY_TAG = INCONSISTENT_LANE_COUNT + 2;
+
+    protected static final int TOO_MANY_ROLES = INCONSISTENT_LANE_COUNT + 3;
+
+    private static final String CONNECTIVITY_TAG = "connectivity";
+    private static final String VIA = "via";
+    private static final String TO = "to";
+    private static final String FROM = "from";
+
+    /**
+    * Constructor
+    */
+    public ConnectivityRelationCheck() {
+        super(tr("Connectivity Relation Check"), tr("Checks that lane count of relation matches with lanes of members"));
+    }
+
+    /**
+     * Convert the connectivity tag into a map of values
+     *
+     * @param relation A relation with a {@code connectivity} tag.
+     * @return A Map in the form of {@code Map<Lane From, Map<Lane To, Optional>>}
+     * @since xxx
+     */
+    public static Map<Integer, Map<Integer, Boolean>> parseConnectivityTag(Relation relation) {
+        final String joined = relation.get(CONNECTIVITY_TAG);
+
+        if (joined == null) {
+            return new TreeMap<>();
+        }
+
+        final Map<Integer, Map<Integer, Boolean>> result = new HashMap<>();
+        String[] lanes = joined.split("\\|", -1);
+        for (int i = 0; i < lanes.length; i++) {
+            String[] lane = lanes[i].split(":", -1);
+            int laneNumber = Integer.parseInt(lane[0].trim());
+            Map<Integer, Boolean> connections = new HashMap<>();
+            String[] toLanes = Pattern.compile("\\p{Zs}*[,:;]\\p{Zs}*").split(lane[1]);
+            for (int j = 0; j < toLanes.length; j++) {
+                String toLane = toLanes[j].trim();
+                if (Pattern.compile("\\([0-9]+\\)").matcher(toLane).matches()) {
+                    toLane = toLane.replace("(", "").replace(")", "").trim();
+                    connections.put(Integer.parseInt(toLane), true);
+                } else {
+                    connections.put(Integer.parseInt(toLane), false);
+                }
+            }
+            result.put(laneNumber, connections);
+        }
+        return result;
+    }
+
+    @Override
+    public void visit(Relation r) {
+        if (r.hasTag("type", CONNECTIVITY_TAG)) {
+            if (!r.hasKey(CONNECTIVITY_TAG)) {
+                errors.add(TestError.builder(this, Severity.WARNING, NO_CONNECTIVITY_TAG)
+                        .message(tr("No connectivity tag in connectivity relation")).primitives(r).build());
+            } else if (!r.hasIncompleteMembers()) {
+                boolean badRole = checkForBadRole(r);
+                if (!badRole)
+                    checkForInconsistentLanes(r);
+            }
+        }
+    }
+
+    private void checkForInconsistentLanes(Relation relation) {
+        // Lane count from connectivity tag
+        Map<Integer, Map<Integer, Boolean>> connTagLanes = parseConnectivityTag(relation);
+        // Lane count from member tags
+        Map<String, Integer> roleLanes = new HashMap<>();
+
+        for (RelationMember rM : relation.getMembers()) {
+            // Check lanes
+            if (rM.getType() == OsmPrimitiveType.WAY) {
+                OsmPrimitive prim = rM.getMember();
+                if (prim.hasKey("lanes") && !rM.getRole().equals(VIA)) {
+                    roleLanes.put(rM.getRole(), Integer.parseInt(prim.get("lanes")));
+                }
+            }
+        }
+        boolean fromCheck = roleLanes.get(FROM) < Collections
+                .max(connTagLanes.entrySet(), Comparator.comparingInt(Map.Entry::getKey)).getKey();
+        boolean toCheck = false;
+        for (Entry<Integer, Map<Integer, Boolean>> to : connTagLanes.entrySet()) {
+            toCheck = roleLanes.get(TO) < Collections
+                    .max(to.getValue().entrySet(), Comparator.comparingInt(Map.Entry::getKey)).getKey();
+        }
+        if (fromCheck || toCheck) {
+            errors.add(TestError.builder(this, Severity.WARNING, INCONSISTENT_LANE_COUNT)
+                    .message(tr("Inconsistent lane numbering between relation and members")).primitives(relation)
+                    .build());
+        }
+    }
+
+    private boolean checkForBadRole(Relation relation) {
+        // Check role names
+        int viaWays = 0;
+        int viaNodes = 0;
+        int toWays = 0;
+        int fromWays = 0;
+        for (RelationMember relationMember : relation.getMembers()) {
+            if (relationMember.getMember() instanceof Way) {
+                if (relationMember.hasRole(FROM))
+                    fromWays++;
+                else if (relationMember.hasRole(TO))
+                    toWays++;
+                else if (relationMember.hasRole(VIA))
+                    viaWays++;
+                else {
+                    createUnknownRole(relation, relationMember.getMember());
+                    return true;
+                }
+            } else if (relationMember.getMember() instanceof Node) {
+                if (!relationMember.hasRole(VIA)) {
+                    createUnknownRole(relation, relationMember.getMember());
+                    return true;
+                }
+                viaNodes++;
+            }
+        }
+        return mixedViaNodeAndWay(relation, viaWays, viaNodes, toWays, fromWays);
+    }
+
+    private boolean mixedViaNodeAndWay(Relation relation, int viaWays, int viaNodes, int toWays, int fromWays) {
+        String message = "";
+        if ((viaWays != 0 && viaNodes != 0) || viaNodes > 1) {
+            message = tr("Relation contains {1} {0} roles.", VIA, viaWays + viaNodes);
+        } else if (toWays != 1) {
+            message = tr("Relation contains too many {0} roles", TO);
+        } else if (fromWays != 1) {
+            message = tr("Relation contains too many {0} roles", FROM);
+        }
+        if (message.isEmpty()) {
+            return false;
+        } else {
+            errors.add(TestError.builder(this, Severity.WARNING, TOO_MANY_ROLES)
+                    .message(message).primitives(relation).build());
+            return true;
+        }
+    }
+
+    private void createUnknownRole(Relation relation, OsmPrimitive primitive) {
+        errors.add(TestError.builder(this, Severity.WARNING, UNKNOWN_CONNECTIVITY_ROLE)
+                .message(tr("Unkown role in connectivity relation")).primitives(relation).highlight(primitive).build());
+    }
+}
Index: src/org/openstreetmap/josm/data/validation/tests/Highways.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/Highways.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/validation/tests/Highways.java	(working copy)
@@ -38,6 +38,7 @@
     protected static final int SOURCE_MAXSPEED_CONTEXT_MISMATCH_VS_MAXSPEED = 2705;
     protected static final int SOURCE_MAXSPEED_CONTEXT_MISMATCH_VS_HIGHWAY = 2706;
     protected static final int SOURCE_WRONG_LINK = 2707;
+    protected static final int ROUNDABOUT_CONNECTIONS_COUNT = 2708;
 
     protected static final String SOURCE_MAXSPEED = "source:maxspeed";
 
@@ -68,6 +69,7 @@
     private int pedestrianWays;
     private int cyclistWays;
     private int carsWays;
+    private final Set<Node> connectionNodesComplained = new HashSet<>();
 
     /**
      * Constructs a new {@code Highways} test.
@@ -77,6 +79,18 @@
     }
 
     @Override
+    public void initialize() throws Exception {
+        super.initialize();
+        connectionNodesComplained.clear();
+    }
+
+    @Override
+    public void endTest() {
+        connectionNodesComplained.clear();
+        super.endTest();
+    }
+
+    @Override
     public void visit(Node n) {
         if (n.isUsable()) {
             if (!n.hasTag("crossing", "no")
@@ -96,10 +110,12 @@
     @Override
     public void visit(Way w) {
         if (w.isUsable()) {
-            if (w.isClosed() && w.hasTag(HIGHWAY, CLASSIFIED_HIGHWAYS) && w.hasTag("junction", "circular", "roundabout")
-                    && IN_DOWNLOADED_AREA_STRICT.test(w)) {
-                // TODO: find out how to handle splitted roundabouts (see #12841)
-                testWrongRoundabout(w);
+            if (isRoundabout(w) && w.hasTag(HIGHWAY, CLASSIFIED_HIGHWAYS) && IN_DOWNLOADED_AREA_STRICT.test(w)) {
+                if (w.isClosed()) {
+                    // TODO: find out how to handle split roundabouts (see #12841)
+                    testWrongRoundabout(w);
+                }
+                testRoundaboutConnections(w, connectionNodesComplained);
             }
             if (w.hasKey(SOURCE_MAXSPEED)) {
                 // Check maxspeed, including context against highway
@@ -109,6 +125,50 @@
         }
     }
 
+    /**
+     * Find nodes in roundabout with more than one connected highway
+     * @param w
+     * @param complained
+     */
+    private void testRoundaboutConnections(Way w, Set<Node> complained) {
+        List<OsmPrimitive> primitives = new ArrayList<>();
+        for (Node n : w.getNodes()) {
+            if (complained.contains(n))
+                continue;
+            int countConnectedArcs = 0;
+            primitives.clear();
+            for (Way p : n.getParentWays()) {
+                if (p == w || !p.isUsable() || isRoundabout(p) || !p.hasTag(HIGHWAY, CLASSIFIED_HIGHWAYS))
+                    continue;
+
+                primitives.add(p);
+                if (!p.isFirstLastNode(n)) {
+                    errors.add(TestError.builder(this, Severity.WARNING, ROUNDABOUT_CONNECTIONS_COUNT)
+                            .message(tr("Highway doesn't start or end at roundabout"))
+                            .primitives(Arrays.asList(p,w,n))
+                            .highlight(n)
+                            .build());
+                    complained.add(n);
+                }
+                countConnectedArcs++;
+            }
+            if (countConnectedArcs > 1) {
+                primitives.add(w);
+                primitives.add(n);
+                errors.add(TestError.builder(this, Severity.WARNING, ROUNDABOUT_CONNECTIONS_COUNT)
+                        .message(tr("Multiple highways connected in one node of a roundabout"))
+                        .primitives(new ArrayList<>(primitives))
+                        .highlight(n)
+                        .build());
+                complained.add(n);
+            }
+        }
+    }
+
+    private static boolean isRoundabout(Way w) {
+        return w.hasTag("junction", "circular", "roundabout");
+    }
+
     private void testWrongRoundabout(Way w) {
         Map<String, List<Way>> map = new HashMap<>();
         // Count all highways (per type) connected to this roundabout, except correct links
@@ -190,7 +250,7 @@
             // in roundabout designs that physically separate a specific turn from the main roundabout
             // But if we have more than a single adjacent class, and one of them is a roundabout, that's an error
             for (Way w : sameClass) {
-                if (w.hasTag("junction", "circular", "roundabout")) {
+                if (isRoundabout(w)) {
                     return false;
                 }
             }
Index: src/org/openstreetmap/josm/data/validation/tests/IntersectionIssues.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/IntersectionIssues.java	(nonexistent)
+++ src/org/openstreetmap/josm/data/validation/tests/IntersectionIssues.java	(working copy)
@@ -0,0 +1,387 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.validation.tests;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.data.validation.Severity;
+import org.openstreetmap.josm.data.validation.Test;
+import org.openstreetmap.josm.data.validation.TestError;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.tools.Geometry;
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Finds issues with highway intersections
+ * @author Taylor Smock
+ * @since xxx
+ */
+public class IntersectionIssues extends Test {
+    private static final int INTERSECTIONISSUESCODE = 3900;
+    /** The code for an intersection which briefly interrupts a road */
+    public static final int SHORT_DISCONNECT = INTERSECTIONISSUESCODE + 0;
+    /** The code for a node that is almost on a way */
+    public static final int NEARBY_NODE = INTERSECTIONISSUESCODE + 1;
+    /** The distance to consider for nearby nodes/short disconnects */
+    public static final double MAX_DISTANCE = 5.0; // meters
+    /** The distance to consider for nearby nodes with tags */
+    public static final double MAX_DISTANCE_NODE_INFORMATION = MAX_DISTANCE / 5.0; // meters
+    /** The maximum angle for almost overlapping ways */
+    public static final double MAX_ANGLE = 15.0; // degrees
+    /** The maximum distance to consider for almost overlapping ways.
+     * Please note that lane width should be at least 2.6m (if it is a full-size lane) */
+    public static final double MAX_DISTANCE_OVERLAPPING = 1.0; // meters
+
+    private HashMap<String, ArrayList<Way>> ways;
+    ArrayList<Way> allWays;
+
+    /**
+     * Construct a new {@code IntersectionIssues} object
+     */
+    public IntersectionIssues() {
+        super(tr("Intersection Issues"), tr("Check for issues at intersections"), OverlappingWays.class);
+    }
+
+    @Override
+    public void startTest(ProgressMonitor monitor) {
+        super.startTest(monitor);
+        ways = new HashMap<>();
+        allWays = new ArrayList<>();
+    }
+
+    @Override
+    public void endTest() {
+        Way pWay = null;
+        try {
+            for (ArrayList<Way> comparison : ways.values()) {
+                pWay = comparison.get(0);
+                checkNearbyEnds(comparison);
+            }
+            for (Way way : allWays) {
+                pWay = way;
+                for (Way way2 : allWays) {
+                    if (way2.equals(way)) continue;
+                    pWay = way2;
+                    if (way.getBBox().intersects(way2.getBBox())) {
+                        checkNearbyNodes(way, way2);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            if (pWay != null) {
+                Logging.debug("Way https://osm.org/way/{0} caused an error", pWay.getOsmId());
+            }
+            Logging.warn(e);
+        }
+        ways = null;
+        allWays = null;
+        super.endTest();
+    }
+
+    @Override
+    public void visit(Way way) {
+        if (!way.isUsable()) return;
+        String highway = "highway";
+        if (way.hasKey(highway) && !way.get(highway).contains("_link") &&
+                !way.hasTag(highway, "proposed") && !way.hasTag(highway, "services")) {
+            for (String tag : Arrays.asList("name", "ref")) {
+                if (way.hasKey(tag)) {
+                    ArrayList<Way> similar = ways.get(way.get(tag)) == null ? new ArrayList<>() : ways.get(way.get(tag));
+                    if (!similar.contains(way)) similar.add(way);
+                    ways.put(way.get(tag), similar);
+                }
+            }
+            if (!allWays.contains(way)) allWays.add(way);
+        }
+    }
+
+    /**
+     * Check for ends that are nearby but not directly connected
+     * @param comparison Ways to look at
+     */
+    public void checkNearbyEnds(List<Way> comparison) {
+        ArrayList<Way> errored = new ArrayList<>();
+        for (Way one : comparison) {
+            LatLon oneLast = one.lastNode().getCoor();
+            LatLon oneFirst = one.firstNode().getCoor();
+            for (Way two : comparison) {
+                if (one.equals(two) || one.isFirstLastNode(two.firstNode())
+                        || one.isFirstLastNode(two.lastNode()) ||
+                        (errored.contains(one) && errored.contains(two))) continue;
+                LatLon twoLast = two.lastNode().getCoor();
+                LatLon twoFirst = two.firstNode().getCoor();
+                int nearCase = getNearCase(oneFirst, oneLast, twoFirst, twoLast);
+                if (nearCase == 8 && (two.firstNode().hasTag("noexit") && two.firstNode().get("noexit").equals("yes"))) {
+                    continue;
+                }
+                if (nearCase != 0 && !checkForConnection(one, two, nearCase)) {
+                    createCheckNearbyEndsError(nearCase, errored, one, two);
+                    return;
+                }
+            }
+        }
+    }
+
+    // 8421 -> twoFirst/oneFirst, twoFirst/oneLast, twoLast/oneFirst, twoLast/oneLast
+    private boolean checkForConnection(Way one, Way two, int nearCase) {
+        List<Node> nodes = new ArrayList<>();
+        if ((nearCase & 1) == 1) {
+            nodes.add(one.lastNode());
+            nodes.add(two.lastNode());
+        }
+        if ((nearCase & 2) == 2) {
+            nodes.add(one.firstNode());
+            nodes.add(two.lastNode());
+        }
+        if ((nearCase & 4) == 4) {
+            nodes.add(one.lastNode());
+            nodes.add(two.firstNode());
+        }
+        if ((nearCase & 8) == 8) {
+            nodes.add(one.firstNode());
+            nodes.add(two.firstNode());
+        }
+        for (Node node : nodes) {
+            Collection<Way> parents = node.getParentWays();
+            parents.remove(one);
+            parents.remove(two);
+            for (Way way : parents) {
+                if ((one.hasKey("name") && way.hasKey("name") && way.get("name").equals(one.get("name"))) ||
+                        (one.hasKey("ref") && way.hasKey("ref") && way.get("ref").equals(one.get("ref")))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if an exception is found
+     * @param nodes Nodes that may be parts of roundabouts or other exceptions.
+     * @return true if an exception is found
+     */
+    private boolean checkForExceptions(Node... nodes) {
+        Collection<String> exceptions = new HashSet<>();
+        exceptions.add("junction");
+        for (Node node : nodes) {
+            for (Way way : Utils.filteredCollection(node.getReferrers(), Way.class)) {
+                for (String exceptionKey : exceptions) {
+                    if (way.hasKey(exceptionKey)) return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void createCheckNearbyEndsError(int nearCase, List<Way> errored, Way one, Way two) {
+        if (nearCase <= 0) return;
+        List<Way> nearby = new ArrayList<>();
+        nearby.add(one);
+        nearby.add(two);
+        List<WaySegment> segments = new ArrayList<>();
+        if ((nearCase & 1) != 0) {
+            if (checkForExceptions(one.lastNode(), two.lastNode())) return;
+            segments.add(new WaySegment(two, two.getNodesCount() - 2));
+            segments.add(new WaySegment(one, one.getNodesCount() - 2));
+        }
+        if ((nearCase & 2) != 0) {
+            if (checkForExceptions(two.lastNode(), one.firstNode())) return;
+            segments.add(new WaySegment(two, two.getNodesCount() - 2));
+            segments.add(new WaySegment(one, 0));
+        }
+        if ((nearCase & 4) != 0) {
+            if (checkForExceptions(two.firstNode(), one.lastNode())) return;
+            segments.add(new WaySegment(two, 0));
+            segments.add(new WaySegment(one, one.getNodesCount() - 2));
+        }
+        if ((nearCase & 8) != 0) {
+            if (checkForExceptions(two.firstNode(), one.firstNode())) return;
+            segments.add(new WaySegment(two, 0));
+            segments.add(new WaySegment(one, 0));
+        }
+        errored.addAll(nearby);
+        allWays.removeAll(errored);
+        TestError.Builder testError = TestError.builder(this, Severity.WARNING, SHORT_DISCONNECT)
+                .primitives(nearby)
+                .highlightWaySegments(segments)
+                .message(tr("Disconnected road"));
+        errors.add(testError.build());
+    }
+
+    /**
+     * Get nearby cases
+     * @param oneFirst The {@code LatLon} of the the first node of the first way
+     * @param oneLast The {@code LatLon} of the the last node of the first way
+     * @param twoFirst The {@code LatLon} of the the first node of the second way
+     * @param twoLast The {@code LatLon} of the the last node of the second way
+     * @return A bitwise int (8421 -> twoFirst/oneFirst, twoFirst/oneLast, twoLast/oneFirst, twoLast/oneLast)
+     *
+     */
+    private int getNearCase(LatLon oneFirst, LatLon oneLast, LatLon twoFirst, LatLon twoLast) {
+        int returnInt = 0;
+        if (twoLast.greatCircleDistance(oneLast) <= MAX_DISTANCE) {
+            returnInt = returnInt | 1;
+        }
+        if (twoLast.greatCircleDistance(oneFirst) <= MAX_DISTANCE) {
+            returnInt = returnInt | 2;
+        }
+        if (twoFirst.greatCircleDistance(oneLast) <= MAX_DISTANCE) {
+            returnInt = returnInt | 4;
+        }
+        if (twoFirst.greatCircleDistance(oneFirst) <= MAX_DISTANCE) {
+            returnInt = returnInt | 8;
+        }
+        return returnInt;
+    }
+
+    /**
+     * Check nearby nodes to an intersection of two ways
+     * @param way1 A way to check an almost intersection with
+     * @param way2 A way to check an almost intersection with
+     */
+    public void checkNearbyNodes(Way way1, Way way2) {
+        Collection<Node> intersectingNodes = getIntersectingNode(way1, way2);
+        if (intersectingNodes.isEmpty() ||
+                (way1.isOneway() != 0 && way2.isOneway() != 0 &&
+                ((way1.hasKey("name") && way1.get("name").equals(way2.get("name"))) ||
+                 (way1.hasKey("ref") && way1.get("ref").equals(way2.get("ref")))))) return;
+        for (Node intersectingNode : intersectingNodes) {
+            checkNearbyNodes(way1, way2, intersectingNode);
+            checkNearbyNodes(way2, way1, intersectingNode);
+        }
+    }
+
+    private void checkNearbyNodes(Way way1, Way way2, Node nearby) {
+        for (Node node : way1.getNeighbours(nearby)) {
+            if (node.equals(nearby) || way2.containsNode(node)) continue;
+            double distance = Geometry.getDistance(way2, node);
+            double angle = getSmallestAngle(way2, nearby, node);
+            if (((distance < MAX_DISTANCE && !node.isTagged())
+                    || (distance < MAX_DISTANCE_NODE_INFORMATION && node.isTagged()))
+                    && angle < MAX_ANGLE) {
+                List<Way> primitiveIssues = new ArrayList<>();
+                primitiveIssues.add(way1);
+                primitiveIssues.add(way2);
+                if (alreadyFoundInRelevantTest(primitiveIssues)) return;
+
+                List<WaySegment> waysegmentsOne = buildWaySegmentAroundNode(way1, nearby);
+                List<WaySegment> waysegmentsTwo = buildWaySegmentAroundNode(way2, nearby);
+                List<WaySegment> waysegments = new ArrayList<>();
+                Node twoNear = null;
+                Node oneNear = null;
+                for (WaySegment twoSegment : waysegmentsTwo) {
+                    if (angle == getSmallestAngle(twoSegment.toWay(), nearby, node)) {
+                        waysegments.add(twoSegment);
+                        twoNear = getNearNode(twoSegment, nearby);
+                        break;
+                    }
+                }
+                for (WaySegment oneSegment: waysegmentsOne) {
+                    if (oneSegment.toWay().containsNode(node)) {
+                        waysegments.add(oneSegment);
+                        oneNear = getNearNode(oneSegment, nearby);
+                        break;
+                    }
+                }
+                if (waysegments.size() >= 2) {
+                    double distance1 = Geometry.getDistance(waysegments.get(0).toWay(), twoNear);
+                    double distance2 = Geometry.getDistance(waysegments.get(1).toWay(), oneNear);
+                    if (Math.min(distance1, distance2) < MAX_DISTANCE_OVERLAPPING)
+                        createNearlyOverlappingError(primitiveIssues, waysegments);
+                }
+            }
+        }
+    }
+
+    private void createNearlyOverlappingError(Collection<? extends OsmPrimitive> primitiveIssues, Collection<WaySegment> waysegments) {
+        TestError.Builder testError = TestError.builder(this, Severity.WARNING, NEARBY_NODE)
+                .primitives(primitiveIssues)
+                .highlightWaySegments(waysegments)
+                .message(tr("Nearly overlapping ways"));
+        errors.add(testError.build());
+    }
+
+    private Node getNearNode(WaySegment segment, Node nearby) {
+        return segment.getFirstNode() != nearby ? segment.getFirstNode() : segment.getSecondNode();
+    }
+
+    private List<WaySegment> buildWaySegmentAroundNode(Way way, Node node) {
+        List<WaySegment> waysegments = new ArrayList<>();
+        int index = way.getNodes().indexOf(node);
+        if (index >= way.getNodesCount() - 1) index--;
+        waysegments.add(new WaySegment(way, index));
+        if (index > 0) waysegments.add(new WaySegment(way, index - 1));
+        return waysegments;
+    }
+
+    private boolean alreadyFoundInRelevantTest(Collection<? extends OsmPrimitive> primitiveIssues) {
+        List<TestError> tErrors = new ArrayList<>();
+        if (previousErrors != null) tErrors.addAll(previousErrors);
+        tErrors.addAll(getErrors());
+        for (TestError error : tErrors) {
+            int code = error.getCode();
+            if ((code == SHORT_DISCONNECT || code == NEARBY_NODE
+                    || code == OverlappingWays.OVERLAPPING_HIGHWAY
+                    || code == OverlappingWays.DUPLICATE_WAY_SEGMENT
+                    || code == OverlappingWays.OVERLAPPING_HIGHWAY_AREA
+                    || code == OverlappingWays.OVERLAPPING_WAY
+                    || code == OverlappingWays.OVERLAPPING_WAY_AREA
+                    || code == OverlappingWays.OVERLAPPING_RAILWAY
+                    || code == OverlappingWays.OVERLAPPING_RAILWAY_AREA)
+                    && primitiveIssues.containsAll(error.getPrimitives())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get the intersecting node of two ways
+     * @param way1 A way that (hopefully) intersects with way2
+     * @param way2 A way to find an intersection with
+     * @return A collection of nodes where the ways intersect
+     */
+    public Collection<Node> getIntersectingNode(Way way1, Way way2) {
+        HashSet<Node> nodes = new HashSet<>();
+        for (Node node : way1.getNodes()) {
+            if (way2.containsNode(node)) {
+                nodes.add(node);
+            }
+        }
+        return nodes;
+    }
+
+    /**
+     * Get the corner angle between nodes
+     * @param way The way with additional nodes
+     * @param intersection The node to get angles around
+     * @param comparison The node to get angles from
+     * @return The angle for comparison->intersection->(additional node) (normalized degrees)
+     */
+    public double getSmallestAngle(Way way, Node intersection, Node comparison) {
+        Set<Node> neighbours = way.getNeighbours(intersection);
+        double angle = Double.MAX_VALUE;
+        EastNorth eastNorthIntersection = intersection.getEastNorth();
+        EastNorth eastNorthComparison = comparison.getEastNorth();
+        for (Node node : neighbours) {
+            EastNorth eastNorthNode = node.getEastNorth();
+            double tAngle = Geometry.getCornerAngle(eastNorthComparison, eastNorthIntersection, eastNorthNode);
+            if (Math.abs(tAngle) < angle) angle = Math.abs(tAngle);
+        }
+        return Geometry.getNormalizedAngleInDegrees(angle);
+    }
+}
Index: src/org/openstreetmap/josm/data/validation/tests/RoutingIslandsTest.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/RoutingIslandsTest.java	(nonexistent)
+++ src/org/openstreetmap/josm/data/validation/tests/RoutingIslandsTest.java	(working copy)
@@ -0,0 +1,518 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.validation.tests;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.stream.Collectors;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.TagMap;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
+import org.openstreetmap.josm.data.validation.Severity;
+import org.openstreetmap.josm.data.validation.Test;
+import org.openstreetmap.josm.data.validation.TestError;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.Access;
+import org.openstreetmap.josm.tools.Pair;
+
+/**
+ * A test for routing islands
+ *
+ * @author Taylor Smock
+ * @since xxx
+ */
+public class RoutingIslandsTest extends Test {
+
+    private static final Map<Integer, Severity> SEVERITY_MAP = new HashMap<>();
+    /** The code for the routing island validation test */
+    public static final int ROUTING_ISLAND = 3900;
+    /** The code for ways that are not connected to other ways, and are routable */
+    public static final int LONELY_WAY = ROUTING_ISLAND + 1;
+    static {
+        SEVERITY_MAP.put(ROUTING_ISLAND, Severity.OTHER);
+        SEVERITY_MAP.put(LONELY_WAY, Severity.ERROR);
+    }
+
+    private static final String HIGHWAY = "highway";
+    private static final String WATERWAY = "waterway";
+
+    /**
+     * This is mostly as a sanity check, and to avoid infinite recursion (shouldn't
+     * happen, but still)
+     */
+    private static final int MAX_LOOPS = 1000;
+    /** Highways to check for routing connectivity */
+    private Set<Way> potentialHighways;
+    /** Waterways to check for routing connectivity */
+    private Set<Way> potentialWaterways;
+
+    /**
+     * Constructs a new {@code RightAngleBuildingTest} test.
+     */
+    public RoutingIslandsTest() {
+        super(tr("Routing islands"), tr("Checks for roads that cannot be reached or left."));
+        super.setPartialSelection(false);
+    }
+
+    @Override
+    public void startTest(ProgressMonitor monitor) {
+        super.startTest(monitor);
+        potentialHighways = new HashSet<>();
+        potentialWaterways = new HashSet<>();
+    }
+
+    @Override
+    public void endTest() {
+        Access.AccessTags.getByTransportType(Access.AccessTags.LAND_TRANSPORT_TYPE).parallelStream().forEach(mode -> {
+            runTest(mode.getKey(), potentialHighways);
+            progressMonitor.setCustomText(mode.getKey());
+        });
+        Access.AccessTags.getByTransportType(Access.AccessTags.WATER_TRANSPORT_TYPE).parallelStream().forEach(mode -> {
+            progressMonitor.setCustomText(mode.getKey());
+            runTest(mode.getKey(), potentialWaterways);
+        });
+        super.endTest();
+    }
+
+    @Override
+    public void visit(Way way) {
+        if (way.isUsable() && way.getNodes().parallelStream().anyMatch(node -> way.getDataSet().getDataSourceBounds()
+                .parallelStream().anyMatch(source -> source.contains(node.getCoor())))) {
+            if ((way.hasKey(HIGHWAY) || way.hasKey(WATERWAY))
+                    && way.getNodes().parallelStream().flatMap(node -> node.getReferrers().parallelStream()).distinct()
+                            .allMatch(way::equals)
+                    && way.getNodes().parallelStream().noneMatch(Node::isOutsideDownloadArea)) {
+                errors.add(TestError.builder(this, SEVERITY_MAP.get(LONELY_WAY), LONELY_WAY).primitives(way)
+                        .message(tr("MapWithAI (experimental)"), marktr("Routable way not connected to other ways"))
+                        .build());
+            } else if ((ValidatorPrefHelper.PREF_OTHER.get() || ValidatorPrefHelper.PREF_OTHER_UPLOAD.get()
+                    || !Severity.OTHER.equals(SEVERITY_MAP.get(ROUTING_ISLAND))) && !isBeforeUpload) {
+                if (way.hasKey(HIGHWAY)) {
+                    potentialHighways.add(way);
+                } else if (way.hasKey(WATERWAY)) {
+                    potentialWaterways.add(way);
+                }
+            }
+        }
+    }
+
+    private void runTest(String currentTransportMode, Collection<Way> potentialWays) {
+        Set<Way> incomingWays = new HashSet<>();
+        Set<Way> outgoingWays = new HashSet<>();
+        findConnectedWays(currentTransportMode, potentialWays, incomingWays, outgoingWays);
+        Collection<Way> realPotentialWays = (incomingWays.isEmpty() || outgoingWays.isEmpty())
+                ? expandNetwork(currentTransportMode, potentialWays)
+                : potentialWays;
+
+        if (incomingWays.isEmpty() || outgoingWays.isEmpty()) {
+            findConnectedWays(currentTransportMode, realPotentialWays, incomingWays, outgoingWays);
+        }
+        runGenericTest(currentTransportMode, realPotentialWays, incomingWays, outgoingWays);
+
+    }
+
+    /**
+     * Expand a network from an initial selection
+     *
+     * @param currentTransportMode The current transport mode
+     * @param initial              The initial collection of ways
+     * @return An expanded collection of ways, which should be all connected ways
+     *         that allow the current transport mode.
+     */
+    private static Collection<Way> expandNetwork(String currentTransportMode, Collection<Way> initial) {
+        Collection<Way> connected = initial.parallelStream().flatMap(way -> way.getNodes().parallelStream())
+                .flatMap(node -> node.getReferrers().parallelStream()).filter(Way.class::isInstance)
+                .map(Way.class::cast).distinct().collect(Collectors.toSet());
+        if (connected.containsAll(initial) && initial.containsAll(connected)) {
+            return connected;
+        }
+        return expandNetwork(currentTransportMode, connected);
+    }
+
+    /**
+     * This test is run when there are known incoming/outgoing ways
+     *
+     * @param currentTransportMode The current transport mode
+     * @param potentialWays        The ways to check
+     * @param incomingWays         The incoming ways
+     * @param outgoingWays         The outgoing ways
+     */
+    private void runGenericTest(String currentTransportMode, Collection<Way> potentialWays,
+            Collection<Way> incomingWays, Collection<Way> outgoingWays) {
+        Set<Way> toIgnore = potentialWays.parallelStream()
+                .filter(way -> incomingWays.contains(way) || outgoingWays.contains(way))
+                .filter(way -> !Access.getPositiveAccessValues().contains(
+                        getDefaultAccessTags(way).getOrDefault(currentTransportMode, Access.AccessTags.NO.getKey())))
+                .collect(Collectors.toSet());
+        incomingWays.removeAll(toIgnore);
+        outgoingWays.removeAll(toIgnore);
+
+        checkForUnconnectedWays(incomingWays, outgoingWays, currentTransportMode);
+        List<Pair<String, Set<Way>>> problematic = collectConnected(potentialWays.parallelStream()
+                .filter(way -> !incomingWays.contains(way) || !outgoingWays.contains(way))
+                .filter(way -> Access.getPositiveAccessValues().contains(
+                        getDefaultAccessTags(way).getOrDefault(currentTransportMode, Access.AccessTags.NO.getKey())))
+                .collect(Collectors.toSet()))
+                        .parallelStream()
+                        .map(way -> new Pair<>(
+                                (incomingWays.containsAll(way) ? marktr("outgoing") : marktr("incoming")), way))
+                        .collect(Collectors.toList());
+        createErrors(problematic, currentTransportMode);
+    }
+
+    /**
+     * Find ways that may be connected to the wider network
+     *
+     * @param currentTransportMode The current mode of transport
+     * @param potentialWays        The ways to check for connections
+     * @param incomingWays         A collection that will have incoming ways after
+     *                             this method is called
+     * @param outgoingWays         A collection that will have outgoing ways after
+     *                             this method is called
+     */
+    private static void findConnectedWays(String currentTransportMode, Collection<Way> potentialWays,
+            Collection<Way> incomingWays, Collection<Way> outgoingWays) {
+        potentialWays.stream().filter(Way::isUsable).filter(Way::isOutsideDownloadArea).forEach(way -> {
+            Node firstNode = firstNode(way, currentTransportMode);
+            Node lastNode = lastNode(way, currentTransportMode);
+            Integer isOneway = isOneway(way, currentTransportMode);
+            if (firstNode != null && firstNode.isOutsideDownloadArea()) {
+                incomingWays.add(way);
+            }
+            if (lastNode != null && lastNode.isOutsideDownloadArea()) {
+                outgoingWays.add(way);
+            }
+            if (isOneway == 0 && firstNode != null && lastNode != null
+                    && (firstNode.isOutsideDownloadArea() || lastNode.isOutsideDownloadArea())) {
+                incomingWays.add(way);
+                outgoingWays.add(way);
+            }
+        });
+    }
+
+    /**
+     * Take a collection of ways and modify it so that it is a list of connected
+     * ways
+     *
+     * @param ways A collection of ways that may or may not be connected
+     * @return a list of sets of ways that are connected
+     */
+    private static List<Set<Way>> collectConnected(Collection<Way> ways) {
+        ArrayList<Set<Way>> collected = new ArrayList<>();
+        ArrayList<Way> listOfWays = new ArrayList<>(ways);
+        final int maxLoop = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
+        for (int i = 0; i < listOfWays.size(); i++) {
+            Way initial = listOfWays.get(i);
+            Set<Way> connected = new HashSet<>();
+            connected.add(initial);
+            int loopCounter = 0;
+            while (!getConnected(connected) && loopCounter < maxLoop) {
+                loopCounter++;
+            }
+            if (listOfWays.removeAll(connected)) {
+                /*
+                 * Not an issue -- this ensures that everything is accounted for, only triggers
+                 * when ways removed
+                 */
+                i--; // NOSONAR
+            }
+            collected.add(connected);
+        }
+        return collected;
+    }
+
+    private static boolean getConnected(Collection<Way> ways) {
+        TagMap defaultAccess = getDefaultAccessTags(ways.iterator().next());
+        return ways.addAll(ways.parallelStream().flatMap(way -> way.getNodes().parallelStream())
+                .flatMap(node -> node.getReferrers().parallelStream()).filter(Way.class::isInstance)
+                .map(Way.class::cast).filter(way -> getDefaultAccessTags(way).equals(defaultAccess))
+                .collect(Collectors.toSet()));
+    }
+
+    /**
+     * Create errors for a problematic way
+     *
+     * @param problematic The set of problematic ways (Pairs are
+     *                    &lt;incoming/outgoing, Set&lt;Connected ways with same
+     *                    issue&gt;&gt;)
+     * @param mode        The transport mode
+     */
+    private void createErrors(List<Pair<String, Set<Way>>> problematic, String mode) {
+        for (Pair<String, Set<Way>> ways : problematic) {
+            errors.add(
+                    TestError.builder(this, SEVERITY_MAP.getOrDefault(ROUTING_ISLAND, Severity.OTHER), ROUTING_ISLAND)
+                            .message(tr("MapWithAI (experimental)"), marktr("Routing island"), "{1}: {0}", tr(ways.a),
+                                    mode == null ? marktr("default") : mode)
+                            .primitives(ways.b).build());
+        }
+    }
+
+    /**
+     * Check for unconnected ways
+     *
+     * @param incoming             The current incoming ways (will be modified)
+     * @param outgoing             The current outgoing ways (will be modified)
+     * @param currentTransportMode The transport mode we are investigating (may be
+     *                             {@code null})
+     */
+    public static void checkForUnconnectedWays(Collection<Way> incoming, Collection<Way> outgoing,
+            String currentTransportMode) {
+        int loopCount = 0;
+        int maxLoops = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
+        do {
+            loopCount++;
+        } while (loopCount <= maxLoops && getWaysFor(incoming, currentTransportMode,
+                (way, oldWay) -> oldWay.containsNode(firstNode(way, currentTransportMode))
+                        && checkAccessibility(oldWay, way, currentTransportMode)));
+        loopCount = 0;
+        do {
+            loopCount++;
+        } while (loopCount <= maxLoops && getWaysFor(outgoing, currentTransportMode,
+                (way, oldWay) -> oldWay.containsNode(lastNode(way, currentTransportMode))
+                        && checkAccessibility(oldWay, way, currentTransportMode)));
+    }
+
+    private static boolean getWaysFor(Collection<Way> directional, String currentTransportMode,
+            BiPredicate<Way, Way> predicate) {
+        Set<Way> toAdd = new HashSet<>();
+        for (Way way : directional) {
+            for (Node node : way.getNodes()) {
+                Set<Way> referrers = node.getReferrers(true).parallelStream().filter(Way.class::isInstance)
+                        .map(Way.class::cast).filter(tWay -> !directional.contains(tWay)).collect(Collectors.toSet());
+                for (Way tWay : referrers) {
+                    if (isOneway(tWay, currentTransportMode) == 0 || predicate.test(tWay, way) || tWay.isClosed()) {
+                        toAdd.add(tWay);
+                    }
+                }
+            }
+        }
+        return directional.addAll(toAdd);
+    }
+
+    /**
+     * Check if I can get to way to from way from (currently doesn't work with via
+     * ways)
+     *
+     * @param from                 The from way
+     * @param to                   The to way
+     * @param currentTransportMode The specific transport mode to check
+     * @return {@code true} if the to way can be accessed from the from way TODO
+     *         clean up and work with via ways
+     */
+    public static boolean checkAccessibility(Way from, Way to, String currentTransportMode) {
+        boolean isAccessible = true;
+
+        List<Relation> relations = from.getReferrers().parallelStream().distinct().filter(Relation.class::isInstance)
+                .map(Relation.class::cast).filter(relation -> "restriction".equals(relation.get("type")))
+                .collect(Collectors.toList());
+        for (Relation relation : relations) {
+            if (((relation.hasKey("except") && relation.get("except").contains(currentTransportMode))
+                    || (currentTransportMode == null || currentTransportMode.trim().isEmpty()))
+                    && relation.getMembersFor(Collections.singleton(from)).parallelStream()
+                            .anyMatch(member -> "from".equals(member.getRole()))
+                    && relation.getMembersFor(Collections.singleton(to)).parallelStream()
+                            .anyMatch(member -> "to".equals(member.getRole()))) {
+                isAccessible = false;
+            }
+        }
+        return isAccessible;
+    }
+
+    /**
+     * Check if a node connects to the outside world
+     *
+     * @param node The node to check
+     * @return true if outside download area, connects to an aeroport, or a water
+     *         transport
+     */
+    public static Boolean outsideConnections(Node node) {
+        boolean outsideConnections = false;
+        if (node.isOutsideDownloadArea() || node.hasTag("amenity", "parking_entrance", "parking", "parking_space",
+                "motorcycle_parking", "ferry_terminal")) {
+            outsideConnections = true;
+        }
+        return outsideConnections;
+    }
+
+    /**
+     * Check if a way is oneway for a specific transport type
+     *
+     * @param way           The way to look at
+     * @param transportType The specific transport type
+     * @return See {@link Way#isOneway} (but may additionally return {@code null} if
+     *         the transport type cannot route down that way)
+     */
+    public static Integer isOneway(Way way, String transportType) {
+        if (transportType == null || transportType.trim().isEmpty()) {
+            return way.isOneway();
+        }
+        String forward = transportType.concat(":forward");
+        String backward = transportType.concat(":backward");
+        boolean possibleForward = "yes".equals(way.get(forward)) || (!way.hasKey(forward) && way.isOneway() != -1);
+        boolean possibleBackward = "yes".equals(way.get(backward)) || (!way.hasKey(backward) && way.isOneway() != 1);
+        if (transportType.equals(Access.AccessTags.FOOT.getKey()) && !"footway".equals(way.get(HIGHWAY))
+                && !way.hasTag("foot:forward") && !way.hasTag("foot:backward")) {
+            /*
+             * Foot is almost never oneway, especially on generic road types. There are some
+             * cases on mountain paths.
+             */
+            return 0;
+        }
+        if (possibleForward && !possibleBackward) {
+            return 1;
+        } else if (!possibleForward && possibleBackward) {
+            return -1;
+        } else if (!possibleBackward) {
+            return null;
+        }
+        return 0;
+    }
+
+    /**
+     * Get the first node of a way respecting the oneway for a transport type
+     *
+     * @param way           The way to get the node from
+     * @param transportType The transport type
+     * @return The first node for the specified transport type, or null if it is not
+     *         routable
+     */
+    public static Node firstNode(Way way, String transportType) {
+        Integer oneway = isOneway(way, transportType);
+        Node node = (Integer.valueOf(-1).equals(oneway)) ? way.lastNode() : way.firstNode();
+
+        Map<String, String> accessValues = getDefaultAccessTags(way);
+        boolean accessible = Access.getPositiveAccessValues()
+                .contains(accessValues.getOrDefault(transportType, Access.AccessTags.NO.getKey()));
+        return (transportType == null || accessible) ? node : null;
+    }
+
+    /**
+     * Get the last node of a way respecting the oneway for a transport type
+     *
+     * @param way           The way to get the node from
+     * @param transportType The transport type
+     * @return The last node for the specified transport type, or the last node of
+     *         the way, or null if it is not routable
+     */
+    public static Node lastNode(Way way, String transportType) {
+        Integer oneway = isOneway(way, transportType);
+        Node node = (Integer.valueOf(-1).equals(oneway)) ? way.firstNode() : way.lastNode();
+        Map<String, String> accessValues = getDefaultAccessTags(way);
+        boolean accessible = Access.getPositiveAccessValues()
+                .contains(accessValues.getOrDefault(transportType, Access.AccessTags.NO.getKey()));
+        return (transportType == null || accessible) ? node : null;
+    }
+
+    /**
+     * Get the default access tags for a primitive
+     *
+     * @param primitive The primitive to get access tags for
+     * @return The map of access tags to access
+     */
+    public static TagMap getDefaultAccessTags(OsmPrimitive primitive) {
+        TagMap access = new TagMap();
+        final TagMap tags;
+        if (primitive.hasKey(HIGHWAY)) {
+            tags = getDefaultHighwayAccessTags(primitive.getKeys());
+        } else if (primitive.hasKey(WATERWAY)) {
+            tags = getDefaultWaterwayAccessTags(primitive.getKeys());
+        } else {
+            tags = new TagMap();
+        }
+        tags.putAll(Access.expandAccessValues(tags));
+
+        for (String direction : Arrays.asList("", "forward:", "backward:")) {
+            Access.getTransportModes().parallelStream().map(direction::concat).filter(tags::containsKey)
+                    .forEach(mode -> access.put(mode, tags.get(direction.concat(mode))));
+        }
+        return access;
+    }
+
+    private static TagMap getDefaultWaterwayAccessTags(TagMap tags) {
+        if ("river".equals(tags.get(WATERWAY))) {
+            tags.putIfAbsent("boat", Access.AccessTags.YES.getKey());
+        }
+        return tags;
+    }
+
+    private static TagMap getDefaultHighwayAccessTags(TagMap tags) {
+        String highway = tags.get(HIGHWAY);
+
+        if (tags.containsKey("sidewalk") && !tags.get("sidewalk").equals(Access.AccessTags.NO.getKey())) {
+            tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.YES.getKey());
+        }
+
+        if (tags.keySet().parallelStream()
+                .anyMatch(str -> str.contains("cycleway") && !Access.AccessTags.NO.getKey().equals(tags.get(str)))) {
+            tags.putIfAbsent(Access.AccessTags.BICYCLE.getKey(), Access.AccessTags.YES.getKey());
+        }
+
+        if ("residential".equals(highway)) {
+            tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
+            tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.YES.getKey());
+            tags.putIfAbsent(Access.AccessTags.BICYCLE.getKey(), Access.AccessTags.YES.getKey());
+        } else if (Arrays.asList("service", "unclassified", "tertiary", "tertiary_link").contains(highway)) {
+            tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
+        } else if (Arrays.asList("secondary", "secondary_link").contains(highway)) {
+            tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
+        } else if (Arrays.asList("primary", "primary_link").contains(highway)) {
+            tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
+            tags.putIfAbsent(Access.AccessTags.HGV.getKey(), Access.AccessTags.YES.getKey());
+        } else if (Arrays.asList("motorway", "trunk", "motorway_link", "trunk_link").contains(highway)) {
+            tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
+            tags.putIfAbsent(Access.AccessTags.BICYCLE.getKey(), Access.AccessTags.NO.getKey());
+            tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.NO.getKey());
+        } else if ("steps".equals(highway)) {
+            tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.NO.getKey());
+            tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.YES.getKey());
+        } else if ("path".equals(highway)) {
+            tags.putIfAbsent(Access.AccessTags.MOTOR_VEHICLE.getKey(), Access.AccessTags.NO.getKey());
+            tags.putIfAbsent(Access.AccessTags.EMERGENCY.getKey(), Access.AccessTags.DESTINATION.getKey());
+        } else if ("footway".equals(highway)) {
+            tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.DESIGNATED.getKey());
+        } else if ("bus_guideway".equals(highway)) {
+            tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.NO.getKey());
+            tags.putIfAbsent(Access.AccessTags.BUS.getKey(), Access.AccessTags.DESIGNATED.getKey());
+        } else if ("road".equals(highway)) { // Don't expect these to be routable
+            tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.NO.getKey());
+        } else {
+            tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.YES.getKey());
+        }
+        return tags;
+    }
+
+    /**
+     * Get the error level for a test
+     *
+     * @param test The integer value of the test error
+     * @return The severity for the test
+     */
+    public static Severity getErrorLevel(int test) {
+        return SEVERITY_MAP.get(test);
+    }
+
+    /**
+     * Set the error level for a test
+     *
+     * @param test     The integer value of the test error
+     * @param severity The new severity for the test
+     */
+    public static void setErrorLevel(int test, Severity severity) {
+        SEVERITY_MAP.put(test, severity);
+    }
+}
Index: src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 15755)
+++ src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(working copy)
@@ -194,6 +194,7 @@
      */
     public TagChecker() {
         super(tr("Tag checker"), tr("This test checks for errors in tag keys and values."));
+        setShowElements(true);
     }
 
     @Override
Index: src/org/openstreetmap/josm/gui/MapViewState.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapViewState.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/MapViewState.java	(working copy)
@@ -131,7 +131,7 @@
         this(projecting, mvs.viewWidth, mvs.viewHeight, mvs.scale, mvs.topLeft, mvs.topLeftInWindow, mvs.topLeftOnScreen);
     }
 
-    private static Point findTopLeftInWindow(JComponent position) {
+    static Point findTopLeftInWindow(JComponent position) {
         Point result = new Point();
         // better than using swing utils, since this allows us to use the method if no screen is present.
         Container component = position;
@@ -143,7 +143,7 @@
         return result;
     }
 
-    private static Point findTopLeftOnScreen(JComponent position) {
+    static Point findTopLeftOnScreen(JComponent position) {
         try {
             return position.getLocationOnScreen();
         } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
Index: src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/NavigatableComponent.java	(working copy)
@@ -1716,3 +1716,4 @@
         )/512;
     }
 }
+
Index: src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java	(working copy)
@@ -174,7 +174,7 @@
         fixAction.setEnabled(false);
         buttons.add(new SideButton(fixAction));
 
-        if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
+        if (Boolean.TRUE.equals(ValidatorPrefHelper.PREF_USE_IGNORE.get())) {
             ignoreAction = new AbstractAction() {
                 {
                     putValue(NAME, tr("Ignore"));
@@ -261,7 +261,7 @@
             updateSelection(ds.getAllSelected());
         }
         MainApplication.getLayerManager().addAndFireActiveLayerChangeListener(this);
-
+        validateAction.updateEnabledState();
     }
 
     @Override
Index: src/org/openstreetmap/josm/gui/download/OSMDownloadSource.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/OSMDownloadSource.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/download/OSMDownloadSource.java	(working copy)
@@ -7,7 +7,9 @@
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.GridBagLayout;
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -23,10 +25,14 @@
 import org.openstreetmap.josm.actions.downloadtasks.DownloadNotesTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadParams;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
 import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.ViewportData;
+import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.NoteData;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -48,6 +54,15 @@
      */
     public static final String SIMPLE_NAME = "osmdownloadpanel";
 
+    /** The possible methods to get data */
+    static final List<DataDownloadType> DOWNLOAD_POSSIBILITIES = new ArrayList<>();
+    static {
+        // Order is important (determines button order, and what gets zoomed to)
+        DOWNLOAD_POSSIBILITIES.add(new OsmDataDownloadType());
+        DOWNLOAD_POSSIBILITIES.add(new GpsDataDownloadType());
+        DOWNLOAD_POSSIBILITIES.add(new NotesDataDownloadType());
+    }
+
     @Override
     public AbstractDownloadSourcePanel<OSMDownloadData> createPanel(DownloadDialog dialog) {
         return new OSMDownloadSourcePanel(this, dialog);
@@ -59,38 +74,23 @@
                 .orElseThrow(() -> new IllegalArgumentException("OSM downloads requires bounds"));
         boolean zoom = settings.zoomToData();
         boolean newLayer = settings.asNewLayer();
-        List<Pair<AbstractDownloadTask<?>, Future<?>>> tasks = new ArrayList<>();
-
-        if (data.isDownloadOSMData()) {
-            DownloadOsmTask task = new DownloadOsmTask();
-            task.setZoomAfterDownload(zoom && !data.isDownloadGPX() && !data.isDownloadNotes());
-            Future<?> future = task.download(new DownloadParams().withNewLayer(newLayer), bbox, null);
-            MainApplication.worker.submit(new PostDownloadHandler(task, future));
-            if (zoom) {
-                tasks.add(new Pair<>(task, future));
+        final List<Pair<AbstractDownloadTask<?>, Future<?>>> tasks = new ArrayList<>();
+        DataDownloadType zoomTask = zoom ? data.getDownloadPossibilities().stream().findFirst().orElse(null) : null;
+        data.getDownloadPossibilities().parallelStream().filter(DataDownloadType::isEnabled).forEach(type -> {
+            try {
+                AbstractDownloadTask<?> task = type.getDownloadClass().getDeclaredConstructor().newInstance();
+                task.setZoomAfterDownload(type.equals(zoomTask));
+                Future<?> future = task.download(new DownloadParams().withNewLayer(newLayer), bbox, null);
+                MainApplication.worker.submit(new PostDownloadHandler(task, future));
+                if (zoom) {
+                    tasks.add(new Pair<AbstractDownloadTask<?>, Future<?>>(task, future));
+                }
+            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+                    | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+                Logging.error(e);
             }
-        }
+        });
 
-        if (data.isDownloadGPX()) {
-            DownloadGpsTask task = new DownloadGpsTask();
-            task.setZoomAfterDownload(zoom && !data.isDownloadOSMData() && !data.isDownloadNotes());
-            Future<?> future = task.download(new DownloadParams().withNewLayer(newLayer), bbox, null);
-            MainApplication.worker.submit(new PostDownloadHandler(task, future));
-            if (zoom) {
-                tasks.add(new Pair<>(task, future));
-            }
-        }
-
-        if (data.isDownloadNotes()) {
-            DownloadNotesTask task = new DownloadNotesTask();
-            task.setZoomAfterDownload(zoom && !data.isDownloadOSMData() && !data.isDownloadGPX());
-            Future<?> future = task.download(new DownloadParams(), bbox, null);
-            MainApplication.worker.submit(new PostDownloadHandler(task, future));
-            if (zoom) {
-                tasks.add(new Pair<>(task, future));
-            }
-        }
-
         if (zoom && tasks.size() > 1) {
             MainApplication.worker.submit(() -> {
                 ProjectionBounds bounds = null;
@@ -129,20 +129,52 @@
     }
 
     /**
+     * @return The possible downloads that JOSM can make in the default Download
+     *         screen
+     * @since xxx
+     */
+    public static List<DataDownloadType> getDownloadTypes() {
+        return Collections.unmodifiableList(DOWNLOAD_POSSIBILITIES);
+    }
+
+    /**
+     * @param type The DataDownloadType object to remove
+     * @return true if the list was modified
+     * @since xxx
+     */
+    public static boolean removeDownloadType(DataDownloadType type) {
+        boolean modified = false;
+        if (!(type instanceof OsmDataDownloadType) && !(type instanceof GpsDataDownloadType)
+                && !(type instanceof NotesDataDownloadType)) {
+            modified = DOWNLOAD_POSSIBILITIES.remove(type);
+        }
+        return modified;
+    }
+
+    /**
+     * Add a download type to the default JOSM download window
+     *
+     * @param type The initialized type to download
+     * @return true if the list was modified
+     * @since xxx
+     */
+    public static boolean addDownloadType(DataDownloadType type) {
+        boolean modified = false;
+        if (!(type instanceof OsmDataDownloadType) && !(type instanceof GpsDataDownloadType)
+                && !(type instanceof NotesDataDownloadType) && DOWNLOAD_POSSIBILITIES.parallelStream()
+                        .noneMatch(possibility -> type.getClass().isInstance(possibility))) {
+            modified = DOWNLOAD_POSSIBILITIES.add(type);
+        }
+        return modified;
+    }
+
+    /**
      * The GUI representation of the OSM download source.
      * @since 12652
      */
     public static class OSMDownloadSourcePanel extends AbstractDownloadSourcePanel<OSMDownloadData> {
-
-        private final JCheckBox cbDownloadOsmData;
-        private final JCheckBox cbDownloadGpxData;
-        private final JCheckBox cbDownloadNotes;
         private final JLabel sizeCheck = new JLabel();
 
-        private static final BooleanProperty DOWNLOAD_OSM = new BooleanProperty("download.osm.data", true);
-        private static final BooleanProperty DOWNLOAD_GPS = new BooleanProperty("download.osm.gps", false);
-        private static final BooleanProperty DOWNLOAD_NOTES = new BooleanProperty("download.osm.notes", false);
-
         /**
          * Creates a new {@link OSMDownloadSourcePanel}.
          * @param dialog the parent download dialog, as {@code DownloadDialog.getInstance()} might not be initialized yet
@@ -159,24 +191,11 @@
 
             // adding the download tasks
             add(new JLabel(tr("Data Sources and Types:")), GBC.std().insets(5, 5, 1, 5).anchor(GBC.CENTER));
-            cbDownloadOsmData = new JCheckBox(tr("OpenStreetMap data"), true);
-            cbDownloadOsmData.setToolTipText(tr("Select to download OSM data in the selected download area."));
-            cbDownloadOsmData.getModel().addChangeListener(checkboxChangeListener);
-
-            cbDownloadGpxData = new JCheckBox(tr("Raw GPS data"));
-            cbDownloadGpxData.setToolTipText(tr("Select to download GPS traces in the selected download area."));
-            cbDownloadGpxData.getModel().addChangeListener(checkboxChangeListener);
-
-            cbDownloadNotes = new JCheckBox(tr("Notes"));
-            cbDownloadNotes.setToolTipText(tr("Select to download notes in the selected download area."));
-            cbDownloadNotes.getModel().addChangeListener(checkboxChangeListener);
-
             Font labelFont = sizeCheck.getFont();
             sizeCheck.setFont(labelFont.deriveFont(Font.PLAIN, labelFont.getSize()));
 
-            add(cbDownloadOsmData, GBC.std().insets(1, 5, 1, 5));
-            add(cbDownloadGpxData, GBC.std().insets(1, 5, 1, 5));
-            add(cbDownloadNotes, GBC.eol().insets(1, 5, 1, 5));
+            DOWNLOAD_POSSIBILITIES
+                    .forEach(obj -> add(obj.getCheckBox(checkboxChangeListener), GBC.std().insets(1, 5, 1, 5)));
             add(sizeCheck, GBC.eol().anchor(GBC.EAST).insets(5, 5, 5, 2));
 
             setMinimumSize(new Dimension(450, 115));
@@ -184,24 +203,17 @@
 
         @Override
         public OSMDownloadData getData() {
-            return new OSMDownloadData(
-                    isDownloadOsmData(),
-                    isDownloadNotes(),
-                    isDownloadGpxData());
+            return new OSMDownloadData(DOWNLOAD_POSSIBILITIES);
         }
 
         @Override
         public void rememberSettings() {
-            DOWNLOAD_OSM.put(isDownloadOsmData());
-            DOWNLOAD_GPS.put(isDownloadGpxData());
-            DOWNLOAD_NOTES.put(isDownloadNotes());
+            DOWNLOAD_POSSIBILITIES.forEach(type -> type.getBooleanProperty().put(type.getCheckBox().isSelected()));
         }
 
         @Override
         public void restoreSettings() {
-            cbDownloadOsmData.setSelected(DOWNLOAD_OSM.get());
-            cbDownloadGpxData.setSelected(DOWNLOAD_GPS.get());
-            cbDownloadNotes.setSelected(DOWNLOAD_NOTES.get());
+            DOWNLOAD_POSSIBILITIES.forEach(type -> type.getCheckBox().setSelected(type.isEnabled()));
         }
 
         @Override
@@ -225,15 +237,23 @@
              * must be chosen : raw osm data, gpx data, notes.
              * If none of those are selected, then the corresponding dialog is shown to inform the user.
              */
-            if (!isDownloadOsmData() && !isDownloadGpxData() && !isDownloadNotes()) {
+            if (DOWNLOAD_POSSIBILITIES.parallelStream().noneMatch(DataDownloadType::isEnabled)) {
+                StringBuilder line1 = new StringBuilder("<html>");
+                StringBuilder line2 = new StringBuilder(tr("Please choose to either download"));
+                DOWNLOAD_POSSIBILITIES.forEach(type -> {
+                    if (line1.length() == 6) {
+                        line1.append(tr("Neither"));
+                    } else {
+                        line1.append(tr("nor"));
+                    }
+                    line1.append(" <strong>").append(type.getCheckBox().getText()).append("</strong> ");
+                    line2.append(' ').append(type.getCheckBox().getText()).append(tr(", or"));
+                });
+                line1.append(tr("is enabled.")).append("<br>");
+                line2.append(tr(" all.")).append("</html>");
                 JOptionPane.showMessageDialog(
                         this.getParent(),
-                        tr("<html>Neither <strong>{0}</strong> nor <strong>{1}</strong> nor <strong>{2}</strong> is enabled.<br>"
-                                        + "Please choose to either download OSM data, or GPX data, or Notes, or all.</html>",
-                                cbDownloadOsmData.getText(),
-                                cbDownloadGpxData.getText(),
-                                cbDownloadNotes.getText()
-                        ),
+                        line1.append(line2).toString(),
                         tr("Error"),
                         JOptionPane.ERROR_MESSAGE
                 );
@@ -250,9 +270,12 @@
          * Replies true if the user selected to download OSM data
          *
          * @return true if the user selected to download OSM data
+         * @deprecated since xxx -- use {@link OSMDownloadSource#getDownloadTypes} with
+         *             {@code get(0).getCheckBox().isSelected()}
          */
+        @Deprecated
         public boolean isDownloadOsmData() {
-            return cbDownloadOsmData.isSelected();
+            return DOWNLOAD_POSSIBILITIES.get(0).getCheckBox().isSelected();
         }
 
         /**
@@ -259,9 +282,12 @@
          * Replies true if the user selected to download GPX data
          *
          * @return true if the user selected to download GPX data
+         * @deprecated since xxx -- use {@link OSMDownloadSource#getDownloadTypes} with
+         *             {@code get(1).getCheckBox().isSelected()}
          */
+        @Deprecated
         public boolean isDownloadGpxData() {
-            return cbDownloadGpxData.isSelected();
+            return DOWNLOAD_POSSIBILITIES.get(1).getCheckBox().isSelected();
         }
 
         /**
@@ -268,9 +294,12 @@
          * Replies true if user selected to download notes
          *
          * @return true if user selected to download notes
+         * @deprecated since xxx -- use {@link OSMDownloadSource#getDownloadTypes} with
+         *             {@code get(2).getCheckBox().isSelected()}
          */
+        @Deprecated
         public boolean isDownloadNotes() {
-            return cbDownloadNotes.isSelected();
+            return DOWNLOAD_POSSIBILITIES.get(2).getCheckBox().isSelected();
         }
 
         @Override
@@ -295,18 +324,8 @@
                 return;
             }
 
-            boolean isAreaTooLarge = false;
-            if (!isDownloadNotes() && !isDownloadOsmData() && !isDownloadGpxData()) {
-                isAreaTooLarge = false;
-            } else if (isDownloadNotes() && !isDownloadOsmData() && !isDownloadGpxData()) {
-                // see max_note_request_area in https://github.com/openstreetmap/openstreetmap-website/blob/master/config/example.application.yml
-                isAreaTooLarge = bbox.getArea() > Config.getPref().getDouble("osm-server.max-request-area-notes", 25);
-            } else {
-                // see max_request_area in https://github.com/openstreetmap/openstreetmap-website/blob/master/config/example.application.yml
-                isAreaTooLarge = bbox.getArea() > Config.getPref().getDouble("osm-server.max-request-area", 0.25);
-            }
-
-            displaySizeCheckResult(isAreaTooLarge);
+            displaySizeCheckResult(DOWNLOAD_POSSIBILITIES.parallelStream()
+                    .anyMatch(type -> type.isDownloadAreaTooLarge(bbox)));
         }
 
         private void displaySizeCheckResult(boolean isAreaTooLarge) {
@@ -325,26 +344,173 @@
      * Encapsulates data that is required to download from the OSM server.
      */
     static class OSMDownloadData {
-        private final boolean downloadOSMData;
-        private final boolean downloadNotes;
-        private final boolean downloadGPX;
 
-        OSMDownloadData(boolean downloadOSMData, boolean downloadNotes, boolean downloadGPX) {
-            this.downloadOSMData = downloadOSMData;
-            this.downloadNotes = downloadNotes;
-            this.downloadGPX = downloadGPX;
+        private List<DataDownloadType> downloadPossibilities;
+
+        /**
+         * @param downloadPossibilities A list of DataDownloadTypes (instantiated, with
+         *                              options set)
+         */
+        OSMDownloadData(List<DataDownloadType> downloadPossibilities) {
+            this.downloadPossibilities = downloadPossibilities;
         }
 
-        boolean isDownloadOSMData() {
-            return downloadOSMData;
+        /**
+         * @return A list of DataDownloadTypes (instantiated, with options set)
+         */
+        public List<DataDownloadType> getDownloadPossibilities() {
+            return downloadPossibilities;
         }
+    }
 
-        boolean isDownloadNotes() {
-            return downloadNotes;
+    /**
+     * An interface to allow arbitrary download sources and types in the primary
+     * download window of JOSM
+     *
+     * @since xxx
+     */
+    interface DataDownloadType {
+        /**
+         * @return The checkbox to be added to the UI
+         */
+        default JCheckBox getCheckBox() {
+            return getCheckBox(null);
         }
 
-        boolean isDownloadGPX() {
-            return downloadGPX;
+        /**
+         * @param checkboxChangeListener The listener for checkboxes (may be
+         *                               {@code null})
+         * @return The checkbox to be added to the UI
+         */
+        JCheckBox getCheckBox(ChangeListener checkboxChangeListener);
+
+        /**
+         * @return The {@link DownloadTask} class which will be getting the data
+         */
+        Class<? extends AbstractDownloadTask<?>> getDownloadClass();
+
+        /**
+         * @return The boolean indicating the last state of the download type
+         */
+        default boolean isEnabled() {
+            return getBooleanProperty().get();
         }
+
+        /**
+         * @return The boolean property for this particular download type
+         */
+        BooleanProperty getBooleanProperty();
+
+        /**
+         * Check if the area is too large for the current DataDownloadType
+         *
+         * @param bound The bound that will be downloaded
+         * @return {@code true} if we definitely cannot download the area;
+         */
+        boolean isDownloadAreaTooLarge(Bounds bound);
     }
+
+    static class OsmDataDownloadType implements DataDownloadType {
+        static final BooleanProperty IS_ENABLED = new BooleanProperty("download.osm.data", true);
+        JCheckBox cbDownloadOsmData;
+
+        @Override
+        public JCheckBox getCheckBox(ChangeListener checkboxChangeListener) {
+            if (cbDownloadOsmData == null) {
+                cbDownloadOsmData = new JCheckBox(tr("OpenStreetMap data"), true);
+                cbDownloadOsmData.setToolTipText(tr("Select to download OSM data in the selected download area."));
+                cbDownloadOsmData.getModel().addChangeListener(checkboxChangeListener);
+            }
+            if (checkboxChangeListener != null) {
+                cbDownloadOsmData.getModel().addChangeListener(checkboxChangeListener);
+            }
+            return cbDownloadOsmData;
+        }
+
+        @Override
+        public Class<? extends AbstractDownloadTask<DataSet>> getDownloadClass() {
+            return DownloadOsmTask.class;
+        }
+
+        @Override
+        public BooleanProperty getBooleanProperty() {
+            return IS_ENABLED;
+        }
+
+        @Override
+        public boolean isDownloadAreaTooLarge(Bounds bound) {
+            // see max_request_area in
+            // https://github.com/openstreetmap/openstreetmap-website/blob/master/config/example.application.yml
+            return bound.getArea() > Config.getPref().getDouble("osm-server.max-request-area", 0.25);
+        }
+    }
+
+    static class GpsDataDownloadType implements DataDownloadType {
+        static final BooleanProperty IS_ENABLED = new BooleanProperty("download.osm.gps", false);
+        private JCheckBox cbDownloadGpxData;
+
+        @Override
+        public JCheckBox getCheckBox(ChangeListener checkboxChangeListener) {
+            if (cbDownloadGpxData == null) {
+                cbDownloadGpxData = new JCheckBox(tr("Raw GPS data"));
+                cbDownloadGpxData.setToolTipText(tr("Select to download GPS traces in the selected download area."));
+            }
+            if (checkboxChangeListener != null) {
+                cbDownloadGpxData.getModel().addChangeListener(checkboxChangeListener);
+            }
+
+            return cbDownloadGpxData;
+        }
+
+        @Override
+        public Class<? extends AbstractDownloadTask<GpxData>> getDownloadClass() {
+            return DownloadGpsTask.class;
+        }
+
+        @Override
+        public BooleanProperty getBooleanProperty() {
+            return IS_ENABLED;
+        }
+
+        @Override
+        public boolean isDownloadAreaTooLarge(Bounds bound) {
+            return false;
+        }
+    }
+
+    static class NotesDataDownloadType implements DataDownloadType {
+        static final BooleanProperty IS_ENABLED = new BooleanProperty("download.osm.notes", false);
+        private JCheckBox cbDownloadNotes;
+
+        @Override
+        public JCheckBox getCheckBox(ChangeListener checkboxChangeListener) {
+            if (cbDownloadNotes == null) {
+                cbDownloadNotes = new JCheckBox(tr("Notes"));
+                cbDownloadNotes.setToolTipText(tr("Select to download notes in the selected download area."));
+            }
+            if (checkboxChangeListener != null) {
+                cbDownloadNotes.getModel().addChangeListener(checkboxChangeListener);
+            }
+
+            return cbDownloadNotes;
+        }
+
+        @Override
+        public Class<? extends AbstractDownloadTask<NoteData>> getDownloadClass() {
+            return DownloadNotesTask.class;
+        }
+
+        @Override
+        public BooleanProperty getBooleanProperty() {
+            return IS_ENABLED;
+        }
+
+        @Override
+        public boolean isDownloadAreaTooLarge(Bounds bound) {
+            // see max_note_request_area in
+            // https://github.com/openstreetmap/openstreetmap-website/blob/master/config/example.application.yml
+            return bound.getArea() > Config.getPref().getDouble("osm-server.max-request-area-notes", 25);
+        }
+    }
+
 }
Index: src/org/openstreetmap/josm/gui/io/BasicUploadSettingsPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/io/BasicUploadSettingsPanel.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/io/BasicUploadSettingsPanel.java	(working copy)
@@ -179,8 +179,8 @@
         setLayout(new GridBagLayout());
         setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
         add(buildUploadCommentPanel(), GBC.eol().fill(GBC.BOTH));
-        add(pnlUploadParameterSummary, GBC.eol().fill(GBC.HORIZONTAL));
-        add(cbRequestReview, GBC.eol().fill(GBC.HORIZONTAL));
+        add(pnlUploadParameterSummary, GBC.eol().fill(GBC.BOTH));
+        add(cbRequestReview, GBC.eol().fill(GBC.BOTH));
         cbRequestReview.addItemListener(e -> changesetReviewModel.setReviewRequested(e.getStateChange() == ItemEvent.SELECTED));
     }
 
Index: src/org/openstreetmap/josm/gui/io/UploadDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/io/UploadDialog.java	(working copy)
@@ -116,7 +116,7 @@
      * @return the unique instance of the upload dialog
      */
     public static synchronized UploadDialog getUploadDialog() {
-        if (uploadDialog == null) {
+        if (uploadDialog == null || true) {
             uploadDialog = new UploadDialog();
         }
         return uploadDialog;
Index: src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(working copy)
@@ -405,6 +405,7 @@
             super(name);
             this.layer = layer;
             this.tile = tile;
+            boolean rnad = (tile.getSource() instanceof ImageryInfo);
         }
     }
 
Index: src/org/openstreetmap/josm/gui/layer/imagery/ReprojectionTile.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/imagery/ReprojectionTile.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/layer/imagery/ReprojectionTile.java	(working copy)
@@ -6,10 +6,13 @@
 import java.awt.image.BufferedImage;
 
 import org.openstreetmap.gui.jmapviewer.Tile;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.imagery.CoordinateConversion;
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.data.projection.Projections;
@@ -222,4 +225,18 @@
             return 1;
         return null;
     }
+
+    /**
+     * Check if this tile will be inside the downloaded area
+     *
+     * @return {@code true} if this tile is inside the downloaded area
+     * @since xxx
+     */
+    public boolean isInDownloadArea() {
+        if (source instanceof ImageryInfo && ((ImageryInfo) source).getBounds() != null) {
+            ICoordinate coord = source.tileXYToLatLon(this);
+            ((ImageryInfo) source).getBounds().contains(new LatLon(coord.getLat(), coord.getLon()));
+        }
+        return false;
+    }
 }
Index: src/org/openstreetmap/josm/gui/mappaint/Cascade.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/Cascade.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/mappaint/Cascade.java	(working copy)
@@ -153,21 +153,14 @@
         if (klass == float[].class)
             return (T) toFloatArray(o);
 
+        if (klass == String[].class)
+            return (T) toStringArray(o);
+
         if (klass == Color.class)
             return (T) toColor(o);
 
         if (klass == String.class) {
-            if (o instanceof Keyword)
-                return (T) ((Keyword) o).val;
-            if (o instanceof Color) {
-                Color c = (Color) o;
-                int alpha = c.getAlpha();
-                if (alpha != 255)
-                    return (T) String.format("#%06x%02x", ((Color) o).getRGB() & 0x00ffffff, alpha);
-                return (T) String.format("#%06x", ((Color) o).getRGB() & 0x00ffffff);
-            }
-
-            return (T) o.toString();
+            return (T) toString(o);
         }
 
         return null;
@@ -207,6 +200,41 @@
         return null;
     }
 
+    private static String toString(Object o) {
+        if (o instanceof Keyword)
+            return ((Keyword) o).val;
+        if (o instanceof Color) {
+            Color c = (Color) o;
+            int alpha = c.getAlpha();
+            if (alpha != 255)
+                return String.format("#%06x%02x", ((Color) o).getRGB() & 0x00ffffff, alpha);
+            return String.format("#%06x", ((Color) o).getRGB() & 0x00ffffff);
+        }
+        return o.toString();
+    }
+
+    private static String[] toStringArray(Object o) {
+        if (o instanceof String[]) {
+            return (String[]) o;
+        }
+        if (o instanceof List) {
+            List<?> l = (List<?>) o;
+            String[] a = new String[l.size()];
+            for (int i = 0; i < l.size(); ++i) {
+                String s = toString(l.get(i));
+                if (s == null)
+                    return null;
+                else
+                    a[i] = s;
+            }
+            return a;
+        }
+        String s = toString(o);
+        if (s != null)
+            return new String[] {s};
+        return null;
+    }
+
     private static float[] toFloatArray(Object o) {
         if (o instanceof float[])
             return (float[]) o;
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java	(working copy)
@@ -24,6 +24,8 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+import org.openstreetmap.josm.data.osm.TagMap;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.search.SearchCompiler;
 import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
@@ -34,6 +36,7 @@
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
 import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory.NullableArguments;
 import org.openstreetmap.josm.io.XmlWriter;
+import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog;
 import org.openstreetmap.josm.tools.AlphanumComparator;
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.Geometry;
@@ -493,6 +496,32 @@
     }
 
     /**
+     * Gets the first non-null value of the key {@code key} from the object's parent(s).
+     * @param env the environment
+     * @param key the OSM key
+     * @param tagValues a pipe (|) separated list of key=value pairs, same syntax as
+     * {@link AddTagsDialog#parseUrlTagsToKeyValues}. This ignores the child selector.
+     * @return a list of non-null values of the key {@code key} from the object's parent(s)
+     * with the tags in {@code tagValues}
+     * @since xxx
+     */
+    public static List<String> parent_tags(final Environment env, String key, String tagValues) { // NO_UCD (unused code)
+        if (env.osm != null) {
+            String[][] expectedTags = AddTagsDialog.parseUrlTagsToKeyValues(tagValues);
+            TagMap expectedTagMap = new TagMap();
+            for (String[] tag : expectedTags) {
+                expectedTagMap.put(tag[0], tag[1]);
+            }
+            return env.osm.getReferrers().parallelStream().filter(prim -> prim.get(key) != null)
+                    .filter(prim -> expectedTagMap.entrySet().parallelStream().allMatch(
+                            entry -> prim.hasKey(entry.getKey()) && prim.get(entry.getKey()).equals(entry.getValue())))
+                    .map(prim -> prim.get(key)).sorted(AlphanumComparator.getInstance())
+                    .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    /**
      * Gets the value of the key {@code key} from the object's child.
      * @param env the environment
      * @param key the OSM key
@@ -515,6 +544,79 @@
     }
 
     /**
+     * Gets a list of all OSM id's of the object's parent(s) with a specified key.
+     *
+     * @param env      the environment
+     * @param key      the OSM key
+     * @param keyValue the regex value of the OSM key
+     * @return a list of non-null values of the OSM id's from the object's parent(s)
+     * @since xxx
+     */
+    public static List<IPrimitive> parent_osm_primitives(final Environment env, String key, String keyValue) {
+        if (env.parent == null) {
+            if (env.osm != null) {
+                final ArrayList<IPrimitive> parents = new ArrayList<>();
+                for (IPrimitive parent : env.osm.getReferrers()) {
+                    if ((key == null || parent.get(key) != null)
+                            && (keyValue == null || regexp_test(keyValue, parent.get(key)))) {
+                        parents.add(parent);
+                    }
+                }
+                return new ArrayList<>(parents);
+            }
+            return Collections.emptyList();
+        }
+        return Collections.singletonList(env.parent);
+    }
+
+    /**
+     * Gets a list of all OSM id's of the object's parent(s) with a specified key.
+     *
+     * @param env the environment
+     * @param key the OSM key
+     * @return a list of non-null values of the OSM id's from the object's parent(s)
+     * @since xxx
+     */
+    public static List<IPrimitive> parent_osm_primitives(final Environment env, String key) { // NO_UCD (unused code)
+        return parent_osm_primitives(env, key, null);
+    }
+
+    /**
+     * Gets a list of all OSM id's of the object's parent(s).
+     *
+     * @param env the environment
+     * @return a list of non-null values of the OSM id's from the object's parent(s)
+     * @since xxx
+     */
+    public static List<IPrimitive> parent_osm_primitives(final Environment env) { // NO_UCD (unused code)
+        return parent_osm_primitives(env, null, null);
+    }
+
+    /**
+     * Convert Primitives to a string
+     *
+     * @param primitives The primitives to convert
+     * @return A list of strings in the format type + id (in the list order)
+     * @see SimplePrimitiveId#toSimpleId
+     * @since xxx
+     */
+    public static List<String> convert_primitives_to_string(List<IPrimitive> primitives) {
+        return primitives.stream().map(Functions::convert_primitive_to_string).collect(Collectors.toList());
+    }
+
+    /**
+     * Convert a primitive to a string
+     *
+     * @param primitive The primitive to convert
+     * @return A string in the format type + id
+     * @see SimplePrimitiveId#toSimpleId
+     * @since xxx
+     */
+    public static String convert_primitive_to_string(IPrimitive primitive) {
+        return SimplePrimitiveId.toSimpleId(primitive);
+    }
+
+    /**
      * Returns the lowest distance between the OSM object and a GPX point
      * <p>
      * @param env the environment
Index: src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java	(working copy)
@@ -29,6 +29,7 @@
 import org.openstreetmap.josm.gui.tagging.presets.items.CheckGroup;
 import org.openstreetmap.josm.gui.tagging.presets.items.Combo;
 import org.openstreetmap.josm.gui.tagging.presets.items.ComboMultiSelect;
+import org.openstreetmap.josm.gui.tagging.presets.items.Implies;
 import org.openstreetmap.josm.gui.tagging.presets.items.ItemSeparator;
 import org.openstreetmap.josm.gui.tagging.presets.items.Key;
 import org.openstreetmap.josm.gui.tagging.presets.items.Label;
@@ -142,6 +143,7 @@
         parser.map("item_separator", ItemSeparator.class);
         parser.mapBoth("chunk", Chunk.class);
         parser.map("reference", Reference.class);
+        parser.map("implies", Implies.class);
         return parser;
     }
 
@@ -314,6 +316,9 @@
                         } else if (o instanceof Key && ((Key) o).value == null) {
                             ((Key) o).value = ""; // Fix #8530
                         }
+                        if (o instanceof Key) {
+                            Logging.debug(o.toString());
+                        }
                         listEntries.clear();
                         lastrole = null;
                     }
Index: src/org/openstreetmap/josm/gui/tagging/presets/items/Key.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/items/Key.java	(revision 15755)
+++ src/org/openstreetmap/josm/gui/tagging/presets/items/Key.java	(working copy)
@@ -18,6 +18,12 @@
     /** The hardcoded value for key */
     public String value; // NOSONAR
 
+    /** {@code true} if implied */
+    public boolean implied; // NOSONAR
+
+    /** {@code true} if recommended (will add even if it is implied) */
+    public boolean recommended; // NOSONAR
+
     @Override
     public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel, boolean presetInitiallyMatches) {
         return false;
@@ -25,10 +31,23 @@
 
     @Override
     public void addCommands(List<Tag> changedTags) {
-        changedTags.add(asTag());
+        addCommands(changedTags, false);
     }
 
     /**
+     * Adds the new tags to apply to selected OSM primitives when the preset holding
+     * this item is applied.
+     *
+     * @param changedTags The list of changed tags to modify if needed
+     * @param allTags     Add all the tags
+     */
+    public void addCommands(List<Tag> changedTags, boolean allTags) {
+        if (allTags || !implied || recommended) {
+            changedTags.add(asTag());
+        }
+    }
+
+    /**
      * Returns the {@link Tag} set by this item
      * @return the tag
      */
Index: src/org/openstreetmap/josm/io/AbstractReader.java
===================================================================
--- src/org/openstreetmap/josm/io/AbstractReader.java	(revision 15755)
+++ src/org/openstreetmap/josm/io/AbstractReader.java	(working copy)
@@ -326,8 +326,10 @@
             throw new IllegalDataException(e);
         } finally {
             OptionalLong minId = externalIdMap.values().stream().mapToLong(AbstractPrimitive::getUniqueId).min();
-            if (minId.isPresent() && minId.getAsLong() < AbstractPrimitive.currentUniqueId()) {
-                AbstractPrimitive.advanceUniqueId(minId.getAsLong());
+            synchronized (AbstractPrimitive.class) {
+                if (minId.isPresent() && minId.getAsLong() < AbstractPrimitive.currentUniqueId()) {
+                    AbstractPrimitive.advanceUniqueId(minId.getAsLong());
+                }
             }
             progressMonitor.finishTask();
             progressMonitor.removeCancelListener(cancelListener);
Index: src/org/openstreetmap/josm/io/imagery/ImageryReader.java
===================================================================
--- src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 15755)
+++ src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(working copy)
@@ -222,6 +222,7 @@
                         "permission-ref",
                         "country-code",
                         "category",
+                        "source",
                         "icon",
                         "date",
                         TILE_SIZE,
@@ -528,6 +529,9 @@
                         entry.setImageryCategory(category);
                     entry.setImageryCategoryOriginalString(cat);
                     break;
+                case "source":
+                    entry.setSource(accumulator.toString());
+                    break;
                 default: // Do nothing
                 }
                 break;
Index: src/org/openstreetmap/josm/plugins/PluginHandler.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 15755)
+++ src/org/openstreetmap/josm/plugins/PluginHandler.java	(working copy)
@@ -88,7 +88,7 @@
     /**
      * Deprecated plugins that are removed on start
      */
-    static final List<DeprecatedPlugin> DEPRECATED_PLUGINS;
+    public static final List<DeprecatedPlugin> DEPRECATED_PLUGINS;
     static {
         String inCore = tr("integrated into main program");
         String replacedByPlugin = marktr("replaced by new {0} plugin");
Index: src/org/openstreetmap/josm/tools/Access.java
===================================================================
--- src/org/openstreetmap/josm/tools/Access.java	(nonexistent)
+++ src/org/openstreetmap/josm/tools/Access.java	(working copy)
@@ -0,0 +1,694 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+/**
+ * Access tag related utilities
+ *
+ * @author Taylor Smock
+ * @see <a href="https://wiki.openstreetmap.org/wiki/Key:access">Key:access</a>
+ * @since xxx
+ */
+public final class Access {
+    /**
+     * Holds access tags to avoid typos
+     */
+    public enum AccessTags {
+        /** Air, land, and sea */
+        ALL_TRANSPORT_TYPE("all"),
+
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:access">Key:access</a>
+         */
+        ACCESS_KEY("access", ALL_TRANSPORT_TYPE),
+
+        // Access tag values
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dyes">Tag:access%3Dyes</a>
+         */
+        YES("yes"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dofficial">Tag:access%3Dofficial</a>
+         */
+        OFFICIAL("official"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Ddesignated">Tag:access%3Ddesignated</a>
+         */
+        DESIGNATED("designated"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Ddestination">Tag:access%3Ddestination</a>
+         */
+        DESTINATION("destination"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Ddelivery">Tag:access%3Ddelivery</a>
+         */
+        DELIVERY("delivery"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dcustomers">Tag:access%3Dcustomers</a>
+         */
+        CUSTOMERS("customers"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dpermissive">Tag:access%3Dpermissive</a>
+         */
+        PERMISSIVE("permissive"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dagricultural">Tag:access%3Dagricultural</a>
+         */
+        AGRICULTURAL("agricultural"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dforestry">Tag:access%3Dforestry</a>
+         */
+        FORESTRY("forestry"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dprivate">Tag:access%3Dprivate</a>
+         */
+        PRIVATE("private"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Dno">Tag:access%3Dno</a>
+         */
+        NO("no"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Ddiscouraged">Tag:access%3Ddiscouraged</a>
+         */
+        DISCOURAGED("discouraged"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Duse_sidepath">Tag:access%3Duse_sidepath</a>
+         */
+        USE_SIDEPATH("use_sidepath"),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Tag:access%3Ddismount">Tag:access%3Ddismount</a>
+         */
+        DISMOUNT("dismount"),
+        // Land
+        /** Land transport types */
+        LAND_TRANSPORT_TYPE("land", ALL_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:vehicle">Key:vehicle</a>
+         */
+        VEHICLE("vehicle", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:motor_vehicle">Key:motor_vehicle</a>
+         */
+        MOTOR_VEHICLE("motor_vehicle", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:trailer">Key:trailer</a>
+         */
+        TRAILER("trailer", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:foot">Key:foot</a> */
+        FOOT("foot", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:ski">Key:ski</a> */
+        SKI("ski", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:inline_skates">Key:inline_skates</a>
+         */
+        INLINE_SKATES("inline_skates", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:ice_skates">Key:ice_skates</a>
+         */
+        ICE_SKATES("ice_skates", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:horse">Key:horse</a>
+         */
+        HORSE("horse", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:bicycle">Key:bicycle</a>
+         */
+        BICYCLE("bicycle", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:carriage">Key:carriage</a>
+         */
+        CARRIAGE("carriage", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:caravan">Key:caravan</a>
+         */
+        CARAVAN("caravan", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:motorcycle">Key:motorcycle</a>
+         */
+        MOTORCYCLE("motorcycle", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:moped">Key:moped</a>
+         */
+        MOPED("moped", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:mofa">Key:mofa</a> */
+        MOFA("mofa", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:motorcar">Key:motorcar</a>
+         */
+        MOTORCAR("motorcar", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:motorhome">Key:motorhome</a>
+         */
+        MOTORHOME("motorhome", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:psv">Key:psv</a> */
+        PSV("psv", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:bus">Key:bus</a> */
+        BUS("bus", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:taxi">Key:taxi</a> */
+        TAXI("taxi", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:tourist_bus">Key:tourist_bus</a>
+         */
+        TOURIST_BUS("tourist_bus", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:goods">Key:goods</a>
+         */
+        GOODS("goods", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:hgv">Key:hgv</a> */
+        HGV("hgv", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:atv">Key:atv</a> */
+        ATV("atv", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:snowmobile">Key:snowmobile</a>
+         */
+        SNOWMOBILE("snowmobile", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:hgv_articulated">Key:hgv_articulated</a>
+         */
+        HGV_ARTICULATED("hgv_articulated", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:ski">Key:ski</a> */
+        SKI_NORDIC("ski:nordic", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:ski">Key:ski</a> */
+        SKI_ALPINE("ski:alpine", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:ski">Key:ski</a> */
+        SKI_TELEMARK("ski:telemark", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:coach">Key:coach</a>
+         */
+        COACH("coach", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:golf_cart">Key:golf_cart</a>
+         */
+        GOLF_CART("golf_cart", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:minibus">Key:minibus</a>
+         */
+        MINIBUS("minibus", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:share_taxi">Key:share_taxi</a>
+         */
+        SHARE_TAXI("share_taxi", LAND_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:hov">Key:hov</a> */
+        HOV("hov", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:car_sharing">Key:car_sharing</a>
+         */
+        CAR_SHARING("car_sharing", LAND_TRANSPORT_TYPE),
+        /**
+         * Routers should default to {@code yes}, regardless of higher access rules,
+         * assuming it is navigatible by vehicle
+         *
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:emergency">Key:emergency</a>
+         */
+        EMERGENCY("emergency", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:hazmat">Key:hazmat</a>
+         */
+        HAZMAT("hazmat", LAND_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:disabled">Key:disabled</a>
+         */
+        DISABLED("disabled", LAND_TRANSPORT_TYPE),
+
+        // Water
+        /** Water transport type */
+        WATER_TRANSPORT_TYPE("water", ALL_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:swimming">Key:swimming</a>
+         */
+        SWIMMING("swimming", WATER_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:boat">Key:boat</a> */
+        BOAT("boat", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:fishing_vessel">Key:fishing_vessel</a>
+         */
+        FISHING_VESSEL("fishing_vessel", WATER_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:ship">Key:ship</a> */
+        SHIP("ship", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:motorboat">Key:motorboat</a>
+         */
+        MOTORBOAT("motorboat", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:sailboat">Key:sailboat</a>
+         */
+        SAILBOAT("sailboat", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:canoe">Key:canoe</a>
+         */
+        CANOE("canoe", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:passenger">Key:passenger</a>
+         */
+        PASSENGER("passenger", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:cargo">Key:cargo</a>
+         */
+        CARGO("cargo", WATER_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:isps">Key:isps</a> */
+        ISPS("isps", WATER_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:bulk">Key:bulk</a> */
+        BULK("bulk", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:tanker">Key:tanker</a>
+         */
+        TANKER("tanker", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href=
+         *      "https://wiki.openstreetmap.org/wiki/Key:container">Key:container</a>
+         */
+        CONTAINER("container", WATER_TRANSPORT_TYPE),
+        /** @see <a href="https://wiki.openstreetmap.org/wiki/Key:imdg">Key:imdg</a> */
+        IMDG("imdg", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:tanker">Key:tanker</a>
+         */
+        TANKER_GAS("tanker:gas", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:tanker">Key:tanker</a>
+         */
+        TANKER_OIL("tanker:oil", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:tanker">Key:tanker</a>
+         */
+        TANKER_CHEMICAL("tanker:chemical", WATER_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:tanker">Key:tanker</a>
+         */
+        TANKER_SINGLEHULL("tanker:singlehull", WATER_TRANSPORT_TYPE),
+
+        // Trains
+        /** Rail transport type */
+        RAIL_TRANSPORT_TYPE("rail", ALL_TRANSPORT_TYPE),
+        /**
+         * @see <a href="https://wiki.openstreetmap.org/wiki/Key:train">Key:train</a>
+         */
+        TRAIN("train", RAIL_TRANSPORT_TYPE);
+
+        private String key;
+        private AccessTags type;
+
+        AccessTags(String key) {
+            this.key = key;
+            this.type = null;
+        }
+
+        AccessTags(String key, AccessTags type) {
+            this.key = key;
+            this.type = type;
+        }
+
+        /**
+         * @return The key for the enum
+         */
+        public String getKey() {
+            return key;
+        }
+
+        /**
+         * @return The AccessTags transport type
+         *         (RAIL_TRANSPORT_TYPE/WATER_TRANSPORT_TYPE/etc)
+         */
+        public AccessTags getTransportType() {
+            return type;
+        }
+
+        /**
+         * Check if this is a parent transport type (air/sea/water/all)
+         *
+         * @param potentialDescendant The AccessTags that we want to check
+         * @return true if valueOf is a child transport type of this
+         */
+        public boolean parentOf(AccessTags potentialDescendant) {
+            AccessTags tmp = potentialDescendant;
+            while (tmp != null && tmp != this) {
+                tmp = tmp.getTransportType();
+            }
+            return tmp == this;
+        }
+
+        /**
+         * Get the enum that matches the mode
+         *
+         * @param childrenMode The mode to get the access tag
+         * @return The AccessTags enum that matches the childrenMode, or null
+         */
+        public static AccessTags get(String childrenMode) {
+            for (AccessTags value : values()) {
+                if (value.getKey().equalsIgnoreCase(childrenMode)) {
+                    return value;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Get access tags that match a certain type
+         *
+         * @param type {@link AccessTags#WATER_TRANSPORT_TYPE},
+         *             {@link AccessTags#LAND_TRANSPORT_TYPE},
+         *             {@link AccessTags#RAIL_TRANSPORT_TYPE}, or
+         *             {@link AccessTags#ALL_TRANSPORT_TYPE}
+         * @return A collection of access tags that match the given transport type
+         */
+        public static Collection<AccessTags> getByTransportType(AccessTags type) {
+            return Arrays.stream(values()).filter(type::parentOf).collect(Collectors.toList());
+        }
+    }
+
+    /**
+     * The key for children modes for the map, see {@link Access#getAccessMethods}
+     */
+    public static final String CHILDREN = "children";
+
+    /** The key for parent modes for the map, see {@link Access#getAccessMethods} */
+    public static final String PARENT = "parent";
+
+    /** This set has keys that indicate that access is possible */
+    private static final Set<String> POSITIVE_ACCESS = new HashSet<>(Arrays.asList(AccessTags.YES, AccessTags.OFFICIAL,
+            AccessTags.DESIGNATED, AccessTags.DESTINATION, AccessTags.DELIVERY, AccessTags.CUSTOMERS,
+            AccessTags.PERMISSIVE, AccessTags.AGRICULTURAL, AccessTags.FORESTRY).stream().map(AccessTags::getKey)
+            .collect(Collectors.toSet()));
+
+    /** This set has all basic restriction values (yes/no/permissive/private/...) */
+    private static final Set<String> RESTRICTION_VALUES = new HashSet<>(
+            Arrays.asList(AccessTags.PRIVATE, AccessTags.NO).stream().map(AccessTags::getKey)
+                    .collect(Collectors.toSet()));
+
+    /** This set has transport modes (access/foot/ski/motor_vehicle/vehicle/...) */
+    private static final Set<String> TRANSPORT_MODES = new HashSet<>(
+            Arrays.asList(AccessTags.ACCESS_KEY, AccessTags.FOOT, AccessTags.SKI, AccessTags.INLINE_SKATES,
+                    AccessTags.ICE_SKATES, AccessTags.HORSE, AccessTags.VEHICLE, AccessTags.BICYCLE,
+                    AccessTags.CARRIAGE, AccessTags.TRAILER, AccessTags.CARAVAN, AccessTags.MOTOR_VEHICLE,
+                    AccessTags.MOTORCYCLE, AccessTags.MOPED, AccessTags.MOFA, AccessTags.MOTORCAR, AccessTags.MOTORHOME,
+                    AccessTags.PSV, AccessTags.BUS, AccessTags.TAXI, AccessTags.TOURIST_BUS, AccessTags.GOODS,
+                    AccessTags.HGV, AccessTags.AGRICULTURAL, AccessTags.ATV, AccessTags.SNOWMOBILE,
+                    AccessTags.HGV_ARTICULATED, AccessTags.SKI_NORDIC, AccessTags.SKI_ALPINE, AccessTags.SKI_TELEMARK,
+                    AccessTags.COACH, AccessTags.GOLF_CART, AccessTags.MINIBUS, AccessTags.SHARE_TAXI,
+                    AccessTags.CAR_SHARING, AccessTags.HOV, AccessTags.EMERGENCY, AccessTags.HAZMAT,
+                    AccessTags.DISABLED
+            ).stream().map(AccessTags::getKey).collect(Collectors.toSet()));
+
+    /**
+     * Map&lt;Access Method, Map&lt;Parent/Child, List&lt;Access Methods&gt;&gt;&gt;
+     */
+    private static final Map<String, Map<String, List<String>>> accessMethods = new HashMap<>();
+    static {
+        RESTRICTION_VALUES.addAll(POSITIVE_ACCESS);
+        defaultInheritance();
+    }
+
+    private Access() {
+        // Hide the constructor
+    }
+
+    /**
+     * Create the default access inheritance, as defined at <a href=
+     * "https://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">Key:access#Transport_mode_restrictions</a>
+     */
+    private static void defaultInheritance() {
+        addMode(null, AccessTags.ACCESS_KEY);
+
+        // Land
+        addModes(AccessTags.ACCESS_KEY, AccessTags.FOOT, AccessTags.SKI, AccessTags.INLINE_SKATES,
+                AccessTags.ICE_SKATES, AccessTags.HORSE, AccessTags.VEHICLE);
+        addModes(AccessTags.SKI, AccessTags.SKI_NORDIC, AccessTags.SKI_ALPINE, AccessTags.SKI_TELEMARK);
+        addModes(AccessTags.VEHICLE, AccessTags.BICYCLE, AccessTags.CARRIAGE, AccessTags.TRAILER,
+                AccessTags.MOTOR_VEHICLE);
+        addModes(AccessTags.TRAILER, AccessTags.CARAVAN);
+        addModes(AccessTags.MOTOR_VEHICLE, AccessTags.MOTORCYCLE, AccessTags.MOPED, AccessTags.MOFA,
+                AccessTags.MOTORCAR, AccessTags.MOTORHOME, AccessTags.TOURIST_BUS, AccessTags.COACH, AccessTags.GOODS,
+                AccessTags.HGV, AccessTags.AGRICULTURAL, AccessTags.GOLF_CART, AccessTags.ATV, AccessTags.SNOWMOBILE,
+                AccessTags.PSV, AccessTags.HOV, AccessTags.CAR_SHARING, AccessTags.EMERGENCY, AccessTags.HAZMAT,
+                AccessTags.DISABLED);
+        addMode(AccessTags.HGV, AccessTags.HGV_ARTICULATED);
+        addModes(AccessTags.PSV, AccessTags.BUS, AccessTags.MINIBUS, AccessTags.SHARE_TAXI, AccessTags.TAXI);
+
+        // Water
+        addModes(AccessTags.ACCESS_KEY, AccessTags.SWIMMING, AccessTags.BOAT, AccessTags.FISHING_VESSEL,
+                AccessTags.SHIP);
+        addModes(AccessTags.BOAT, AccessTags.MOTORBOAT, AccessTags.SAILBOAT, AccessTags.CANOE);
+        addModes(AccessTags.SHIP, AccessTags.PASSENGER, AccessTags.CARGO, AccessTags.ISPS);
+        addModes(AccessTags.CARGO, AccessTags.BULK, AccessTags.TANKER, AccessTags.CONTAINER, AccessTags.IMDG);
+        addModes(AccessTags.TANKER, AccessTags.TANKER_GAS, AccessTags.TANKER_OIL, AccessTags.TANKER_CHEMICAL,
+                AccessTags.TANKER_SINGLEHULL);
+
+        // Rail
+        addModes(AccessTags.ACCESS_KEY, AccessTags.TRAIN);
+    }
+
+    /**
+     * Add multiple modes with a common parent
+     *
+     * @param parent The parent of all the modes
+     * @param modes  The modes to add
+     */
+    public static void addModes(AccessTags parent, AccessTags... modes) {
+        for (AccessTags mode : modes) {
+            addMode(parent, mode);
+        }
+    }
+
+    /**
+     * Add modes to a list, modifying parents as needed
+     *
+     * @param mode   The mode to be added
+     * @param parent The parent of the mode
+     */
+    public static void addMode(AccessTags parent, AccessTags mode) {
+        Objects.requireNonNull(mode, "Mode must not be null");
+        if (parent != null) {
+            Map<String, List<String>> parentMap = accessMethods.getOrDefault(parent.getKey(), new HashMap<>());
+            accessMethods.putIfAbsent(parent.getKey(), parentMap);
+            List<String> parentChildren = parentMap.getOrDefault(CHILDREN, new ArrayList<>());
+            if (!parentChildren.contains(mode.getKey()))
+                parentChildren.add(mode.getKey());
+            parentMap.putIfAbsent(CHILDREN, parentChildren);
+        }
+        Map<String, List<String>> modeMap = accessMethods.getOrDefault(mode.getKey(), new HashMap<>());
+        accessMethods.putIfAbsent(mode.getKey(), modeMap);
+        List<String> modeParent = modeMap.getOrDefault(PARENT,
+                Collections.singletonList(parent == null ? null : parent.getKey()));
+        modeMap.putIfAbsent(PARENT, modeParent);
+    }
+
+    /**
+     * Get the number of parents a mode has
+     *
+     * @param mode The mode with parents
+     * @return The number of parents the mode has
+     */
+    public static int depth(String mode) {
+        String tempMode = mode;
+        int maxCount = accessMethods.size();
+        while (tempMode != null && maxCount > 0) {
+            tempMode = accessMethods.getOrDefault(tempMode, Collections.emptyMap())
+                    .getOrDefault(PARENT, Collections.emptyList()).get(0);
+            if (tempMode != null)
+                maxCount--;
+        }
+        return accessMethods.size() - maxCount;
+    }
+
+    /**
+     * Expand access modes to cover the children of that access mode (currently only
+     * supports the default hierarchy)
+     *
+     * @param mode   The transport mode
+     * @param access The access value (the children transport modes inherit this
+     *               value)
+     * @return A map of the mode and its children (does not include parents)
+     */
+    public static Map<String, String> expandAccessMode(String mode, String access) {
+        return expandAccessMode(mode, access, AccessTags.ALL_TRANSPORT_TYPE);
+    }
+
+    /**
+     * Expand access modes to cover the children of that access mode (currently only
+     * supports the default hierarchy)
+     *
+     * @param mode          The transport mode
+     * @param access        The access value (the children transport modes inherit
+     *                      this value)
+     * @param transportType {@link AccessTags#ALL_TRANSPORT_TYPE},
+     *                      {@link AccessTags#LAND_TRANSPORT_TYPE},
+     *                      {@link AccessTags#WATER_TRANSPORT_TYPE},
+     *                      {@link AccessTags#RAIL_TRANSPORT_TYPE}
+     * @return A map of the mode and its children (does not include parents)
+     */
+    public static Map<String, String> expandAccessMode(String mode, String access, AccessTags transportType) {
+        Map<String, String> accessModes = new HashMap<>();
+        accessModes.put(mode, access);
+        if (accessMethods.containsKey(mode)) {
+            for (String childrenMode : accessMethods.getOrDefault(mode, Collections.emptyMap()).getOrDefault(CHILDREN,
+                    Collections.emptyList())) {
+                if (transportType.parentOf(AccessTags.get(childrenMode)))
+                    accessModes.putAll(expandAccessMode(childrenMode, access, transportType));
+            }
+        }
+        return accessModes;
+    }
+
+    /**
+     * Merge two access maps (more specific wins)
+     *
+     * @param map1 A map with access values (see {@link Access#expandAccessMode})
+     * @param map2 A map with access values (see {@link Access#expandAccessMode})
+     * @return The merged map
+     */
+    public static Map<String, String> mergeMaps(Map<String, String> map1, Map<String, String> map2) {
+        Map<String, String> merged;
+        if (map1.keySet().containsAll(map2.keySet())) {
+            merged = new HashMap<>(map1);
+            merged.putAll(map2);
+        } else { // if they don't overlap or if map2 contains all of map1
+            merged = new HashMap<>(map2);
+            merged.putAll(map1);
+        }
+        return merged;
+    }
+
+    /**
+     * Get the set of values that can generally be considered to be accessible
+     *
+     * @return A set of values that can be used for routing purposes (unmodifiable)
+     */
+    public static Set<String> getPositiveAccessValues() {
+        return Collections.unmodifiableSet(POSITIVE_ACCESS);
+    }
+
+    /**
+     * Get the valid restriction values ({@code unknown} is not included). See
+     *
+     * @return Valid values for restrictions (unmodifiable)
+     * @see <a href=
+     *      "https://wiki.openstreetmap.org/wiki/Key:access#List_of_possible_values">Key:access#List_of_possible_values</a>
+     */
+    public static Set<String> getRestrictionValues() {
+        return Collections.unmodifiableSet(RESTRICTION_VALUES);
+    }
+
+    /**
+     * Get the valid transport modes. See
+     *
+     * @return Value transport modes (unmodifiable)
+     * @see <a href=
+     *      "https://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">Key:access#Transport_mode_restrictions</a>
+     */
+    public static Set<String> getTransportModes() {
+        return Collections.unmodifiableSet(TRANSPORT_MODES);
+    }
+
+    /**
+     * Get the access method hierarchy.
+     *
+     * @return The hierarchy for access modes (unmodifiable)
+     * @see <a href=
+     *      "https://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">Key:access#Transport_mode_restrictions</a>
+     */
+    public static Map<String, Map<String, List<String>>> getAccessMethods() {
+        Map<String, Map<String, List<String>>> map = new HashMap<>();
+        for (Entry<String, Map<String, List<String>>> entry : map.entrySet()) {
+            Map<String, List<String>> tMap = new HashMap<>();
+            entry.getValue().forEach((key, list) -> tMap.put(key, Collections.unmodifiableList(list)));
+            map.put(entry.getKey(), Collections.unmodifiableMap(tMap));
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Get the implied access values for a primitive
+     *
+     * @param primitive     A primitive with access values
+     * @param transportType {@link AccessTags#ALL_TRANSPORT_TYPE},
+     *                      {@link AccessTags#LAND_TRANSPORT_TYPE},
+     *                      {@link AccessTags#WATER_TRANSPORT_TYPE},
+     *                      {@link AccessTags#RAIL_TRANSPORT_TYPE}
+     * @return The implied access values (for example, "hgv=designated" adds
+     *         "hgv_articulated=designated")
+     */
+    public static Map<String, String> getAccessValues(OsmPrimitive primitive, AccessTags transportType) {
+        Map<String, String> accessValues = new HashMap<>();
+        TRANSPORT_MODES.stream().filter(primitive::hasKey)
+                .map(mode -> expandAccessMode(mode, primitive.get(mode), transportType))
+                .forEach(modeAccess -> {
+                    Map<String, String> tMap = mergeMaps(accessValues, modeAccess);
+                    accessValues.clear();
+                    accessValues.putAll(tMap);
+                });
+        return accessValues;
+    }
+
+    /**
+     * Expand a map of access values
+     *
+     * @param accessValues A map of mode, access type values
+     * @return The expanded access values
+     */
+    public static Map<String, String> expandAccessValues(Map<String, String> accessValues) {
+        Map<String, String> modes = new HashMap<>();
+        List<Map<String, String>> list = accessValues.entrySet().stream()
+                .map(entry -> expandAccessMode(entry.getKey(), entry.getValue()))
+                .sorted(Comparator.comparingInt(Map::size))
+                .collect(Collectors.toCollection(ArrayList::new));
+        Collections.reverse(list);
+        for (Map<String, String> access : list) {
+            modes = mergeMaps(modes, access);
+        }
+        return modes;
+    }
+}
Index: test/unit/org/openstreetmap/josm/command/MoveCommandTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/command/MoveCommandTest.java	(revision 15755)
+++ test/unit/org/openstreetmap/josm/command/MoveCommandTest.java	(working copy)
@@ -10,18 +10,24 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.command.CommandTest.CommandTestDataWithRelation;
+import org.openstreetmap.josm.data.UndoRedoHandler;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveData;
 import org.openstreetmap.josm.data.osm.User;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.visitor.MergeSourceBuildingVisitor;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
@@ -39,7 +45,7 @@
      */
     @Rule
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().i18n().projection();
+    public JOSMTestRules test = new JOSMTestRules().preferences().i18n().projection().commands();
     private CommandTestDataWithRelation testData;
 
     /**
@@ -272,4 +278,46 @@
             .suppress(Warning.NONFINAL_FIELDS)
             .verify();
     }
+
+    /**
+     * Test {@link MoveCommand#executeCommand()} and {@link MoveCommand#undoCommand()} with {@link AddPrimitivesCommand}
+     */
+    @Test
+    public void testUndoRedoWithAddPrimitivesCommand() {
+        final DataSet to = new DataSet();
+    final DataSet from = new DataSet();
+    final Way way1 = TestUtils.newWay("highway=tertiary", new Node(new LatLon(0, 0)),
+            new Node(new LatLon(0.1, 0.1)));
+    way1.getNodes().stream().forEach(node -> from.addPrimitive(node));
+    from.addPrimitive(way1);
+    from.addPrimitive(new Node(new LatLon(-0.1, 0.1)));
+
+    from.setSelected(way1);
+    MergeSourceBuildingVisitor builder = new MergeSourceBuildingVisitor(from);
+    DataSet hull = builder.build();
+
+    List<PrimitiveData> primitiveAddData = hull.allPrimitives().stream().map(OsmPrimitive::save)
+            .collect(Collectors.toList());
+
+    UndoRedoHandler.getInstance().add(new SequenceCommand("random sequence", new AddPrimitivesCommand(primitiveAddData, primitiveAddData, to)));
+
+    Node tNode = (Node) to.getPrimitiveById(way1.firstNode());
+
+    UndoRedoHandler.getInstance().add(new MoveCommand(tNode, LatLon.ZERO));
+
+    Assert.assertTrue(UndoRedoHandler.getInstance().getRedoCommands().isEmpty());
+    Assert.assertEquals(2, UndoRedoHandler.getInstance().getUndoCommands().size());
+
+    UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size());
+    Assert.assertTrue(UndoRedoHandler.getInstance().getUndoCommands().isEmpty());
+    Assert.assertEquals(2, UndoRedoHandler.getInstance().getRedoCommands().size());
+    UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size());
+
+    UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size());
+    UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size());
+
+    UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size());
+    UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size());
+
+    }
 }
Index: test/unit/org/openstreetmap/josm/data/validation/tests/IntersectionIssuesTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/IntersectionIssuesTest.java	(nonexistent)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/IntersectionIssuesTest.java	(working copy)
@@ -0,0 +1,325 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.validation.tests;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.validation.TestError;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.Utils;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * JUnit Test of "Intersection Issues" validation test.
+ */
+public class IntersectionIssuesTest {
+
+    /**
+     * Setup test.
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().projection();
+
+    private static List<TestError> test(DataSet ds) throws Exception {
+        IntersectionIssues test = new IntersectionIssues();
+        test.initialize();
+        test.startTest(null);
+        for (Way w : ds.getWays()) {
+            test.visit(w);
+        }
+        test.endTest();
+        return test.getErrors();
+    }
+
+    private static Collection<OsmPrimitive> createCollection(OsmPrimitive... osmPrimitives) {
+        HashSet<OsmPrimitive> collection = new HashSet<>();
+        for (OsmPrimitive primitive : osmPrimitives) {
+            if (collection.contains(primitive)) continue;
+            if (primitive instanceof Node) {
+                collection.add(primitive);
+            } else if (primitive instanceof Way) {
+                collection.addAll(((Way) primitive).getNodes());
+                collection.add(primitive);
+            } else if (primitive instanceof Relation) {
+                Relation relation = (Relation) primitive;
+                collection.add(relation);
+                for (OsmPrimitive tPrim : relation.getMemberPrimitives()) {
+                    collection.addAll(createCollection(tPrim));
+                }
+            }
+        }
+        return collection;
+    }
+
+    /**
+     * This test area has 3 ways, where two have the same name and one has a
+     * different name where there is a short disconnect between the two with
+     * the same name.
+     * @return The collection of ways to test.
+     */
+    private static Collection<OsmPrimitive> getTestArea1() {
+        Node node1 = new Node(new LatLon(43.85619540309, 18.36535033094));
+        Node node2 = new Node(new LatLon(43.85658651031, 18.36534961159));
+        Node node3 = new Node(new LatLon(43.85662897034, 18.36534953349));
+        Node node4 = new Node(new LatLon(43.85694640771, 18.36534894963));
+        Node node5 = new Node(new LatLon(43.85658576291, 18.36456808743));
+        Node node6 = new Node(new LatLon(43.8566296379, 18.36604757608));
+
+        Way way1 = TestUtils.newWay("highway=residential name=\"Test Road 1\"",
+                node1, node2);
+        Way way2 = TestUtils.newWay("highway=residential name=\"Test Road 1\"",
+                node3, node4);
+        Way way3 = TestUtils.newWay("highway=residential name=\"Test Road 2\"",
+                node5, node2, node3, node6);
+
+        return createCollection(way1, way2, way3);
+    }
+
+    private static Collection<OsmPrimitive> getTestArea2() {
+        Node node1 = new Node(new LatLon(43.85641709632, 18.36725849681));
+        Node node2 = new Node(new LatLon(43.85680820208, 18.36725777746));
+        Node node3 = new Node(new LatLon(43.85685066196, 18.36725769936));
+        Node node4 = new Node(new LatLon(43.85716809815, 18.3672571155));
+        Node node5 = new Node(new LatLon(43.85680745469, 18.3664762533));
+        Node node6 = new Node(new LatLon(43.85685132951, 18.36795574195));
+        Way way1 = TestUtils.newWay("highway=residential name=\"Test Road 1\"",
+                node1, node2);
+        Way way2 = TestUtils.newWay("highway=residential name=\"Test Road 1\"",
+                node2, node3);
+        Way way3 = TestUtils.newWay("highway=residential name=\"Test Road 1\"",
+                node3, node4);
+        Way way4 = TestUtils.newWay("highway=residential name=\"Test Road 2\"",
+                node5, node2);
+        Way way5 = TestUtils.newWay("highway=residential name=\"Test Road 2\"",
+                node3, node6);
+
+        return createCollection(way1, way2, way3, way4, way5);
+    }
+
+    private static Collection<OsmPrimitive> getTestArea3() {
+        Node node1 = new Node(new LatLon(43.85570051259, 18.36651114378));
+        Node node2 = new Node(new LatLon(43.85613408344, 18.36651034633));
+        Node node3 = new Node(new LatLon(43.85645152344, 18.36650976248));
+        Node node4 = new Node(new LatLon(43.85609087565, 18.36572890027));
+        Node node5 = new Node(new LatLon(43.85609162303, 18.3665104064));
+        Node node6 = new Node(new LatLon(43.85613475101, 18.36720838893));
+        Way way1 = TestUtils.newWay("highway=residential name=\"Test Road 1\"",
+                node1, node2, node3);
+        Way way2 = TestUtils.newWay("highway=residential name=\"Test Road 2\"",
+                node4, node5, node2, node6);
+
+        return createCollection(way1, way2);
+    }
+
+    /**
+     * This is a section of road that should be found (almost overlapping)
+     * @return A collection of ways and nodes to be tested
+     */
+    private static Collection<OsmPrimitive> getTestAreaRealWorld1() {
+        // This was at https://www.openstreetmap.org/node/6123937677
+        Node node1 = new Node(new LatLon(16.4151329, -95.0267841));
+        Node node2 = new Node(new LatLon(16.4150313, -95.0267948));
+        Node node3 = new Node(new LatLon(16.4149297, -95.0268057));
+        Way way1 = TestUtils.newWay("highway=residential name=Calle Los Olivos",
+                node1, node3);
+        Way way2 = TestUtils.newWay(
+                "highway=residential name=Calle Camino Carretero (La Amistad)",
+                node1, node2, node3);
+
+        return createCollection(way1, way2);
+    }
+
+    /**
+     * This is a section of road that is almost overlapping
+     * @return A collection of ways and nodes to be tested
+     */
+    private static Collection<OsmPrimitive> getTestAreaRealWorld2() {
+        // this was at https://www.openstreetmap.org/way/435783782
+        Node node1 = new Node(new LatLon(38.9881335, 31.1968857));
+        Node node2 = new Node(new LatLon(38.9879932, 31.1968928));
+        Node node3 = new Node(new LatLon(38.9877181, 31.1969176));
+        Node node4 = new Node(new LatLon(38.9873522, 31.1969247));
+        Node node5 = new Node(new LatLon(38.9870915, 31.1969116));
+
+        Way way1 = TestUtils.newWay("highway=track", node1, node2, node3, node4, node5);
+        Way way2 = TestUtils.newWay("highway=track", node1, node5);
+
+        return createCollection(way1, way2);
+    }
+
+    /**
+     * This is a roundabout that happened to be a false positive for the
+     * disconnected road test
+     * @return A collection of ways and nodes to be tested
+     */
+    private static Collection<OsmPrimitive> getTestAreaRealWorld3() {
+        // this was at https://www.openstreetmap.org/way/50635342
+        Node node1 = new Node(new LatLon(38.3260143, 26.3085291));
+
+        // This probably should have been a junction=roundabout, but I don't know that for certain
+        Way way1 = TestUtils.newWay("highway=secondary name=\"Atatürk Blv.\" oneway=yes ref=D300", node1);
+        way1.addNode(new Node(new LatLon(38.3260353, 26.308504)));
+        way1.addNode(new Node(new LatLon(38.3260507, 26.308473)));
+        way1.addNode(new Node(new LatLon(38.3260596, 26.308438)));
+        way1.addNode(new Node(new LatLon(38.3260612, 26.3083978)));
+        way1.addNode(new Node(new LatLon(38.3260542, 26.3083586)));
+        way1.addNode(new Node(new LatLon(38.326039, 26.3083233)));
+        way1.addNode(new Node(new LatLon(38.3260169, 26.3082945)));
+        way1.addNode(new Node(new LatLon(38.3259895, 26.3082745)));
+        way1.addNode(new Node(new LatLon(38.3259562, 26.3082644)));
+        way1.addNode(new Node(new LatLon(38.325922, 26.3082673)));
+        way1.addNode(new Node(new LatLon(38.3258899, 26.3082829)));
+        way1.addNode(new Node(new LatLon(38.3258629, 26.3083099)));
+        way1.addNode(new Node(new LatLon(38.3258434, 26.3083458)));
+        way1.addNode(new Node(new LatLon(38.325833, 26.3083874)));
+        way1.addNode(new Node(new LatLon(38.3258326, 26.3084308)));
+        way1.addNode(new Node(new LatLon(38.3258422, 26.3084723)));
+        way1.addNode(new Node(new LatLon(38.3258609, 26.3085085)));
+        way1.addNode(new Node(new LatLon(38.3258821, 26.3085321)));
+        way1.addNode(new Node(new LatLon(38.3259071, 26.3085484)));
+        way1.addNode(new Node(new LatLon(38.3259345, 26.3085564)));
+        way1.addNode(new Node(new LatLon(38.3259626, 26.3085558)));
+        way1.addNode(new Node(new LatLon(38.3259898, 26.3085465)));
+        way1.addNode(node1);
+
+        Way way2 = TestUtils.newWay("highway=secondary name=\"Atatürk Blv.\" oneway=yes ref=D300", node1);
+        way2.addNode(new Node(new LatLon(38.3259914, 26.3086145)));
+        way2.addNode(new Node(new LatLon(38.3259765, 26.3087124)));
+        way2.addNode(new Node(new LatLon(38.3259728, 26.3087982)));
+
+        return createCollection(way1, way2);
+    }
+
+    private static Collection<OsmPrimitive> getTestAreaRealWorld4() {
+        // This was at https://www.openstreetmap.org/way/584296023
+        Node node1 = new Node(new LatLon(14.3272233, 120.9600503));
+        Node node2 = new Node(new LatLon(14.326624, 120.9605805));
+        Way way1 = TestUtils.newWay("highway=service oneway=yes name=\'Congressional Avenue Transit Lane\"", node1,
+                new Node(new LatLon(14.3270856, 120.9601202)),
+                new Node(new LatLon(14.326801, 120.9603738)), node2);
+        Way way2 = TestUtils.newWay("highway=tertiary name=\"Congressional Avenue\" oneway=yes", node1, node2);
+
+        return createCollection(way1, way2);
+    }
+
+    private static Collection<OsmPrimitive> getTestAreaRealWorld5() {
+        // False positive for disconnected road
+        // This was at https://www.openstreetmap.org/way/375383808
+        Node node1 = new Node(new LatLon(44.4554384, 25.9568208));
+        Node roundaboutStart = new Node(new LatLon(44.4554752, 25.9568265));
+        // Simplified roundabout
+        Way roundabout = TestUtils.newWay("highway=primary junction=roundabout name=\"Șoseaua de Centură\"",
+                roundaboutStart,
+                new Node(new LatLon(44.4555956, 25.9567686)),
+                new Node(new LatLon(44.4556529, 25.9564646)),
+                new Node(new LatLon(44.4554982, 25.9563004)),
+                new Node(new LatLon(44.4553037, 25.9564588)),
+                new Node(new LatLon(44.455302, 25.9566607)),
+                node1, roundaboutStart);
+        Way flare = TestUtils.newWay("highway=primary name=\"Șoseaua de Centură\" oneway=yes",
+                new Node(new LatLon(44.4553062, 25.9571151)),
+                new Node(new LatLon(44.4553669, 25.9569653)),
+                node1);
+        return createCollection(roundabout, flare);
+    }
+
+    private static DataSet createDataSet(Collection<OsmPrimitive> primitives) {
+        DataSet ds = new DataSet();
+        for (Node node : Utils.filteredCollection(primitives, Node.class)) {
+            if (ds.containsNode(node)) continue;
+            ds.addPrimitive(node);
+        }
+        for (Way way : Utils.filteredCollection(primitives, Way.class)) {
+            for (Node node : way.getNodes()) {
+                if (ds.containsNode(node)) continue;
+                ds.addPrimitive(node);
+            }
+            if (ds.containsWay(way)) continue;
+            ds.addPrimitive(way);
+        }
+        return ds;
+    }
+
+    /**
+     * Unit test for {@link IntersectionIssues#checkNearbyEnds}
+     * @throws Exception if any error occurs
+     */
+    @Test
+    public void testCheckNearbyEnds() throws Exception {
+        /** TODO add the following real world areas:
+         * https://www.openstreetmap.org/way/261432285
+         */
+        DataSet area1 = createDataSet(getTestArea1());
+        List<TestError> testResults = test(area1);
+        Assert.assertEquals(1, testResults.size());
+        Assert.assertEquals(IntersectionIssues.SHORT_DISCONNECT, testResults.get(0).getCode());
+
+        DataSet area2 = createDataSet(getTestArea2());
+        testResults = test(area2);
+        Assert.assertEquals(1, testResults.size());
+        Assert.assertEquals(IntersectionIssues.SHORT_DISCONNECT, testResults.get(0).getCode());
+
+        area1.mergeFrom(area2);
+        testResults = test(area1);
+        Assert.assertEquals(2, testResults.size());
+        for (TestError error : testResults) {
+            Assert.assertEquals(IntersectionIssues.SHORT_DISCONNECT, error.getCode());
+        }
+
+        testResults = test(createDataSet(getTestAreaRealWorld2()));
+        Assert.assertEquals(1, testResults.size());
+        Assert.assertNotEquals(IntersectionIssues.SHORT_DISCONNECT, testResults.get(0).getCode());
+
+        testResults = test(createDataSet(getTestAreaRealWorld3()));
+        if (testResults.size() == 1)
+            Assert.assertNotEquals(IntersectionIssues.SHORT_DISCONNECT, testResults.get(0).getCode());
+        Assert.assertTrue(testResults.size() <= 1);
+
+        testResults = test(createDataSet(getTestAreaRealWorld5()));
+        if (testResults.size() >= 1) {
+            for (TestError result : testResults) {
+                Assert.assertNotEquals(IntersectionIssues.SHORT_DISCONNECT, result.getCode());
+            }
+        }
+    }
+
+    /**
+     * Unit test for {@link IntersectionIssues#checkNearbyNodes}
+     * @throws Exception if any error occurs
+     */
+    @Test
+    public void testCheckAlmostOverlappingWays() throws Exception {
+        List<TestError> testResults = test(createDataSet(getTestArea1()));
+        Assert.assertEquals(1, testResults.size());
+        Assert.assertNotEquals(IntersectionIssues.NEARBY_NODE, testResults.get(0).getCode());
+
+        testResults = test(createDataSet(getTestArea3()));
+        Assert.assertEquals(1, testResults.size());
+        Assert.assertEquals(IntersectionIssues.NEARBY_NODE, testResults.get(0).getCode());
+
+        testResults = test(createDataSet(getTestAreaRealWorld1()));
+        Assert.assertEquals(1, testResults.size());
+        Assert.assertEquals(IntersectionIssues.NEARBY_NODE, testResults.get(0).getCode());
+
+        DataSet area4 = createDataSet(getTestAreaRealWorld2());
+        testResults = test(area4);
+        Assert.assertEquals(1, testResults.size());
+        Assert.assertEquals(IntersectionIssues.NEARBY_NODE, testResults.get(0).getCode());
+
+        testResults = test(createDataSet(getTestAreaRealWorld4()));
+        Assert.assertEquals(0, testResults.size());
+    }
+}
Index: test/unit/org/openstreetmap/josm/data/validation/tests/RoutingIslandsTestTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/RoutingIslandsTestTest.java	(nonexistent)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/RoutingIslandsTestTest.java	(working copy)
@@ -0,0 +1,365 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.validation.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.DataSource;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.validation.Severity;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Test class for {@link RoutingIslandsTest}
+ *
+ * @author Taylor Smock
+ * @since xxx
+ */
+public class RoutingIslandsTestTest {
+    /**
+     * Setup test.
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules rule = new JOSMTestRules().projection().preferences().timeout(30000);
+
+    /**
+     * Test method for {@link RoutingIslandsTest#RoutingIslandsTest()} and the
+     * testing apparatus
+     */
+    @Test
+    public void testRoutingIslandsTest() {
+        RoutingIslandsTest.setErrorLevel(RoutingIslandsTest.ROUTING_ISLAND, Severity.WARNING);
+        RoutingIslandsTest test = new RoutingIslandsTest();
+        test.startTest(null);
+        test.endTest();
+        assertTrue(test.getErrors().isEmpty());
+
+        DataSet ds = new DataSet();
+
+        Way way1 = TestUtils.newWay("highway=residential", new Node(new LatLon(0, 0)), new Node(new LatLon(1, 1)));
+        Way way2 = TestUtils.newWay("highway=residential", new Node(new LatLon(-1, 0)), way1.firstNode());
+        addToDataSet(ds, way1);
+        addToDataSet(ds, way2);
+
+        ds.addDataSource(new DataSource(new Bounds(0, 0, 1, 1), "openstreetmap.org"));
+
+        test.clear();
+        test.startTest(null);
+        test.visit(ds.allPrimitives());
+        test.endTest();
+        assertTrue(test.getErrors().isEmpty());
+
+        ds.addDataSource(new DataSource(new Bounds(-5, -5, 5, 5), "openstreetmap.org"));
+        test.clear();
+        test.startTest(null);
+        test.visit(ds.allPrimitives());
+        test.endTest();
+        assertFalse(test.getErrors().isEmpty());
+        assertEquals(2, test.getErrors().get(0).getPrimitives().size());
+
+        ds.clear();
+        way1 = TestUtils.newWay("highway=motorway oneway=yes", new Node(new LatLon(39.1156655, -108.5465434)),
+                new Node(new LatLon(39.1157251, -108.5496874)), new Node(new LatLon(39.11592, -108.5566841)));
+        way2 = TestUtils.newWay("highway=motorway oneway=yes", new Node(new LatLon(39.1157244, -108.55674)),
+                new Node(new LatLon(39.1155548, -108.5496901)), new Node(new LatLon(39.1154827, -108.5462431)));
+        addToDataSet(ds, way1);
+        addToDataSet(ds, way2);
+        ds.addDataSource(
+                new DataSource(new Bounds(new LatLon(39.1136949, -108.558445), new LatLon(39.117242, -108.5489166)),
+                        "openstreetmap.org"));
+        test.clear();
+        test.startTest(null);
+        test.visit(ds.allPrimitives());
+        test.endTest();
+        assertFalse(test.getErrors().isEmpty());
+        Way way3 = TestUtils.newWay("highway=motorway oneway=no", way1.getNode(1), way2.getNode(1));
+        addToDataSet(ds, way3);
+        test.clear();
+        test.startTest(null);
+        test.visit(ds.allPrimitives());
+        test.endTest();
+        assertFalse(test.getErrors().isEmpty());
+
+        Node tNode = new Node(new LatLon(39.1158845, -108.5599312));
+        addToDataSet(ds, tNode);
+        way1.addNode(tNode);
+        tNode = new Node(new LatLon(39.115723, -108.5599239));
+        addToDataSet(ds, tNode);
+        way2.addNode(0, tNode);
+        test.clear();
+        test.startTest(null);
+        test.visit(ds.allPrimitives());
+        test.endTest();
+        assertTrue(test.getErrors().isEmpty());
+    }
+
+    /**
+     * Test roundabouts
+     */
+    @Test
+    public void testRoundabouts() {
+        RoutingIslandsTest test = new RoutingIslandsTest();
+        Way roundabout = TestUtils.newWay("highway=residential junction=roundabout oneway=yes",
+                new Node(new LatLon(39.119582, -108.5262686)), new Node(new LatLon(39.1196494, -108.5260935)),
+                new Node(new LatLon(39.1197572, -108.5260784)), new Node(new LatLon(39.1197929, -108.526391)),
+                new Node(new LatLon(39.1196595, -108.5264047)));
+        roundabout.addNode(roundabout.firstNode()); // close it up
+        DataSet ds = new DataSet();
+        addToDataSet(ds, roundabout);
+        ds.addDataSource(
+                new DataSource(new Bounds(new LatLon(39.1182025, -108.527574), new LatLon(39.1210588, -108.5251112)),
+                        "openstreetmap.org"));
+        Way incomingFlare = TestUtils.newWay("highway=residential oneway=yes",
+                new Node(new LatLon(39.1196377, -108.5257567)), roundabout.getNode(3));
+        addToDataSet(ds, incomingFlare);
+        Way outgoingFlare = TestUtils.newWay("highway=residential oneway=yes", roundabout.getNode(2),
+                incomingFlare.firstNode());
+        addToDataSet(ds, outgoingFlare);
+
+        Way outgoingRoad = TestUtils.newWay("highway=residential", incomingFlare.firstNode(),
+                new Node(new LatLon(39.1175184, -108.5219623)));
+        addToDataSet(ds, outgoingRoad);
+
+        test.startTest(null);
+        test.visit(ds.allPrimitives());
+        test.endTest();
+        assertTrue(test.getErrors().isEmpty());
+    }
+
+    /**
+     * Test method for {@link RoutingIslandsTest#checkForUnconnectedWays}.
+     */
+    @Test
+    public void testCheckForUnconnectedWaysIncoming() {
+        RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), Collections.emptySet(), null);
+        Way way1 = TestUtils.newWay("highway=residential oneway=yes", new Node(new LatLon(0, 0)),
+                new Node(new LatLon(1, 1)));
+        Set<Way> incomingSet = new HashSet<>();
+        DataSet ds = new DataSet();
+        way1.getNodes().forEach(ds::addPrimitive);
+        ds.addPrimitive(way1);
+        incomingSet.add(way1);
+        RoutingIslandsTest.checkForUnconnectedWays(incomingSet, Collections.emptySet(), null);
+        assertEquals(1, incomingSet.size());
+        assertSame(way1, incomingSet.iterator().next());
+
+        Way way2 = TestUtils.newWay("highway=residential", way1.firstNode(), new Node(new LatLon(-1, -2)));
+        way2.getNodes().parallelStream().filter(node -> node.getDataSet() == null).forEach(ds::addPrimitive);
+        ds.addPrimitive(way2);
+
+        RoutingIslandsTest.checkForUnconnectedWays(incomingSet, Collections.emptySet(), null);
+        assertEquals(2, incomingSet.size());
+        assertTrue(incomingSet.parallelStream().allMatch(way -> Arrays.asList(way1, way2).contains(way)));
+
+        Way way3 = TestUtils.newWay("highway=residential", way2.lastNode(), new Node(new LatLon(-2, -1)));
+        way3.getNodes().parallelStream().filter(node -> node.getDataSet() == null).forEach(ds::addPrimitive);
+        ds.addPrimitive(way3);
+
+        incomingSet.clear();
+        incomingSet.add(way1);
+        RoutingIslandsTest.checkForUnconnectedWays(incomingSet, Collections.emptySet(), null);
+        assertEquals(3, incomingSet.size());
+        assertTrue(incomingSet.parallelStream().allMatch(way -> Arrays.asList(way1, way2, way3).contains(way)));
+
+        Config.getPref().putInt("validator.routingislands.maxrecursion", 1);
+        incomingSet.clear();
+        incomingSet.add(way1);
+        RoutingIslandsTest.checkForUnconnectedWays(incomingSet, Collections.emptySet(), null);
+        assertEquals(2, incomingSet.size());
+        assertTrue(incomingSet.parallelStream().allMatch(way -> Arrays.asList(way1, way2).contains(way)));
+    }
+
+    /**
+     * Test method for {@link RoutingIslandsTest#checkForUnconnectedWays}.
+     */
+    @Test
+    public void testCheckForUnconnectedWaysOutgoing() {
+        RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), Collections.emptySet(), null);
+        Way way1 = TestUtils.newWay("highway=residential oneway=yes", new Node(new LatLon(0, 0)),
+                new Node(new LatLon(1, 1)));
+        Set<Way> outgoingSet = new HashSet<>();
+        DataSet ds = new DataSet();
+        way1.getNodes().forEach(ds::addPrimitive);
+        ds.addPrimitive(way1);
+        outgoingSet.add(way1);
+        RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), outgoingSet, null);
+        assertEquals(1, outgoingSet.size());
+        assertSame(way1, outgoingSet.iterator().next());
+
+        Way way2 = TestUtils.newWay("highway=residential", way1.firstNode(), new Node(new LatLon(-1, -2)));
+        way2.getNodes().parallelStream().filter(node -> node.getDataSet() == null).forEach(ds::addPrimitive);
+        ds.addPrimitive(way2);
+
+        RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), outgoingSet, null);
+        assertEquals(2, outgoingSet.size());
+        assertTrue(outgoingSet.parallelStream().allMatch(way -> Arrays.asList(way1, way2).contains(way)));
+
+        Way way3 = TestUtils.newWay("highway=residential", way2.lastNode(), new Node(new LatLon(-2, -1)));
+        way3.getNodes().parallelStream().filter(node -> node.getDataSet() == null).forEach(ds::addPrimitive);
+        ds.addPrimitive(way3);
+
+        outgoingSet.clear();
+        outgoingSet.add(way1);
+        RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), outgoingSet, null);
+        assertEquals(3, outgoingSet.size());
+        assertTrue(outgoingSet.parallelStream().allMatch(way -> Arrays.asList(way1, way2, way3).contains(way)));
+
+        Config.getPref().putInt("validator.routingislands.maxrecursion", 1);
+        outgoingSet.clear();
+        outgoingSet.add(way1);
+        RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), outgoingSet, null);
+        assertEquals(2, outgoingSet.size());
+        assertTrue(outgoingSet.parallelStream().allMatch(way -> Arrays.asList(way1, way2).contains(way)));
+    }
+
+    /**
+     * Test method for {@link RoutingIslandsTest#outsideConnections(Node)}.
+     */
+    @Test
+    public void testOutsideConnections() {
+        Node node = new Node(new LatLon(0, 0));
+        DataSet ds = new DataSet(node);
+        ds.addDataSource(new DataSource(new Bounds(-0.1, -0.1, -0.01, -0.01), "Test bounds"));
+        node.setOsmId(1, 1);
+        assertTrue(RoutingIslandsTest.outsideConnections(node));
+        ds.addDataSource(new DataSource(new Bounds(-0.1, -0.1, 0.1, 0.1), "Test bounds"));
+        assertFalse(RoutingIslandsTest.outsideConnections(node));
+        node.put("amenity", "parking_entrance");
+        assertTrue(RoutingIslandsTest.outsideConnections(node));
+    }
+
+    /**
+     * Test method for {@link RoutingIslandsTest#isOneway(Way, String)}.
+     */
+    @Test
+    public void testIsOneway() {
+        Way way = TestUtils.newWay("highway=residential", new Node(new LatLon(0, 0)), new Node(new LatLon(1, 1)));
+        assertEquals(Integer.valueOf(0), RoutingIslandsTest.isOneway(way, null));
+        assertEquals(Integer.valueOf(0), RoutingIslandsTest.isOneway(way, " "));
+        way.put("oneway", "yes");
+        assertEquals(Integer.valueOf(1), RoutingIslandsTest.isOneway(way, null));
+        assertEquals(Integer.valueOf(1), RoutingIslandsTest.isOneway(way, " "));
+        way.put("oneway", "-1");
+        assertEquals(Integer.valueOf(-1), RoutingIslandsTest.isOneway(way, null));
+        assertEquals(Integer.valueOf(-1), RoutingIslandsTest.isOneway(way, " "));
+
+        way.put("vehicle:forward", "yes");
+        assertEquals(Integer.valueOf(0), RoutingIslandsTest.isOneway(way, "vehicle"));
+        way.put("vehicle:backward", "no");
+        assertEquals(Integer.valueOf(1), RoutingIslandsTest.isOneway(way, "vehicle"));
+        way.put("vehicle:forward", "no");
+        assertNull(RoutingIslandsTest.isOneway(way, "vehicle"));
+        way.put("vehicle:backward", "yes");
+        assertEquals(Integer.valueOf(-1), RoutingIslandsTest.isOneway(way, "vehicle"));
+
+        way.put("oneway", "yes");
+        way.remove("vehicle:backward");
+        way.remove("vehicle:forward");
+        assertEquals(Integer.valueOf(1), RoutingIslandsTest.isOneway(way, "vehicle"));
+        way.remove("oneway");
+        assertEquals(Integer.valueOf(0), RoutingIslandsTest.isOneway(way, "vehicle"));
+
+        way.put("oneway", "-1");
+        assertEquals(Integer.valueOf(-1), RoutingIslandsTest.isOneway(way, "vehicle"));
+    }
+
+    /**
+     * Test method for {@link RoutingIslandsTest#firstNode(Way, String)}.
+     */
+    @Test
+    public void testFirstNode() {
+        Way way = TestUtils.newWay("highway=residential", new Node(new LatLon(0, 0)), new Node(new LatLon(1, 1)));
+        assertEquals(way.firstNode(), RoutingIslandsTest.firstNode(way, null));
+        way.put("oneway", "yes");
+        assertEquals(way.firstNode(), RoutingIslandsTest.firstNode(way, null));
+        way.put("oneway", "-1");
+        assertEquals(way.lastNode(), RoutingIslandsTest.firstNode(way, null));
+
+        way.put("vehicle:forward", "yes");
+        assertEquals(way.firstNode(), RoutingIslandsTest.firstNode(way, "vehicle"));
+        way.put("vehicle:backward", "no");
+        assertEquals(way.firstNode(), RoutingIslandsTest.firstNode(way, "vehicle"));
+        way.put("vehicle:forward", "no");
+        assertEquals(way.firstNode(), RoutingIslandsTest.firstNode(way, "vehicle"));
+        way.put("vehicle:backward", "yes");
+        assertEquals(way.lastNode(), RoutingIslandsTest.firstNode(way, "vehicle"));
+    }
+
+    /**
+     * Test method for {@link RoutingIslandsTest#lastNode(Way, String)}.
+     */
+    @Test
+    public void testLastNode() {
+        Way way = TestUtils.newWay("highway=residential", new Node(new LatLon(0, 0)), new Node(new LatLon(1, 1)));
+        assertEquals(way.lastNode(), RoutingIslandsTest.lastNode(way, null));
+        way.put("oneway", "yes");
+        assertEquals(way.lastNode(), RoutingIslandsTest.lastNode(way, null));
+        way.put("oneway", "-1");
+        assertEquals(way.firstNode(), RoutingIslandsTest.lastNode(way, null));
+
+        way.put("vehicle:forward", "yes");
+        assertEquals(way.lastNode(), RoutingIslandsTest.lastNode(way, "vehicle"));
+        way.put("vehicle:backward", "no");
+        assertEquals(way.lastNode(), RoutingIslandsTest.lastNode(way, "vehicle"));
+        way.put("vehicle:forward", "no");
+        assertEquals(way.lastNode(), RoutingIslandsTest.lastNode(way, "vehicle"));
+        way.put("vehicle:backward", "yes");
+        assertEquals(way.firstNode(), RoutingIslandsTest.lastNode(way, "vehicle"));
+    }
+
+    /**
+     * Test with a way that by default does not give access to motor vehicles
+     */
+    @Test
+    public void testNoAccessWay() {
+        Way i70w = TestUtils.newWay("highway=motorway hgv=designated", new Node(new LatLon(39.1058104, -108.5258586)),
+                new Node(new LatLon(39.1052235, -108.5293733)));
+        Way i70e = TestUtils.newWay("highway=motorway hgv=designated", new Node(new LatLon(39.1049905, -108.5293074)),
+                new Node(new LatLon(39.1055829, -108.5257975)));
+        Way testPath = TestUtils.newWay("highway=footway", i70w.lastNode(true), i70e.firstNode(true));
+        DataSet ds = new DataSet();
+        Arrays.asList(i70w, i70e, testPath).forEach(way -> addToDataSet(ds, way));
+
+        RoutingIslandsTest test = new RoutingIslandsTest();
+        test.startTest(null);
+        test.visit(ds.allPrimitives());
+        test.endTest();
+    }
+
+    private static void addToDataSet(DataSet ds, OsmPrimitive primitive) {
+        if (primitive instanceof Way) {
+            ((Way) primitive).getNodes().parallelStream().distinct().filter(node -> node.getDataSet() == null)
+                    .forEach(ds::addPrimitive);
+        }
+        if (primitive.getDataSet() == null) {
+            ds.addPrimitive(primitive);
+        }
+        Long id = Math.max(ds.allPrimitives().parallelStream().mapToLong(prim -> prim.getId()).max().orElse(0L), 0L);
+        for (OsmPrimitive osm : ds.allPrimitives().parallelStream().filter(prim -> prim.getUniqueId() < 0)
+                .collect(Collectors.toList())) {
+            id++;
+            osm.setOsmId(id, 1);
+        }
+    }
+}
Index: test/unit/org/openstreetmap/josm/gui/download/OSMDownloadSourceTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/gui/download/OSMDownloadSourceTest.java	(nonexistent)
+++ test/unit/org/openstreetmap/josm/gui/download/OSMDownloadSourceTest.java	(working copy)
@@ -0,0 +1,156 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.download;
+
+import static org.junit.Assert.assertEquals;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.List;
+
+import javax.swing.JCheckBox;
+import javax.swing.event.ChangeListener;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.openstreetmap.josm.actions.downloadtasks.AbstractDownloadTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadNotesTask;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.preferences.BooleanProperty;
+import org.openstreetmap.josm.gui.download.OSMDownloadSource.DataDownloadType;
+import org.openstreetmap.josm.gui.download.OSMDownloadSource.GpsDataDownloadType;
+import org.openstreetmap.josm.gui.download.OSMDownloadSource.NotesDataDownloadType;
+import org.openstreetmap.josm.gui.download.OSMDownloadSource.OsmDataDownloadType;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@link OSMDownloadSource} class.
+ *
+ * @author Taylor Smock
+ *
+ */
+public class OSMDownloadSourceTest {
+
+    /**
+     * Setup tests
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().preferences();
+
+    /**
+     * Account for tests that require an exception.
+     */
+    @Rule
+    public final ExpectedException exception = ExpectedException.none();
+
+    DataDownloadType testType;
+
+    static List<DataDownloadType> defaultDownloadTypes;
+
+    /**
+     * Set the initial download types
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() {
+        defaultDownloadTypes = OSMDownloadSource.getDownloadTypes();
+    }
+
+    /**
+     * Set up some common variables
+     */
+    @Before
+    public void setUp() {
+        testType = new DataDownloadType() {
+            private JCheckBox cbTestBox;
+
+            @Override
+            public JCheckBox getCheckBox(ChangeListener checkboxChangeListener) {
+                if (cbTestBox == null) {
+                    cbTestBox = new JCheckBox(tr("Notes"));
+                    cbTestBox.setToolTipText(tr("Select to download notes in the selected download area."));
+                }
+                if (checkboxChangeListener != null) {
+                    cbTestBox.getModel().addChangeListener(checkboxChangeListener);
+                }
+
+                return cbTestBox;
+            }
+
+            @Override
+            public Class<? extends AbstractDownloadTask<?>> getDownloadClass() {
+                return DownloadNotesTask.class;
+            }
+
+            @Override
+            public BooleanProperty getBooleanProperty() {
+                return new BooleanProperty("download.osm.notes-test", false);
+            }
+
+            @Override
+            public boolean isDownloadAreaTooLarge(Bounds bound) {
+                return bound.getArea() > Config.getPref().getDouble("osm-server.max-request-area-notes", 25);
+            }
+        };
+    }
+
+    /**
+     * Test that we have the default download sources
+     */
+    @Test
+    public void testGetDownloadSources() {
+        List<DataDownloadType> list = OSMDownloadSource.getDownloadTypes();
+        assertEquals(1, list.parallelStream().filter(OsmDataDownloadType.class::isInstance).count());
+        assertEquals(1, list.parallelStream().filter(GpsDataDownloadType.class::isInstance).count());
+        assertEquals(1, list.parallelStream().filter(NotesDataDownloadType.class::isInstance).count());
+    }
+
+    /**
+     * Ensure that the default download sources cannot be removed
+     */
+    @Test
+    public void testCannotRemoveDefaults() {
+        for (DataDownloadType type : defaultDownloadTypes) {
+            OSMDownloadSource.removeDownloadType(type);
+            testGetDownloadSources();
+        }
+
+        // This has to be last in JUnit 4 (it stops the test)
+        exception.expect(UnsupportedOperationException.class);
+        defaultDownloadTypes.remove(0);
+    }
+
+    /**
+     * Ensure that the default download sources cannot be added
+     */
+    @Test
+    public void testCannotAddDefaults() {
+        for (DataDownloadType type : defaultDownloadTypes) {
+            OSMDownloadSource.addDownloadType(type);
+            testGetDownloadSources();
+        }
+    }
+
+    /**
+     * Test adding/removing/using a new source
+     */
+    @Test
+    public void testAddNewSource() {
+        OSMDownloadSource.addDownloadType(testType);
+        OSMDownloadSource.addDownloadType(testType);
+        OSMDownloadSource.addDownloadType(testType);
+        testGetDownloadSources();
+        assertEquals(1, OSMDownloadSource.getDownloadTypes().parallelStream()
+                .filter(type -> testType.getClass().isInstance(type)).count());
+
+        OSMDownloadSource.removeDownloadType(testType);
+        assertEquals(0, OSMDownloadSource.getDownloadTypes().parallelStream()
+                .filter(type -> testType.getClass().isInstance(type)).count());
+        OSMDownloadSource.removeDownloadType(testType);
+        testGetDownloadSources();
+    }
+}
Index: test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
===================================================================
--- test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java	(revision 15755)
+++ test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java	(working copy)
@@ -23,6 +23,9 @@
 import java.util.logging.Handler;
 
 import org.awaitility.Awaitility;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.rules.TemporaryFolder;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
@@ -79,7 +82,7 @@
  *
  * @author Michael Zangl
  */
-public class JOSMTestRules implements TestRule {
+public class JOSMTestRules implements TestRule, AfterEachCallback, BeforeEachCallback {
     private int timeout = isDebugMode() ? -1 : 10 * 1000;
     private TemporaryFolder josmHome;
     private boolean usePreferences = false;
@@ -433,6 +436,28 @@
         return statement;
     }
 
+    @Override
+    public void beforeEach(ExtensionContext context) throws Exception {
+        Statement temporaryStatement = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                // do nothing
+            }
+        };
+        try {
+            this.apply(temporaryStatement,
+                    Description.createTestDescription(this.getClass(), "JOSMTestRules JUnit5 Compatibility"))
+                    .evaluate();
+        } catch (Throwable e) {
+            throw new Exception(e);
+        }
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) throws Exception {
+        // do nothing for now
+    }
+
     /**
      * Set up before running a test
      * @throws InitializationError If an error occurred while creating the required environment.
Index: test/unit/org/openstreetmap/josm/tools/AccessTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/tools/AccessTest.java	(nonexistent)
+++ test/unit/org/openstreetmap/josm/tools/AccessTest.java	(working copy)
@@ -0,0 +1,59 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+/**
+ * Test class for {@link Access}
+ *
+ * @author Taylor Smock
+ * @since xxx
+ */
+public class AccessTest {
+
+    /**
+     * Test that access tags inherit the expected values
+     */
+    @Test
+    public void testInheritance() {
+        assertEquals(Access.AccessTags.YES.getKey(),
+                Access.expandAccessMode(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey())
+                        .getOrDefault(Access.AccessTags.MOTOR_VEHICLE.getKey(), Access.AccessTags.NO.getKey()));
+        assertEquals(Access.AccessTags.YES.getKey(),
+                Access.expandAccessMode(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey())
+                        .getOrDefault(Access.AccessTags.HGV.getKey(), Access.AccessTags.NO.getKey()));
+        assertEquals(Access.AccessTags.YES.getKey(),
+                Access.expandAccessMode(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey())
+                        .getOrDefault(Access.AccessTags.HGV_ARTICULATED.getKey(), Access.AccessTags.NO.getKey()));
+    }
+
+    /**
+     * Test that access maps get merged properly ({@link Access#mergeMaps})
+     */
+    @Test
+    public void testMergeMaps() {
+        Map<String, String> mergedMaps = Access.mergeMaps(
+                Access.expandAccessMode(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey()),
+                Access.expandAccessMode(Access.AccessTags.HGV.getKey(), Access.AccessTags.DESIGNATED.getKey()));
+        assertEquals(Access.AccessTags.YES.getKey(),
+                mergedMaps.getOrDefault(Access.AccessTags.MOTORCAR.getKey(), Access.AccessTags.NO.getKey()));
+        assertEquals(Access.AccessTags.DESIGNATED.getKey(),
+                mergedMaps.getOrDefault(Access.AccessTags.HGV.getKey(), Access.AccessTags.NO.getKey()));
+        assertEquals(Access.AccessTags.DESIGNATED.getKey(),
+                mergedMaps.getOrDefault(Access.AccessTags.HGV_ARTICULATED.getKey(), Access.AccessTags.NO.getKey()));
+
+        mergedMaps = Access.mergeMaps(
+                Access.expandAccessMode(Access.AccessTags.HGV.getKey(), Access.AccessTags.DESIGNATED.getKey()),
+                Access.expandAccessMode(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey()));
+        assertEquals(Access.AccessTags.YES.getKey(),
+                mergedMaps.getOrDefault(Access.AccessTags.MOTORCAR.getKey(), Access.AccessTags.NO.getKey()));
+        assertEquals(Access.AccessTags.DESIGNATED.getKey(),
+                mergedMaps.getOrDefault(Access.AccessTags.HGV.getKey(), Access.AccessTags.NO.getKey()));
+        assertEquals(Access.AccessTags.DESIGNATED.getKey(),
+                mergedMaps.getOrDefault(Access.AccessTags.HGV_ARTICULATED.getKey(), Access.AccessTags.NO.getKey()));
+    }
+}
